En los anteriores post vimos como guardar el estado de las entradas/salidas del PLC en el PC. Hoy vamos a leer estos archivos y generar una tabla que nos muestre de una forma clara como se han producido los cambios. La técnica empleada para esto es leer texto separado por “;”. En el anterior proyecto añadiremos un botón que nos abra un nuevo formulario. A este botón lo llamaremos buAnalizar y en la propiedad texto le pondremos Analizar. Doble click en el botón y nos genera el evento donde pondremos el siguiente código.

También podríamos utilizar el siguiente código para abrir el formulario, este código nos permite abrir múltiples estancias del mismo formulario:

Como podemos ver en el código, en el segundo caso se crea una nueva estancia del formulario cada vez que presionamos el botón.

En el explorador de soluciones, click con el derecho y añadir nuevo elemento:

Y este es el aspecto de nuestro formAnalizar:

He previsto tres posibilidades para elegir el archivo, las dos primera (IN, OUT), son RadioButon y tienen la peculiaridad de que solo podrá estar marcada una. Cuando marcamos IN se desmarca Out y viceversa. La última posibilidad es un CheckBoxy la función es abrir un cuadro de dialogo para elegir el archivo a analizar. Aunque los tres podrían ser RadioButon he considerado poner un Checkbox para que podáis apreciar la diferencia entre los dos primeros y el tercero. Por último ponemos un botón para proceder a la lectura del archivo.

El cuadro blanco situado a la derecha es un ListView. Podríamos configurar las columnas directamente pero yo prefiero hacerlo por código. Hacemos doble click en el formAnalizar y nos genera el gestor de eventos del FormAnalizar.Load. Lo que quiere decir que será el código que primero leerá cuando se abra el formulario. Aprovechamos este evento para configurar la tabla en el listView. Aunque es un poco largo porque hay muchas columnas, es fácil y prácticamente es copiar pegar, puesto que la diferencia entre las columnas de la tabla son los nombres, bit0, bit1, etc

Private Sub FormAnalizar_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _
 
Handles MyBase.Load
 
ListView1.View = View.Details
 
ListView1.BackColor = Color.GhostWhite
 
ListView1.GridLines = True
 
ListView1.Columns.Add("Fecha / Hora")
 
ListView1.Columns(0).Width = 150
 
ListView1.Columns.Add("bit.0")
 
ListView1.Columns(1).Width = 40
 
ListView1.Columns.Add("bit.1")
 
ListView1.Columns(2).Width = 40
 
ListView1.Columns.Add("bit.2")
 
ListView1.Columns(3).Width = 40
 
ListView1.Columns.Add("bit.3")
 
ListView1.Columns(4).Width = 40
 
ListView1.Columns.Add("bit.4")
 
ListView1.Columns(5).Width = 40
 
ListView1.Columns.Add("bit.5")
 
ListView1.Columns(6).Width = 40
 
ListView1.Columns.Add("bit.6")
 
ListView1.Columns(7).Width = 40
 
ListView1.Columns.Add("bit.7")
 
ListView1.Columns(8).Width = 40
 
ListView1.Columns.Add("bit.8")
 
ListView1.Columns(9).Width = 40
 
ListView1.Columns.Add("bit.9")
 
ListView1.Columns(10).Width = 40
 
ListView1.Columns.Add("bit.10")
 
ListView1.Columns(11).Width = 40
 
ListView1.Columns.Add("bit.11")
 
ListView1.Columns(12).Width = 40
 
ListView1.Columns.Add("bit.12")
 
ListView1.Columns(13).Width = 40
 
ListView1.Columns.Add("bit.13")
 
ListView1.Columns(14).Width = 40
 
ListView1.Columns.Add("bit.14")
 
ListView1.Columns(15).Width = 40
 
ListView1.Columns.Add("bit.15")
 
ListView1.Columns(16).Width = 40
 
End Sub

Bien, tenemos el formulario gráficamente terminado, ahora vamos a leer los archivos y a llenar la tabla con datos. El primer paso es seleccionar el archivo con el que queremos trabajar:

Agregamos un componente, que nos hará el trabajo de abrir un cuadro de diálogo para seleccionar un archivo. OpenFileDialog.

Lo arrastramos hasta el formulario, y automáticamente se pasará a la barra gris situada debajo del formulario.

Le he cambiado la propiedad Name por Ofd1. El siguiente extracto de código muestra la selección del nombre del archivo a leer, en función de los requerimientos del usuario:

'Borramos el listview
 
ListView1.Items.Clear()
 
'Comprobamos si quiere ver In, Out o abrir un cuadro de dialogo
 
Dim Filename As String = ""
 
If ckMostrarDialogo.Checked Then
 
Ofd1.ShowDialog()
 
Filename = Ofd1.FileName
 
Else
 
If rdIn.Checked Then Filename = "In.csv"
 
If rdOut.Checked Then Filename = "Out.csv"
 
End If
 
If Filename = "" Then
 
MessageBox.Show("Error en parametros")
 
Exit Sub
 
End If

Declaramos la variable FileName donde almacenaremos el nombre del archivo a abrir. Si está marcado el Cheked.Box abre el cuadro de diálogo para que seleccionemos un archivo, una vez seleccionado pasa el nombre a la variable. De no ser así, se comprueba cual de los RadioButton está marcado para asignar el nombre del archivo como In.csv u Out.csv.

Como no sabemos a priori cuantas líneas tendrá el archivo que vamos a abrir, lo haremos en dos pasadas, en la primera pasada contamos las líneas, dimensionamos las variables que almacenaran los datos y en la siguiente pasada pasamos los datos a las variables. Realmente no es necesario almacenar los datos, puesto que como veremos más adelante, los datos se irán escribiendo en la tabla a medida que los leemos, pero esto no termina en una tabla, en la próxima entrada mostraremos los datos en un gráfico, por este motivo los guardamos en unas variables, para posteriormente poder visualizarlos en grafico.

¿Y cómo podemos leer un archivo de este tipo? Pues que lo diga el IDE. Pincha con el derecho dentro del evento buLeerDatos, insertar fragmento de código:

En nuestro caso quitamos la primera línea, ya que filename ya está declarada y cambiamos delimiter por “;”. El código completo del gestor de eventos leerdatos es este:

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
 
Handles buLeerDatos.Click
 
'Borramos el listview
 
ListView1.Items.Clear()
 
'Comprobamos si quiere ver In, Out o abrir un cuadro de dialogo
 
Dim Filename As String = ""
 
If ckMostrarDialogo.Checked Then
 
Ofd1.ShowDialog()
 
Filename = Ofd1.FileName
 
Else
 
If rdIn.Checked Then Filename = "In.csv"
 
If rdOut.Checked Then Filename = "Out.csv"
 
End If
 
If Filename = "" Then
 
MessageBox.Show("Error en parametros")
 
Exit Sub
 
End If
 
Dim i As Integer
 
Dim fields As String()
 
Dim delimiter As String = ";"
 
Try
 
'Leemos para dimensionar las variables
 
Using parser As New TextFieldParser(Filename)
 
parser.SetDelimiters(delimiter)
 
While Not parser.EndOfData
 
' Read in the fields for the current line
 
fields = parser.ReadFields()
 
' Add code here to use data in fields variable.
 
i += 1
 
End While
 
End Using
 
Catch ex As Exception
 
MessageBox.Show("Error de parametros")
 
Exit Sub
 
End Try
 
'Dimensionamos las variables
 
ReDim Momento(i - 1)
 
ReDim Dato(i - 1)
 
i = 0
 
'Leemos y asignamos a variables
 
Using parser As New TextFieldParser(Filename)
 
parser.SetDelimiters(delimiter)
 
While Not parser.EndOfData
 
' Read in the fields for the current line
 
fields = parser.ReadFields()
 
' Add code here to use data in fields variable.
 
Momento(i) = fields(0)
 
Dato(i) = DecToBin(fields(1))
 
Trace1(Momento(i), Dato(i), Color.Black)
 
i += 1
 
End While
 
End Using
 
End Sub

Como podemos ver en el código, en la primera pasada sólo incrementamos i de manera que al final del bucle i = total filas. Redimensionamos las variables y volvemos a leer para asignar los valores a las variables, a la vez llamamos a la función Trace1, que es la encargada de rellenar la tabla de una manera especial.

Public Sub Trace1(ByVal Momento As String, ByVal ValorInt16 As String, ByVal ColorMsg As Color)
 
Dim Texto(16) As String
 
Texto(0) = Momento
 
Dim i As Integer
 
For i = 0 To ValorInt16.Length - 1
 
If DatoAnterior.Chars(i) <> ValorInt16.Chars(i) Then
 
If ValorInt16.Chars(i) = "0" Then Texto(i + 1) = "OFF" Else Texto(i + 1) = "ON"
 
End If
 
Next
 
Dim item As New ListViewItem(Texto)
 
item.ForeColor = ColorMsg
 
ListView1.Items.Add(item)
 
DatoAnterior = ValorInt16
 
End Sub

Principalmente se trata de ir comprobando cada carácter de la variable string que contiene el valor binario, si es diferente de la vez anterior. De ser así, escribimos en la tabla. El resultado es este:

Y este es el código completo:

Imports Microsoft.VisualBasic.FileIO
 
Public Class FormAnalizar
 
Dim Dato(1) As String
 
Dim Momento(1) As String
 
Dim DatoAnterior As String = "0000000000000000"
 
Private Sub FormAnalizar_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) _
 
Handles MyBase.Load
 
ListView1.View = View.Details
 
ListView1.BackColor = Color.GhostWhite
 
ListView1.GridLines = True
 
ListView1.Columns.Add("Fecha / Hora")
 
ListView1.Columns(0).Width = 150
 
ListView1.Columns.Add("bit.0")
 
ListView1.Columns(1).Width = 40
 
ListView1.Columns.Add("bit.1")
 
ListView1.Columns(2).Width = 40
 
ListView1.Columns.Add("bit.2")
 
ListView1.Columns(3).Width = 40
 
ListView1.Columns.Add("bit.3")
 
ListView1.Columns(4).Width = 40
 
ListView1.Columns.Add("bit.4")
 
ListView1.Columns(5).Width = 40
 
ListView1.Columns.Add("bit.5")
 
ListView1.Columns(6).Width = 40
 
ListView1.Columns.Add("bit.6")
 
ListView1.Columns(7).Width = 40
 
ListView1.Columns.Add("bit.7")
 
ListView1.Columns(8).Width = 40
 
ListView1.Columns.Add("bit.8")
 
ListView1.Columns(9).Width = 40
 
ListView1.Columns.Add("bit.9")
 
ListView1.Columns(10).Width = 40
 
ListView1.Columns.Add("bit.10")
 
ListView1.Columns(11).Width = 40
 
ListView1.Columns.Add("bit.11")
 
ListView1.Columns(12).Width = 40
 
ListView1.Columns.Add("bit.12")
 
ListView1.Columns(13).Width = 40
 
ListView1.Columns.Add("bit.13")
 
ListView1.Columns(14).Width = 40
 
ListView1.Columns.Add("bit.14")
 
ListView1.Columns(15).Width = 40
 
ListView1.Columns.Add("bit.15")
 
ListView1.Columns(16).Width = 40
 
End Sub
 
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
 
Handles buLeerDatos.Click
 
'Borramos el listview
 
ListView1.Items.Clear()
 
'Comprobamos si quiere ver In, Out o abrir un cuadro de dialogo
 
Dim Filename As String = ""
 
If ckMostrarDialogo.Checked Then
 
Ofd1.ShowDialog()
 
Filename = Ofd1.FileName
 
Else
 
If rdIn.Checked Then Filename = "In.csv"
 
If rdOut.Checked Then Filename = "Out.csv"
 
End If
 
If Filename = "" Then
 
MessageBox.Show("Error en parametros")
 
Exit Sub
 
End If
 
Dim i As Integer
 
Dim fields As String()
 
Dim delimiter As String = ";"
 
Try
 
'Leemos para dimensionar las variables
 
Using parser As New TextFieldParser(Filename)
 
parser.SetDelimiters(delimiter)
 
While Not parser.EndOfData
 
' Read in the fields for the current line
 
fields = parser.ReadFields()
 
' Add code here to use data in fields variable.
 
i += 1
 
End While
 
End Using
 
Catch ex As Exception
 
MessageBox.Show("Error de parametros")
 
Exit Sub
 
End Try
 
'Dimensionamos las variables
 
ReDim Momento(i - 1)
 
ReDim Dato(i - 1)
 
i = 0
 
'Leemos y asignamos a variables
 
Using parser As New TextFieldParser(Filename)
 
parser.SetDelimiters(delimiter)
 
While Not parser.EndOfData
 
' Read in the fields for the current line
 
fields = parser.ReadFields()
 
' Add code here to use data in fields variable.
 
Momento(i) = fields(0)
 
Dato(i) = DecToBin(fields(1))
 
Trace1(Momento(i), Dato(i), Color.Black)
 
i += 1
 
End While
 
End Using
 
End Sub
 
#Region "Conversion binario decimal "
 
Private Function BinToDec(ByVal ValorBin As String) As Decimal
 
Dim Longitud As Integer = ValorBin.Length
 
'Debug.WriteLine("Entrar: " & ValorBin & "Longitud: " & Longitud)
 
Dim i As Integer = 0
 
Dim ValorDec As Decimal = 0
 
For i = 0 To Longitud - 1
 
Dim _Char As Char = ValorBin.Chars(i)
 
Dim ValorChar As Integer
 
If _Char = "0" Then ValorChar = 0 Else ValorChar = 1
 
ValorDec += ValorChar * System.Math.Pow(2, ((Longitud - i) - 1))
 
Next
 
Return (ValorDec)
 
End Function
 
Private Function DecToBin(ByVal ValorDec As Int32) As String
 
'Esta funcion convierte en binario tanto palabras INT como UINT.
 
'En caso de haber valores negativos se asume que es una palabra INT
 
' y hace la conversión con esta formula
 
If ValorDec < 0 Then
 
ValorDec = 65536 + ValorDec
 
End If
 
Dim Cociente As Int32 = ValorDec
 
Dim Resto As Int32 = 0
 
Dim ValorBinMatriz(17) As Char
 
Dim ValorBin As String = ""
 
Dim i As Integer = 0
 
If ValorDec = 1 Then ValorBinMatriz(0) = "1"
 
While Cociente > 1
 
Cociente = System.Math.DivRem(Cociente, 2, Resto)
 
ValorBinMatriz(i) = Resto.ToString
 
If Cociente < 2 Then ValorBinMatriz(i + 1) = Cociente.ToString
 
i += 1
 
End While
 
Dim j As Integer
 
For j = 0 To 15
 
If ValorBinMatriz(j) = "1" Then ValorBin &= "1" Else ValorBin &= "0"
 
Next
 
Return (ValorBin)
 
End Function
 
#End Region
 
Public Sub Trace1(ByVal Momento As String, ByVal ValorInt16 As String, ByVal ColorMsg As Color)
 
Dim Texto(16) As String
 
Texto(0) = Momento
 
Dim i As Integer
 
For i = 0 To ValorInt16.Length - 1
 
If DatoAnterior.Chars(i) <> ValorInt16.Chars(i) Then
 
If ValorInt16.Chars(i) = "0" Then Texto(i + 1) = "OFF" Else Texto(i + 1) = "ON"
 
End If
 
Next
 
Dim item As New ListViewItem(Texto)
 
item.ForeColor = ColorMsg
 
ListView1.Items.Add(item)
 
DatoAnterior = ValorInt16
 
End Sub
 
End Class