Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Edición en papel
nº 1
Índice
Introducción ..............................................................................7
1. Entregon+ ............................................................................11
1.1. Descripción..........................................................................11
1.2. Ensamblado .........................................................................13
1.3. Puesta en servicio ...............................................................14
2. El puerto serie .....................................................................15
2.1. El puerto serie .....................................................................15
2.2. Protocolo de comunicaciones DispeDataLink ................18
2.3. OSI Layer 1. La capa física.................................................19
2.4. OSI Layer 2. Enlace a datos ...............................................20
2.5. OSI Layer 2. Definir características del enlace de datos..22
3. La aplicación .........................................................................25
3.1. OSI Layer 7. La aplicación ................................................25
3.2. Tratamiento de eventos, recepción y errores ...................26
3.3. System.IO.Ports ¡El Espacio! ............................................28
4. Programando .......................................................................29
4.1. Nuestra primera aplicación ................................................29
5.Programando con técnica ....................................................38
5.1. Programando con técnica ..................................................38
6. ServidorComm. La clase......................................................50
6.1. ServidorComm. Introducción a la clase ...........................50
7. ServidorCom.dll. Nuestro laboratorio ..............................59
7.1. ServidorCom.dll ..................................................................59
7.2. Formato tramas envío/recepción ......................................60
7.3. Petición/respuesta entrega de cápsula - 01........................61
7.4. Petición/respuesta introducción de cápsula - 02 ..............62
7.5. Petición/respuesta estatus del sistema - 03 .......................65
7.6. Códigos retorno y operación .............................................67
7.7. Códigos Indicadores de Incidencias...................................68
7.8. Cálculo del CRC (pasos previos)........................................69
7.9. El simulador.........................................................................88
7.10. Mensajes en el EventLog .................................................97
7.11. Avisos de incidenciasautomatizados ................................98
7.12. Los archivos de configuración........................................103
7.13. La gestión del puerto serie ............................................106
7.14. Acceso a una base de datos Access ................................116
8. El ClienteEPlus. La solución ...........................................122
8.1. ClienteEPlus .....................................................................122
8.2. [F5] ....................................................................................146
9. De beta 1 a beta 2 ..............................................................147
10. Conclusiones ....................................................................150
10.1. Conclusiones ...................................................................150
10.2. La reflexión (pero en serio) ............................................150
10.2. Dedicatorias ....................................................................151
10.2. Agradecimientos..............................................................151
Introducción
Descripción
Entregon+ pertenece a la familia de los prestigiosos
dispensadores del grupo Dispensotron, potentes robots dis-
pensadores de encapsulados o carcasas que incorporan un
mecanismo de lectores grabadores con etiquetas electró-
nicas que permiten construir un sistema flexible y versá-
til, controlando tanto el contenido como el destinatario y
recepción del mismo. Elimina la necesidad de las aburri-
das secretarias encargadas del tedioso control manual de
entradas/salidas de material, siendo un almacén inteligen-
te, sin llegar a serlo.
Fabricado en base a una potente aleación de alumi-
nio/titanio, para paliar la acidez palmar de los usuarios de
este tipo de contenedores, así como la incorporación de
su bandeja de entrega antivandálica, hacen que
Entregon+ sea uno de los dispensadores de películas de
video o CD más potentes del mercado.
Su sencillez es alarde de robustez, un simple sistema
de coordenadas de eje horizontal con la movilidad del
cabezal en su eje vertical, permiten una sorprendente
simplicidad de estructura mecánica, tolerante a fallos y
libre de mantenimiento.
Su concepción permite dispensar encapsulados, tanto
en cajeros automatizados como en mostrador, siendo de
uso compartido y eliminando la inoperativa concepción
de dispensadores exclusivos (cajero/dispensador). Además
de optimizar el rendimiento, organización y coste por
cápsula dispensada.
Sus principales características son:
• Carcasa de aleación exclusiva Entregon+.
• Mecanizado de barras cabezal, niqueladas con auto
engrase.
• Lector/grabador de etiquetas electrónicas incor-
porados en el cabezal.
• Juego de 1.000 (EE) preparadas para más de 1
millón de grabaciones.
• Localizador/dispensador de carcasas de alta velo-
cidad, 3ª generación.
• Matriz de carcasas, con un máximo de 4m de largo
por 2m de alto.
• Sistema de doble procesador (RISC), tolerante a
fallo.
• Comunicaciones RS232/485.
Antes de dar alimentación al robot debe haber com-
pletado todos los pasos y recomendaciones de instalación.
Preparación: Desembale y desempaquete todos los
elementos que componen el dispensador, según le indican
las instrucciones detalladas en el lateral de las cajas. Una
vez localizadas y ordenadas por orden ascendente siga a
su ensamblaje siguiendo los pasos detallados en el primer
apartado.
Ensamblado
Matriz
1. Preparar los soportes de manera que los agüeros
mecanizados queden fijados a la pared con los tor-
nillos de disparo, preparados para soportar un
mínimo de 50Kg.
2. Utilizando los pernos 50, 51, 52 y 53, fijar las dos
barras de manera que observemos una paralela,
visualizándolo desde al menos dos metros de dis-
tancia.
3. Fijar las barras laterales a la guía porta cabezales.
4. Asegurar el anclaje que fija el usillo, no olvide
introducir los tornillos 23 y 24 de 12mm, apretán-
dolos con una presión de torque mínima de 12nw.
5. Realice la operación de test antes de integrarlo en
sistema alguno (siga las instrucciones del apartado
de puesta en funcionamiento).
MATRIZ
gráfico 1.1
Puesta en servicio
Prueba
1. Conectar el cable de alimentación a la toma de 220v.
2. Verificar que la luz “PowerLED” de color verde,
está encendida (consultar el apéndice “Resolución
de problemas” en caso contrario).
3. Observar la intermitencia del indicador naranja de
ignición, durante un tiempo aproximado de 30
segundos.
4. Esperar a que el indicador de “Ready” quede
encendido.
5. Pulsar el botón “Test”.
El puerto serie
Características
El dispensador Entregon+, incorpora dos UART
16C450 (Universal Asincronous Receiver Transmiter) de
Texas. Compartidas por los dos procesadores RISC. Su
avanzado diseño es tolerante a fallos, en cuyo caso, el pri-
mer procesador disponible conmuta las líneas de entra-
da/salida del conector serie RS232/RS485 a unos circui-
tos que convierten directamente las tensiones +/- 9/12V a
lógica TTL, permitiendo que el sistema continue traba-
jando sin interrumpir sus comunicaciones y lanzando una
alerta al sistema central, avisando de la anomalía en uno
de los controladores.
La tarjeta de comunicaciones serie es intercambiable
en caliente (HotSwap) de manera que el responsable de
mantenimiento podrá sustituir dicha tarjeta sin tener que
detener o reiniciar el sistema. Pida su pieza de recambio
PN=PS23MSDNVideo/3.
PATILLAS DEL CONECTOR SERIE
gráfico 2.1
gráfico 2.2
Un rápido análisis del gráfico 2.2 nos clarifica los
siguientes elementos:
Pensando en la unión de un transmisor y un receptor,
el transmisor dispone de una salida de datos SD, por la
que entrega un voltaje comprendido entre -3 y -15 Vcc,
para la señal de marca (Mark) y un voltaje entre +3 y +15
Vcc para la señal de espacio (Space). El proceso se inicia
con una transición de reposo a espacio, el receptor espe-
ra el bit de inicio (star), después del cual inicia la des-
seriacion de datos, marcada en intervalos exactos defini-
dos por la velocidad fijada en la operación de apertura del
puerto. Una vez recibidos los 8 bits, comprueba que la
paridad sea correcta y espera un periodo de paro corres-
pondiente al definido en bits de parada, para continuar
con la siguiente entrada de datos. El byte recibido se
almacena en un área tampón (búfer) del controlador de
comunicaciones que dispara una interrupción a la CPU
para que ésta recoja el dato antes de que éste sea sobres-
crito por la próxima recepción.
Llevar a cabo una comunicación serie nos obliga a
concentrarnos en:
a) Características del enlace a datos.
b) Envío/recepción asíncrona.
c) Tratamiento de eventos de recepción y errores.
Protocolo de comunicaciones DispeDataLink
Descripción
Entregon+ dispone del protocolo de comunicaciones
DDL (DispeDataLink) exclusivo de este dispensador. Este
protocolo le permite realizar las principales funciones de
posicionamiento, utilizando una sencilla comunicación de
intercambio de tramas. Por lo que incluso podemos
hacerlo trabajar mandándole órdenes a través del sencillo
Hyperterminal.
Como cualquier otro protocolo de comunicaciones,
DDL define su estructura OSI siguiendo el esquema del
gráfico 2.3.
OSI Layer 1. La capa física
Laboratorio 1
Para llevar a cabo este laboratorio deberá disponer de
un conector hembra de 9 contactos (ver gráfico 2.1), así
como de un soldador con estaño y diversos hilos de cobre
para realizar los puentes que se detallan en el gráfico 2.4.
En caso de no disponer de estos medios diríjase a una
tienda especializada de electrónica y pida este servicio.
gráfico 2.3
ESQUEMA DEL CABLE DE BUCLES
gráfico 2.4
gráfico 2.5
gráfico 2.6
EJEMPLO
gráfico 3.1
System.IO.Ports ¡El Espacio!
Detalle del espacio de nombres:
Clases Descripción
Enumeraciones Descripción
Delegados Descripción
Representa el método que manipula el evento error del
SerialErrorEventHandler
SerialPort.
tabla 3.1 Espacio de nombres para la utilización de los puertos serie. Framework 2.01
1
Información del Longhorn SDK Beta 1
capítulo 4
Programando
figura 4.1
En Visual Studio 2005, tenemos el código del diseña-
dor separado del código del formulario, por lo tanto nos
interesa editar el código del formulario (Form1.vb)… [F7]
para los avanzados.
A continuación declararemos nuestro objeto de acce-
so al puerto serie Puerto como clase de System.IO.Ports.SerialPort.
Para darle un aspecto más organizado, podemos
incluir tres regiones. Es de suponer que la mayoría de
vosotros sabéis que directiva #Region, nos ayuda a agrupar el
código (ver el fuente 4.1).
Su aspecto sería el de la figura 4.2.
#Region "Carga / Descarga del Formulario"
#End Region
.
.
#Region "Envio / Recepcion de tramas"
. etc.
Fuente 4.1
figura 4.2
figura 4.3
figura 4.4
figura 4.7
figura 4.8
Pero la ilusión se va a desvanecer tan rápido como
pulsemos el Button1… pues, ¡no ocurre nada!
Si aparentemente no ocurre nada, lo cierto es que
han pasado un montón de cosas, pues realmente la cade-
na “¡Hola Mundo!” ha sido enviada a nuestro controlador
serie que con una escrupulosa paciencia ha seriado todos
sus bits convirtiéndolos en voltajes a la salida del conec-
tor del COM4.
Eso será muy bonito en teoría, pero el pragmatismo
me obliga a decir que si no lo veo, no lo creo.
Enchufaremos el conector de pruebas, a nuestra sali-
da serie asignada (en nuestro laboratorio, COM4), este conec-
tor actúa como bucle, así pues cualquier dato enviado será
inmediatamente recibido.
Deberemos también añadir un temporizador timer
arrastrándolo de la caja de herramientas (toolbox) a nues-
tro formulario form1.
En el Sub Form_Load, añadiremos dos líneas de inicializa-
ción del timer de manera que leamos:
figura 4.9
figura 4.10
Fuente 5.1.
Fuente 5.2
Fuente 5.3
Destaquemos la importancia de la función Recibir en
nuestra clase. ¿Veis cómo es la receptora de Serie.ReceivedEvent?,
la aplicación que utilice nuestra clase podrá continuar su
ejecución a pesar de tener una petición pendiente de res-
ponder, por lo tanto, estará utilizando el puerto serie de una
manera desatendida. Nuestra clase recibirá el evento una
vez se haya completado una recepción y a continuación lo
notificara a sus instancias, disparándoles el evento respues-
ta… ¡Maravilloso!
Sobre el resto sólo comentar, que en New creamos el
objeto serie que nos dará acceso a todos sus métodos,
eventos y propiedades, en finalize liberamos el puerto serie
y que Enviar es tan simple como hacer escribir la trama al
objeto Serie.
Pasemos ahora a la funcionalidad en casa del cliente
Class Form.
He elegido un ejemplo que trabaje un par de con-
ceptos muy importantes, los eventos (events) y los hilos
(threats).
Existen dos maneras de afrontar los cambios en el
versionado de lenguajes:
1) A bofetones (sensación de torpe, siempre buscan-
do y sin haber perdido nada).
2) Esperar que los demás se peguen los bofetones y te
lo cuenten (sensación “seguro de ti mismo”, ima-
gen limpia, siempre con el traje impecable).
Como ya sabéis Visual Basic .NET, incorpora una
serie de avances cualitativos, inherentes a los lenguajes
orientados a objeto, además del mejorado manejo de
eventos y entre otras mil, poder utilizar hilos para la eje-
cución; dicho esto me confieso un aterrizado miembro
del grupo 1, y es un orgullo contribuir en la rápida adhe-
sión a esta tecnología para los del grupo 2.
A los acostumbrados a las anteriores versiones de
Visual Basic, no nos termina de encajar del todo este
modelo; antes de todo se ejecutaba sobre un plano, sin
embargo con el nuevo Framework, podemos crear hilos
hijos o llamar a otros hilos… Menuda potencia… pero
congones qué leches con lo de los hilos... lo único que yo
quiero es recibir la llamada de un evento y leer sus datos.
Bien aquí tenemos la parte formal, según nuestro
modelo de ejecución disponemos de un árbol de hilos del
que cuelgan nuestros procesos, una peculiaridad de los
formularios es que se ejecutan en un hilo, lo que no impi-
de que a partir de nuestro hilo, creemos otros hilos de
ejecución que cuelguen del nuestro “hilos hijos”, la inter-
acción con ellos resulta ciertamente asequible. Sin
embargo, las complicaciones llegan solas. Acabamos de
crear una clase que recibe la llamada de un evento que se
ejecuta en el espacio delegado de SerialReceivedEventHandler, o
sea, de otro hilo.
La pregunta sería ¿y a qué viene todo esto? La res-
puesta sería:
“illegal cross-threat operation, control accessed from a
threat other than the threat it was created on”
Resumiendo: ¡que no podemos tocar con los hilos de
otra guitarra!
Muchas veces me sorprendo a mí mismo intentando
dar explicación a todo esto de la OOP y siempre termino
igual, pensando en el ensamblador; al fin y al cabo es lo
que el procesador entiende, una secuencia que recorre la
memoria de arriba hasta abajo.
Rápidamente me repongo, con ánimo y ayuda
entiendo que efectivamente estas son excelencias que
requieren que nuestra mentalidad se adapte a los tiempos,
no por nada se inventaron los delegados. ¡Ya va siendo
hora de que los usemos!
La mayoría de nosotros tiene un vago concepto sobre
los delegados y su aplicación. Creo que este es un buen
ejemplo sobre todo para entender el modelo de ejecución
de nuestras aplicaciones, ¡vamos pues a coger el hilo por
sus extremos!
En las declaraciones deberemos crear ahora una ins-
tancia al objeto puerto:
Public Class Form1
'
Private Comunica A s Puerto = New Puerto 'Instancia nuestra clase Puerto
Private InicioFin A s Boolean = False 'Encadenar las peticiones (si/no)
Private DatosRecibidos A s String 'Datos recibidos
Fuente 5.4
'
'delegado para manejar la recepción de datos desde un 'threat' externo
Delegate Sub Refrescar()
Fuente 5.5
Fuente 5.6
'
'Preparamos el entorno
Private Sub Form1_Load(ByVal sender A s Object, ByVal e A s System.EventA rgs ...
'dirección de ejecución para el evento 'Respuesta' una vez recibidos los datos
A ddHandler Comunica.Respuesta, A ddressOf recibedatos
segundos.Interval = 1000 'Fijar el intervalo de disparo del temporizador
segundos.Enabled = True 'Temporizador en Marcha
Me.ProgressBar1.Maximum = 19200 'Fijar el valor maximo del progress bar 1
Me.ProgressBar2.Maximum = 19200 'Fijar el valor maximo del progress bar 2
End Sub
Fuente 5.7
'
'Cuando nos pulsen el botón
Private Sub Button1_Click(ByVal sender A s System.Object, ByVal e A s System.Eve ...
Comunica.Enviar(System.DateTime.Now) 'Enviamos la fecha/Hora
InicioFin = Not InicioFin 'Memorizamos Inicio/Fin
End Sub
Fuente 5.8
Fuente 5.9
'
'Disparo de la instancia del 'Puerto' llamada Comunica, cuando recibe una trama
Private Sub recibedatos()
DatosRecibidos = Comunica.Recepcion 'leer los datos recibidos
'
'invocar al delegado que rellene con los datosRecibidos el texto del label1
Me.Label1.Invoke(New Refrescar(A ddressOf actualizar_Datos))
'
'enviar otra trama, Si la trama contiene el caracter CR y queremos bucle.
If DatosRecibidos.Contains(Chr(13)) A nd InicioFin Then
DatosRecibidos = "" 'Limpiar los datos recibidos
Comunica.Enviar(System.DateTime.Now)
End If
End Sub
'
'delegado para leer y asignar los datos de otro hilo
Public Sub actualizar_Datos()
Me.Label1.Text = DatosRecibidos
End Sub
End Class
Fuente 5.10
figura 5.2
Uff... no sé si atreverme a pulsar [F5]... ¡Bien!
figura 5.3
figura 5.4
Detalles
Nuestra clase deberá estar compilada en un proyec-
to Class Library, para poder usar su funcionalidad desde
dispensador, simplemente añadiendo una referencia a la
misma.
Para poder desarrollar este laboratorio, es imprescin-
dible disponer de un equipo con un puerto serie y el conec-
tor descrito en el gráfico 2.3 (capítulo 2, “El puerto serie”).
Es aconsejable utilizar Windows 2003 Server o Windows
XP Profesional con SP2 y Visual Studio 2005 Beta 2.
Después de muchos años de trabajo, continuo apa-
sionándome cada vez que afrontamos la fase de definición
del proyecto. Es emocionante sentir nuestra imaginación
en un torrente desbordado de ideas que fluyen descontro-
ladamente, dando forma y sentido a un montón de zambu-
llidos neuronales, que poco a poco van componiendo ese
fantástico puzzle al que terminamos llamando solución.
Una primera imagen de nuestro trabajo, es diferen-
ciar sus dos elementos esenciales: el mecanismo
Entregon+ con su equipo controlador y nuestra aplica-
ción. A pesar de las grandes habilidades, tanto mecáni-
cas como de control de nuestro Entregon+, debemos
entender la importancia de esta simbiosis ya que dichas
versatilidades sólo afloraran con la ayuda de unas libre-
rías que sean capaces de dotar al conjunto de la funcio-
nalidad suficiente, para exponer toda la gestión del con-
junto de una manera simple y eficiente.
Dediquemos unos minutos a recorrer visualmente la
representación gráfica de nuestro objetivo (ver gráfico 6.1).
A primera vista puede parecer que no olvidamos nada
y como dibujito no está nada mal, sin embargo, un análi-
sis más detallado nos conducirá a descubrir que debemos
ser mucho más rigurosos y efectuar una descripción más
concreta.
Esta descripción detallada debe conducirnos directa-
mente a la definición de las clases necesarias que confor-
maran nuestras librerías.
Me gustaría insistir en el hecho de ser minuciosa-
mente escrupulosos al diseñar una librería en la que se
fundamentara el éxito de las aplicaciones que la exploten.
No podemos dejar nada al azar, debemos ser capaces de
construir un conjunto de funcionalidades “mantenimien-
to cero”.
ENLACE DE COMUNICACIONES–DISPENSADOR/ENTREGON+
gráfico 6.1
figura 6.1
gráfico 6.2
ServidorCom.dll
Por fin nos adentraremos en los placeres de la codi-
ficación, no sin antes recordar que necesitaremos tener
muy cerca la descripción de todos los formatos y códigos
que intervienen en nuestros procesos. Cuanto más deta-
llados sean nuestros modelos de formato y su descripción,
más fácil será nuestra labor posterior.
A continuación vamos a detallar el formato de las tra-
mas que intercambiaran el Entregon+ y nuestro sistema,
es importante entender su estructura, pues será hilo con-
ductor que sustentara nuestra aplicación... “son el cora-
zón de nuestro proyecto”.
gráfico 7.1
Petición/respuesta entrega de cápsula - 01
Para poder cumplir los requisitos del protocolo, debe-
remos fundamentarnos en la siguiente estructura de datos:
tabla 7.1
1
CRC = Cálculo de redundancia cíclica
CR = Carriage return
Petición
#010201080910111213477666555XFF$(Cr)
tabla 7.2
Respuesta
#020100FF$(Cr)
tabla 7.3
Petición
#010202FF$(Cr)
Sinónimo Tipo Posiciones Rango Descripción
tabla 7.4
Respuesta
#020100080910111213477666555FF$(Cr)
Petición/respuesta estatus del sistema - 03
Para poder cumplir los requisitos del protocolo,
deberemos fundamentarnos en la siguiente estructura de
datos:
tabla 7.5
Petición
#010203FF$(Cr)
Sinónimo Tipo Posiciones Rango Descripción
tabla 7.6
Respuesta
#020100EEEEFF$(Cr)
Códigos retorno y operación
Código Descripción
Código Descripción
01 Petición de expulsión de cápsula
02 Petición de Introducción de cápsula
03 Petición de banderas de estado controlador
Alertas
10 Todo Bien
11 Existe una alarma en el sistema leer estatus
Avisos
20 Producto solicitado en stock mínimo
21 Último producto
22 Últimas cápsulas
0080 0000 0000 1000 0000 Disparo del detector anti vandálico
0400 0000 0100 0000 0000 Suciedad en la óptica del láser posicionador
0800 0000 1000 0000 0000 Paro en el ventilador del sistema de refrigeración
tabla 7.9
Cálculo del CRC (pasos previos)
El Cyclic Redundancy Check es un mecanismo de veri-
ficación de error, que permite a la aplicación determinar
si la trama recibida está libre de errores.
Este checksum es generado por el remitente, sin
embargo, el destinatario debe volver a efectuar el cálculo
del CRC con los datos recibidos; es evidente que si el cál-
culo del CRC del remitente coincide con el del destinata-
rio, podemos casi afirmar que los datos recibidos están
libres de errores.
Es necesario precisar que este sistema no es efectivo
en la detección del 100% de errores que se produzcan,
aunque tampoco son frecuentes los errores en este tipo de
transmisiones. Por lo que podríamos considerar que para
nuestro cometido es más que suficiente.
Tampoco es preciso analizar este código, será sufi-
ciente entendiendo que a partir de una cadena de carac-
teres ASCII efectúa una suma binaria vertical y nos
devuelve dos bytes en formato ASCII que corresponden
al CRC que incluiremos al final de la trama. No olvide-
mos que su complejidad añadida se debe la necesidad de
entregar el resultado de una suma binaria de 16 bits en
dos caracteres ASCII que como ya sabéis son de 8 bits.
(ver Fuente 7.1)
Este fragmento de programa esta íntegramente des-
arrollado y diseñado en el año 89, por Pep. Utiliza la téc-
nica “Lo+Retorcida”, en esos años era la única forma de
proteger intelectualmente los desarrollos, se caracteriza-
ba porque “no había quien la entendiera”.
'
'
' Calcular el crc de la variable Var
'
'
Shared Function Crc(ByVal Var) A s String
Dim i A s Integer, j A s Integer
Dim CrcTmp A s Integer, Ct A s Integer, Ch A s Integer, Cl A s Integer
Dim C1 A s Integer, C2 A s Integer
CrcTmp = &HFFFF
For i = 1 To Len(Var)
CrcTmp = CrcTmp Xor A sc(Mid(Var, i, 1))
For j = 1 To 8
Ct = CrcTmp A nd &H1
If CrcTmp < 0 Then Ch = 1 Else Ch = 0
CrcTmp = CrcTmp A nd &H7FFF
CrcTmp = CrcTmp \ 2
If Ch = 1 Then CrcTmp = CrcTmp Or &H4000
If Ct = 1 Then CrcTmp = CrcTmp Xor &HA 001
Next j, i
If CrcTmp < 0 Then Cl = 1 : CrcTmp = CrcTmp A nd &H7FFF Else Cl = 0
C1 = CrcTmp A nd &HFF& : C2 = (CrcTmp A nd &H7F00) \ 256
If Cl = 1 Then C2 = C2 Or &H80
Return (Chr("&h" + Hex(C1)) + Chr("&h" + Hex(C2)))
End Function
Fuente 7.1
Fuente 7.2
'
' Propiedad DatosISBN
Public Property DatosISBN() A s String
Get
Return Datos_ISBN
End Get
Fuente 7.3
¡Eureka!, nuestros dos bloques de información defini-
dos en el primer apartado, ya están listos para ser usados.
Debemos componer una estructura para cada mode-
lo de solicitud, a saber: Expulsión, Introducción, Estado.
Así que compuestos los bloques de datos, abordare-
mos la construcción de las tramas dándoles el formato
adecuado.
Lo que pretende la siguiente estructura es abstraer el
rígido protocolo DispeDataLink de la aplicación, lo que
permite llamar a esta estructura sin necesidad de concen-
trarte en los aspectos formales (CRC/CR/Carácter de
Inicio/Fin..., etc.) de esa forma la aplicación se concentra
únicamente en los datos que maneja.
Esta sencilla fórmula es la responsable de componer
los bloques, ponerlos en orden, añadirles las cabeceras,
calcular los bytes de redundancia cíclica y entregarnos
una cadena que contiene la trama lista para enviar. ¿A
alguien le parece poco?
Fuente 7.4
Fuente 7.5
Por supuesto, no olvidaremos implementar la trama
para la solicitar el estado del dispensador.
Fuente 7.6
'
Friend Overloads Function Trama(ByVal UDest A s String, _
ByVal UOrig A s String, _
ByVal CodigoFin A s String, _
ByVal IndicadorEstatus A s Integer) A s String
'
blDatos1.UnidadDestino = UDest 'Unidad Destino
blDatos1.UnidadOrigen = UOrig 'Unidad Origen
blDatos2.CodigoFin = CodigoFin
blDatos2.IndicadorEstado = IndicadorEstatus 'Cod.Retorno Operacion
'
miTrama = Ini.ToString + _
blDatos1.UnidadDestino + _
blDatos1.UnidadOrigen + _
blDatos2.CodigoFin + _
blDatos2.IndicadorEstado
Return miTrama + calcular_Crc(miTrama) + Fin.ToString
End Function
End Structure
#End Region
Fuente 7.7
#End Region
Fuente 7.8
#End Region
Fuente 7.9
figura 7.1
El simulador
A los más impacientes se nos hace difícil teclear códi-
go sin poderle dar al [F5], sin embargo, es importante
seguir un orden, a pesar del desespero, como en la mayo-
ría de disciplinas, deberemos construir la infraestructura
que nos va a permitir elevar nuestro edificio hasta conse-
guir la altura diseñada.
Bien, una vez hemos completado la parte más aburri-
da (definir estructuras), pasaremos a conformar una vital.
Acabamos de construir un instrumento dispensador, sin
embargo, a todos los efectos requerimos disponer de un
simulador que emule el funcionamiento de nuestra
máquina.
La naturaleza y topología de las comunicaciones
entre nuestro dispensador y el equipo al que está unido,
nos obliga a intercambiar tramas en ambos sentidos,
debemos pues proveernos de todos los mecanismos nece-
sarios para poder desarrollar nuestra aplicación sin el
soporte del dispensador. Con la ayuda de este simulador
podremos construir una aplicación resistente. Además
podemos perfeccionar el simulador hasta tal punto en que
cambiar el simulador por el dispensador sea simplemente
eso: ¡cambiar!
¡… Bienvenido a la virtualidad!
Conseguiremos nuestro propósito dotando a nuestro
simulador de una función distribuidora de solicitudes, cual-
quier operación externa será dirigida y distribuida desde
este punto; la función llamará a cada uno de los procedi-
mientos contemplados, o sea, solicitud de introducción,
expulsión y estado. Codificaremos una función que com-
pondrá el modelo de respuesta. Finalizaremos nuestra
clase con la función A larmaGrave encargada de simular y
reportar los problemas relacionados con mensajes de
advertencia, informativos o de alarma.
figura 7.2
Su aspecto:
En el proceso de solicitudes, recibiremos la llamada a
la función incluyendo la trama recibida. Como vemos
asignaremos a la variable CodigoOpe la operación solicitada,
siendo éste el que decida en la Select qué función ejecuta-
remos para procesar dicha solicitud:
'
'Procesar las tramas recibidas por el simulador
Public Function ProcesoDeSolicitudes(ByVal TramaRecibida A s String) A s String
If Not Campos.LaTramaEstaCompleta(TramaRecibida) Then 'Trama no completa
TramaDeRespuesta = "" 'No procesamos Nada
Else
_Origen = Campos.Origen.ToString 'A signacion campos recibidos
_Destino = Campos.Destino.ToString
_CodigoOpe = Campos.CodigoOpe.ToString
Fuente 7.10
'
'Simular la expulsion
Private Sub SolicitarExpulsion()
'
'Simular ordenes del mecanismo
'If LocalizarCapsula(_ISBN) then
' CodigoDeRetorno = PosicionarPinzasCabezal(): VerificarCodigosFinDeOperacion
' CodigoDeRetorno = RecogerProductoEnPinzas(): VerificarCodigosFinDeOperacion
' CodigoOperacion = GrabarEtiquetaElectronica(_ISBN,_NIFCIF):VerificarCodFinDeOp
' CodigoDeRetorno = DejarProductoEnBandejas(): VerificarCodigosFinDeOperacion
'else
' ReportarProblemaDelSistemaLocalizador
'end if
'
'SIMULA DOR!!
_CodigoDeRetorno = SimuladorCodigoFin() 'Simular retorno incidencia entregon+
_CodigoFin = campos.CodigoOpe 'Operacion completada correctamente
ComponerRespuestaModelo()
'
'Insertar el ISBN al banco local de peliculas que podemos dispensar
End Sub
'
'Simular la introduccion
Private Sub SolicitarIntroduccion()
'
'Simular ordenes del mecanismo
' Disparo interrupcion por deteccion de introduccion de capsula
' CodigoOperacion = LeerEtiquetaElectronica(_ISBN, _NIFCIF)
'If CodigoOperacion then
' CodigoDeRetorno = PosionCabezalEnRecogida(): VerificarCodigosFinDeOperacion
' CodigoDeRetorno = RecogerProductoDePinzas(): VerificarCodigosFinDeOperacion
' CodigoDeRetorno = A ctualizarEtiquetaElectronica(_ISBN,_NIFCIF):VerCodFinDeOpe
' CodigoDeRetorno = PosicionProductoA lmacen() : VerificarCodigosFinDeOperacion()
' CodigoDeRetorno = DejarProducto(): VerificarCodigosFinDeOperacion
'else
' RechazarIntroduccionPorObjetoDesconocido
' LanzarA lertaA lUsuario
' ReportarCodigoErrorLecturaEtiqueta
'end if
'
_CodigoDeRetorno = SimuladorCodigoFin() '... ?
_CodigoFin = campos.CodigoOpe 'Operacion completada correctamente
'
_ISBN = campos.ISBN
_NIFCIF = campos.NIFCIF
ComponerRespuestaModelo()
End Sub
'
'Simular el estado del mecanismo
Private Sub SolicitarEstatus()
'_CodigoDeRetorno = SimuladorCodigoFin() '... ?
'
'ComponerRespuestaModelo()
Dim _Respuesta A s Tramas.RespuestaModelo = New Tramas.RespuestaModelo
TramaDeRespuesta =
_Respuesta.Trama(_Destino.ToString,_Origen.ToString, "03",IndicadoresEstado)
End Sub
'
'Formato de la respuesta
Private Sub ComponerRespuestaModelo()
Dim _Respuesta A s Tramas.RespuestaModelo = New Tramas.RespuestaModelo
TramaDeRespuesta = Respuesta.Trama(_Destino.ToString, _Origen.ToString, _
_CodigoFin.ToString, _CodigoDeRetorno.ToString)
End Sub
Fuente 7.14
Fuente 7.15
Fuente 7.16
Mensajes en el EventLog
Por fin, para nuestra librería, una clase “facilonga”.
Básicamente se compone de una función que genera una
entrada en el registro del sistema, determinada por su ori-
gen, su tipo de entrada y un identificador.
Todo esto se materializa en una única llamada a la
función WriteEntry del espacio System.Diagnostics.EventLog.
Fuente 7.17
'
'A visar de una A lerta utilizando el correo electonico
Public Sub A visar(ByVal emailMensa A s String)
'
'Lectura de las variables de configuracion del archivo app.config.
Dim email_From A s String = _
A plicacion.LeerConfig("app.config", "email_From", "emailOrigen").InnerText
Dim email_To A s String = _
A plicacion.LeerConfig("app.config", "email_To", "emailDestino").InnerText
A plicacion.LeerConfig("app.config", "email_Cc", "emailCopia").InnerText
Dim email_User A s String = _
A plicacion.LeerConfig("app.config", "email_User", "CuentaUsuario").InnerText
Dim email_Pwd A s String = _
A plicacion.LeerConfig("app.config", "email_Pwd", "password").InnerText
Dim email_smtp A s String = _
A plicacion.LeerConfig("app.config","email_Smtp","servidor").InnerText
'
'Conformar un mensage de mail
Dim correo A s MailMessage = New MailMessage
'Definir el esquema CDO
Dim Esquema A s String = "http://schemas.microsoft.com/cdo/configuration/"
'Llenar de contenido el mensage
correo.From = email_From
correo.To = email_To
correo.Cc = email_Cc
correo.Subject = "ENTREGON+, A LA RMA - REQUIERE INTERVENCION"
correo.Body = emailMensa
'A signar las credendiales
correo.Fields.A dd(Esquema + "smtpauthenticate", "1")
correo.Fields.A dd(Esquema + "sendusername", email_User)
correo.Fields.A dd(Esquema + "sendpassword", email_Pwd)
'A signar el nombre del servidor de correo
SmtpMail.SmtpServer = email_smtp
Try
SmtpMail.Send(correo) 'Enviar el correo
Catch ex A s Exception
'reportar problemas al eventlog
Mensaje.Registra("A lertas", ex.Message, EventLogEntryType.Error, 4)
End Try
End Sub
Fuente 7.18
'--------------------------------------------------------------------
'Version con nombre de espacios system.net.mail
'--------------------------------------------------------------------
'Dim correo A s MailMessage = New MailMessage(email_From, email_To)
'correo.Subject = "ENTREGON+, A LA RMA - REQUIERE INTERVENCION"
'correo.Body = email_Mensa
Fuente 7.19
figura 7.3
Los archivos de configuración
Si hemos estado atentos, la clase anterior llamaba a
un procedimiento: A plicacion.LeerConfig, no te sorprendas, aún
no hemos hablado de él. Cualquier aplicación que se pre-
cie debe almacenar y leer sus valores de configuración.
Como veremos, esta clase nos permite realizar esta fun-
ción utilizando un fichero en XML. Hemos decido usar
el app.config aunque quizás no sea la mejor forma, lo hace-
mos para entender que podemos concentrar toda la infor-
macion de configuración de la aplicación en un mismo
archivo. Para no complicar excesivamente el código, sólo
trabajaremos el documento XML a nivel de elemento.
Según se describe en la figura 7.4, podemos distin-
guir tres funciones :
Existe, LeerConfig y SalvarConfig.
figura 7.4
Existe simplemente verifica que el fichero solicitado
se encuentre en la carpeta de la aplicación.
'
'Verificar la existencia del archivo
Private Function Existe(ByVal Nombre A s String) A s Boolean
Dim Doc A s XmlDocument = New Xml.XmlDocument 'Documento XML
Try '
Doc.Load(Nombre) 'Intentar Cargar el nombre
Doc = Nothing 'Liberar el Doc
Return True 'A rchivo disponible
Catch ex A s Exception 'En otro caso
Return False 'A rchivo no disponible
End Try
End Function
Fuente 7.20
LeerConfig
lee un elemento del documento XML y si no
existe crea uno nuevo con el valor pasado por defecto.
'
'Leer un valor de Configuración de un A rchivo en formato XML
'Parametros de la funcion :
Fichero = Nombre del A rchivo en formato nnn.eee (Ejemplo: app.config)
' Raiz = Elemento
' Defecto = Valor que retornara por defecto
'
Public Function LeerConfig(ByVal Fichero A s String, ByVal Raiz A s String, _
ByVal Defecto A s String) A s Xml.XmlElement
Fuente 7.21
'
' Guardar un valor en el documento xml de configuracion
'
Public Function SalvarConfig(ByVal Fichero A s String, ByVal Raiz A s String, _
ByVal Valor A s String) A s Boolean
Dim Documento A s XmlDocument = New Xml.XmlDocument 'Constructo del Documento
Dim Elemento A s XmlElement = Documento.CreateElement("Raiz")
Fuente 7.22
Fuente 7.23
figura 7.5
Observaremos cómo se han ordenado cinco aparta-
dos. El primero de ellos crea las instancias que utilizare-
mos para acceder a los objetos de la librería (instancias a
clases). El segundo, tercero y cuarto, ordena las variables
que utilizaremos en la aplicación en grupos de configura-
ción, banderas y proceso. Es una agrupación muy prácti-
ca, facilitando la comprensión, sobre todo cuando esta-
mos en proyectos desarrollados en equipo. Salta a la vista
que el grupo de configuración definirá las variables usa-
das en la misma, las banderas son flags usados en el con-
trol del proceso y finalmente variables utilizadas para
contabilizar o memorizar datos generados en el mismo.
El último grupo... ¡importante! es el de los eventos.
En este punto asignaremos los nombres que manipularán
los eventos que nuestra aplicación deba conducir.
La siguiente figura nos ilustra las clases necesarias
para atender la transmisión y recepción de tramas.
figura 7.6
Empezaremos detallando las operaciones a realizar
en tiempo de carga: New, Dispose y Tiempo, para continuar con
los procedimientos que formarán nuestra columna verte-
bral: Enviar, Recibir y A brirPuertoSerie.
Por sí solos, todos los procedimientos descritos, con-
tienen suficientes comentarios y son lo suficientemente
sugerentes para poder seguir el hilo del código. Por lo que
animo al lector a leerlos detenidamente. Sin dudar añadi-
ré cualquier explicación que ayude a su entendimiento.
'Liberar el puerto
Protected Overrides Sub Finalize()
'cerrar el objecto serie
If PuertoSerieA bierto Then Serie.Close()
MyBase.Finalize()
End Sub
'
'Recibir una trama
Public Sub Recibir(ByVal sender A s Object, ByVal e A s _
System.IO.Ports.SerialDataReceivedEventA rgs) Handles Serie.DataReceived
Try
EnvioEnCurso = False 'Limpiar memoria estado Envio
Recepcion = Serie.ReadExisting.ToString 'Leer chars del buffer recepcion
CuentaBitsR += Recepcion.Length * 11 'contabilizar bits recibidos
Catch ex A s Exception
'registrar mensage en caso de error
Mensaje.Registra("ComSerie", ex.Message, EventLogEntryType.Error, 7)
UltimoMensajeError = ex.Message
End Try
'
'Simulador Envio/Recepcion entre Entregon y Servidor conectado a Dispensador
'
If SemaforoSimulador Then 'Debemos simular la operacion?
Try
'Simular peticion
Serie.Write(miSimulador.ProcesoDeSolicitudes(Recepcion))
CuentaBitsE += Recepcion.Length * 11 'Contabilizar bits recibidos
EnvioEnCurso = 'Señalizador de envio en curso
Catch ex A s Exception
'registrar mensage en caso de error
Mensaje.Registra("ComSerie", ex.Message, EventLogEntryType.Error, 8)
UltimoMensajeError = ex.Message
End Try
SemaforoSimulador = False 'Borrar indicador de simulacion
Else
RaiseEvent Respuesta() 'Disparar respuesta al cliente
End If
End Sub
Serie = My.Computer.Ports.OpenSerialPort _
(Puerto, VelocidadPuerto, IO.Ports.Parity.Even, 7, IO.Ports.StopBits.Two)
'
' Crear el objecto de acceso Serie
Public Function A brirPuertoSerie() A s Boolean
'
If PuertoSerieA bierto Then Serie.Close()
'constructor del objecto serie
Try
'Leer los valores para abrir el puerto desde archivo app.config
NombreDelPuerto = A plicacion.LeerConfig _
("app.config", "PuertoSerie_Nombre", NombreDelPuerto).InnerText
VelocidadPuerto = A plicacion.LeerConfig _
("app.config", "PuertoSerie_Velocidad", VelocidadPuerto).InnerText
'
NumeroPuertoA bierto = Val(NombreDelPuerto.Substring(3, 1))
Serie = My.Computer.Ports.OpenSerialPort _
(NombreDelPuerto, VelocidadPuerto, IO.Ports.Parity.Even, _
7, IO.Ports.StopBits.Two)
UltimoMensajeError = NombreDelPuerto & "/" & VelocidadPuerto & "Open"
PuertoSerieA bierto = True
Catch ex A s Exception
'registrar mensage en caso de error
Mensaje.Registra("ComSerie", ex.Message, EventLogEntryType.Error, 5)
NumeroPuertoA bierto = 0
UltimoMensajeError = ex.Message
PuertoSerieA bierto = False
End Try
Return PuertoSerieA bierto
End Function
Fuente 7.30
'
' Introducir una capsula, comprovando si esta existe para marcarla a 'true' o
creando registro en caso contrario
'
Public Function Introducir(ByVal ISBN A s String, _
ByVal NIFCIF A s String) A s Integer
'---------------------------------------------------------------
'No se contempla que un cliente pueda alquilar la misma pelicula
' Retorna :
' 0 = Si no puede actualizar la Capsula
' 1 = Si el proceso se ha efectuado con normalidad
' 888 = Existe duplicacion de capsulas
' 999 = Si existe un conflicto de estado o capula registrada dentro
Fuente 7.30
figura 7.8
capítulo 8
El ClienteEplus
ClienteEPlus
A estas alturas más de uno estará pensando que tiene
una sensación un tanto extraña, nos hemos dedicado a
plantear una librería entera ¡sin tan siquiera probarla!, me
confesaré: esta situación idílica es sólo posible para unos
pocos privilegiados, quizás sólo algunos de nuestros gran-
des maestros como..., por no hablar de otros. Pero aún y
así me resisto a pensar que sea cierto.
Los libros como las películas nos presentan una
situación perfecta dendro de un escenario donde no cabe
posibilidad de error. Es evidente que a pesar de que
muchos arquitectos sean capaces de planificar su desarro-
llo a niveles tan elevados que incluso puedan codificar una
librería a pelo, tal como si estubiéramos hablando de unos
cimientos, la mayoría de mortales necesitamos construir
las bases de nuestros cimientos desde el primer piso. Sé
que esto suena muy mal y aún con riesgo de que me exco-
mulgen de mi apreciada comunidad de MVP, es cierto
que antes de abordar la organización de la librería resulta
muy útil contruirla y probrala desde el cliente, de mane-
ra que vamos organizando y encapsulando los conjuntos
de código o spnnipeds que resultan útiles y comunes al
resto de la aplicación.
Por lo tanto, a estas alturas debo confesarme, el des-
arrollo práctico lo hubiéramos empezado definiendo las
necesidades del cliente y, a partir de éstas, codificando el
contenido de la librería, resumiendo, estaríamos cons-
truiendo nuestro cliente y nuestra librería de una manera
paralela.
Sin embargo, debemos consolarnos pensando en la
existencia de un montón de “teóricas” y “buenas prácti-
cas” que quedan muy bien entre comillas. Por de pronto,
lo interesante es avanzar en un increíble entorno integra-
do de desarrollo, tampoco era nuestra intención abordar
técnicas avanzadas de codificación, me gustará entonces
reforzar la idea de que este libro debe servirnos como
modelo para iniciar o migrar sin complejos nuestras apli-
caciones. Eso sí, siendo conscientes de las limitaciones de
migracion de grandes aplicaciones.
Me gustaría pues desde aquí dar ánimos para iniciar
nuestra aventura a todos aquellos que dudan y se sienten
atrapados en antiguos diseños; no conozco ningún entorno
de programacion mas productivo que Visual Studio 2005 y
os aseguro que no estoy haciendo marketing. Me he pasa-
do media vida programando y es increíble ver cómo conse-
guimos nuestros objetivos practicamente codificando cua-
tro líneas, recordando la aureola de los programadores y su
mito me cuesta creer que yo soy uno de ellos, pues real-
mente con estos entornos más bien me asemejo a un usua-
rio avanzado. Os estoy diciendo que ¡es muy fácil!
Bien, vamos a darle forma a nuestro cliente, será una
buena experiencia iniciar la construccion de nuestros
contenedores con el nuevo diseñador de WinForms
(impresionante la colección de controles, listos y a punto
para ser usados). La gran difierencia con otras versiones
es que ¡menudos controles!, nada parecido hasta la fecha,
por lo tanto, ¡venga! Con cuatro arrastrar y soltar vere-
mos un formulario repleto de cositas…
figura 8.1
Debo hacer hincapié y destacar la utilidad del
Document Outline (ver a la izquierda del diseñador),
imprescindible para llevar a cabo una nomenclatura efi-
ciente y coherente. Su navegación permite asignar los
nombres con una facilidad y agilidad suficiente para que
nunca más utilicemos los por defecto Label1, Command1...
figura 8.2
La aplicación del cliente se ha divido en tres partes:
una superior conteniendo un control de tablas con un pri-
mer marco que contiene los botones de solicitud de intro-
ducción y expulsión, juntamente con las cajas de texto
para informar el ISBN y el NIFCIF; la segunda pestaña
del control tab contiene una lista que se llenará con los
textos correspondientes a la solicitud de estado del
Entregon+. Finalmente la última pestaña contiene los
textboxes necesarios para informar de la configuración de
envío de correos electrónicos automáticos al detectar una
alarma grave.
La parte media contiene un marco con las etiquetas
que se utilizan para visualizar todos los mensajes de la
aplicación, así como las específicas para monitorizar las
tramas enviadas y recibidas. Este marco así como el infe-
rior están siempre visibles.
figura 8.6
Y este es su icono:
figura 8.7
Fuente 8.1
figura 8.8
Tal como comentábamos anteriormente es importan-
te el uso de cabeceras que describen nuestro “Historial Clí-
nico”, tan importante como agrupar las funciones dentro
de nuestras regiones de la aplicación.
Fijaros que son dos aspectos muy simples de observar,
sin embargo, de vital importancia para el trabajo en equi-
po. Marcar un modelo que identifica un estilo de progra-
mación, compromete a los ingenieros involucrados en el
proyecto a usar una metodología común, que facilita ex-
traordinariamente la lectura y localización del código. Con-
diciones primordiales para conseguir un desarrollo eficien-
te y un mantenimiento de aplicaciones asequible. Pero
subrayo: aplicaciones hechas en equipo.
No es de extrañar que haga uso de esta receta agru-
pando los procedimientos en torno a cuatro regiones: Car-
gar/liberar formulario, recepción y procesado del evento respues-
ta, interacción con el usuario y, finalmente, rutinas de uso
general.
El primer grupo contiene la ejecución del código en
tiempo de carga y descarga del formulario, que normal-
mente realiza operaciones de preparación efectuando las
inicializaciones necesarias para la puesta en marcha de la
aplicación. La segunda, recepción y procesado, contiene la su-
brutina que recibirá el disparo del evento en tanto dispo-
nemos de una respuesta a nuestra petición. Esta respuesta
será analizada y posteriormente procesada, no sin compro-
bar la validez de sus datos. El tercer grupo contiene el có-
digo que se ejecuta a petición del usuario, a saber, cuando
pulsa el botón para la solicitud de expulsión, el botón de
abrir el puerto serie, etc. Finalmente no es mala idea in-
cluir una región que contiene todos los procedimientos de
uso general en nuestro formulario y que no son parientes
directos de ninguno de los anteriores.
Veamos todo esto con mayor detalle. Repasaremos las
operaciones que el cliente debe realizar en tiempo de car-
ga/descarga del formulario.
'
' A l cargar el formulario
'
Private Sub frmClienteEPlus_Load(ByVal sender A s Object, ByVal e A s _
System.EventA rgs) Handles Me.Load
'imagen estado ko. del puerto serie Visible
Me.pbxKo.Visible = True
'direccionar los eventos de respuesta a la sub DatosRecibidos
A ddHandler PuertoSerie.Respuesta, A ddressOf DatosRecibidos
End Sub
Fuente 8.2
'
' Liberar objetos instanciados
'
Private Sub frmClienteEPlus_Disposed(ByVal sender A s Object, ByVal e A s _
System.EventA rgs) Handles Me.Disposed
PuertoSerie = Nothing 'Liberar puerto serie
Campos = Nothing 'liberar constructor formato tramas
A plicacion = Nothing 'liberar acceso archivo configuraciones app.config
End Sub
Fuente 8.3
'
' Recepcion de respuestas
'
Public Sub DatosRecibidos()
miRespuesta = Me.PuertoSerie.Recepcion 'los datos recibidos
'Procesar y Visualizar la recepcion en la etiqueta
Me.lblRespuesta.Invoke(New EntreHilos(A ddressOf ProcesolblRespuesta))
If Campos.LaTramaEstaCompleta(miRespuesta) Then 'Si la trama es completa
'procesar la respuesta, mostrando incidencias
Me.lblInicidencia.Invoke(New EntreHilos(A ddressOf procesolblInicidencias))
End If
End Sub
Fuente 8.4
'
' Procesar la recepcion segun los codigos de respuesta
'
Private Sub ProcesolblRespuesta()
If Campos.LaTramaEstaCompleta(miRespuesta) Then 'Con la respuesta completa
Select Case Campos.CodigoOpe
Case "00" 'Codigos operacion 00
' Simplemente visualizamos respuesta
Me.lblRespuesta.Text = "(" + miRespuesta + ")"
Case "01" 'Codigo 01 - Expulsar
'
CRA ccesoBDS = MarcarBD.Expulsar(Me.txtISBN.Text, Me.txtNIFCIF.Text)
Me.lblRespuesta.Text = "(" + miRespuesta + ")"
Case "02" 'Codigo 02 - Introducción
'
CRA ccesoBDS = MarcarBD.Introducir(Me.txtISBN.Text, Me.txtNIFCIF.Text)
Me.lblRespuesta.Text = "(" + miRespuesta + ")"
Case "03" 'Codigo 03 - Estado
'Llenamos la lista de indicadores estado
Me.lblRespuesta.Text = "(" + miRespuesta + ")"
Indicadores = "&h" + Campos.Indicadores
LlenarListaIndicadores()
Me.lblInicidencia.BackColor = Me.BackColor
Case Else
'Ignorar los codigos de operacion desconocidos
Me.lblRespuesta.Text = "Error Codigo :" & Campos.CodigoOpe
End Select
Else 'Sin respuesta completa reportamos error
Me.PnlExpulsion.BackColor = Color.Red
Me.lblRespuesta.Text = "(" + miRespuesta + ")"
Me.lblInicidencia.Text = "El mecanismo entrega, esta fuera de Servicio"
End If
End Sub
'
' Procesar los codigos fin de operacion
'
Private Sub procesolblInicidencias()
'
' A signar texto segun la correspondencia de codigos / literales
' Nota: este codigo deberia ser leido de una base externa, no se incluye
' aquí para simpificar su entendimiento
Fuente 8.7
Nuestro formulario contiene un temporizador de un
segundo, por lo tanto después de este intervalo se ejecuta
esta función que básicamente se encargará de refrescar la
información más relevante para el usuario, tales como la
presentación de los bits transmitidos/recibidos, así como
hacer visibles o invisibles los paneles de errores, después
de haberlos visualizados durante un tiempo determinado,
como también el control de pequeñas filigranas que
hacen más atractiva la interacción de la aplicación con el
usuario.
No es necesario analizar el código con más detalle,
pues a pesar de su aspecto estético, no lo considero de
interés técnico... recordemos que nuestro objetivo es el
correcto uso de las librerías del Entregon+. Tampoco
quiero aconsejar estas técnicas para mantener el aspecto y
refresco de información en pantalla; como siempre es una
solución de compromiso y, como digo, nos interesa con-
centrarnos en el cómo.
'
' A ctualizar los datos de nuestro formulario
'
Private Sub tmpRefresco_Tick(ByVal sender A s System.Object, ByVal e A s _
System.EventA rgs) Handles tmpRefresco.Tick
On Error Resume Next
Static Veces A s Integer, Mensaje A s String, VecesRegistro A s Integer
'Filigranas relacionadas con refresco, intermitencia de colores y mensajes
If Me.lblInicidencia.Text.Length > 0 Then
If Mensaje <> Me.lblInicidencia.Text Then Veces = 0
Veces += 1
If Veces < 11 Then
'Durante 10 segundos visualizar mensaje en el centro e intermitente
Mensaje = Me.lblInicidencia.Text
Me.lblInicidencia.TextA lign = ContentA lignment.MiddleCenter
If Me.lblInicidencia.ForeColor = Me.PnlExpulsion.BackColor Then
Me.lblInicidencia.ForeColor = Color.Black
Me.lblInicidencia.BackColor = Me.BackColor
Else
Me.lblInicidencia.ForeColor = Me.PnlExpulsion.BackColor
Me.lblInicidencia.BackColor = Color.Black
End If
Else
'Pasados 10 segundos apagar intermitencia y alinear a la izquierda
Me.lblInicidencia.TextA lign = ContentA lignment.TopLeft
End If
Else
Veces = 0
End If
'
If Me.PuertoSerie.PuertoSerieA bierto Then
'Permitir solicitudes y dejar visible la imagen de puerto OK.
Me.btnIntroducir.Enabled = True
Me.btnExpulsar.Enabled = True
Me.pbxKo.Visible = False
Me.pbxOk.Visible = True
Else
'Denegar solicitudes y dejar visible la imagen de puerto KO.
Me.btnIntroducir.Enabled = False
Me.btnExpulsar.Enabled = False
Me.pbxKo.Visible = True
Me.pbxOk.Visible = False
End If
Me.pbxTry.Visible = False 'Solo visible en el momento de abrir el puerto
'
'A signar mensajes del PuertoSerie a las etiquetas de nuestro 'Form'
Me.lblTextoMensaje.Text = Me.PuertoSerie.UltimoMensajeError
Me.lblBitsRecibidos.Text = Me.PuertoSerie.Recibidos.ToString
Me.lblBitsEnviados.Text = Me.PuertoSerie.Recibidos.ToString
'
'A lertar de que existen mensajes en el EventLog
If ServidorComm.RegistroA lertas.MensajesEnRegistro Then
VecesRegistro += 1
Me.lblTextoMensaje.Text = Me.lblTextoMensaje.Text + _
Chr(10) + Chr(13) + "**Mensajes en Registro A plicacion del Sistema"
If VecesRegistro > 10 Then
VecesRegistro = 0
ServidorComm.RegistroA lertas.MensajesEnRegistro = False
End If
End If
'
'Si no exiten mensajes, esconder la etiqueta visualizacion
If Me.PuertoSerie.UltimoMensajeError.Length = 0 A nd _
ServidorComm.RegistroA lertas.MensajesEnRegistro = False Then
Me.lblTextoMensaje.BorderStyle = BorderStyle.None
Me.lblMensaje.Visible = False
Else
Me.lblTextoMensaje.BorderStyle = BorderStyle.Fixed3D
Me.lblMensaje.Visible = True
End If
'A signar el valor del puerto al numeric Up/Down
If Me.PuertoSerie.UltimoMensajeError.Substring(0, 3) = "COM" Then
Me.nudPuerto.Value = Val(Me.PuertoSerie.UltimoMensajeError.Substring(3, 1))
End If
Fuente 8.8.
'
' A l Incrementar / Disminuir seleccion de puerto de trabajo
'
Private Sub budPuerto_ValueChanged(ByVal sender A s System.Object, ByVal e A s _
System.EventA rgs) Handles nudPuerto.ValueChanged
'Siempre que el valor se la seleccion se encuentre entre 1 i 8
If (Me.nudPuerto.Value < 9) A nd (Me.nudPuerto.Value > 0) Then
'guardar la seleccion de puerto en archivo app.config
'asi lo abriremos por defecto la proxima session
A plicacion.SalvarConfig("app.config", "PuertoSerie_Nombre", "COM" & _
Me.nudPuerto.Value.ToString)
Else
'forzar a 1 cuando los valores esten fuera de rango
nudPuerto.Value = 1
End If
End Sub
Fuente 8.9. Cuando el usuario pulsa el Up/Down del control numérico o introduce un
valor en su entrada.
'
' A brir el puerto de comunicaciones
'
Private Sub btnA brir_Click(ByVal sender A s System.Object, ByVal e A s _
System.EventA rgs) Handles btnA brir.Click
'a la pulsacion del boton de abrir
Me.pbxTry.Visible = True 'visualizar imagen : intento abrir puerto
Me.pbxKo.Visible = False 'esconder imagen Ko
Me.pbxOk.Visible = False 'esconder imagen Ok
Me.PuertoSerie.A brirPuertoSerie() 'A brir el puerto Serie
End Sub
'
' Enviar un correo de pruebas
'
Private Sub btnPrueba_Click(ByVal sender A s System.Object, ByVal e A s _
System.EventA rgs) Handles btnPrueba.Click
'a la pulsacion de btnPruebas
'Instanciar la clase para envio de correo
Dim Enviar A s A lertasPorCorreo = New A lertasPorCorreo
Enviar.A visar("Prueba de Correo A utomatizado") 'enviar el correo
End Sub
Fuente 8.12. Al pulsar el botón leer (leemos la configuración para envío automatizado)
panel “AutoeMail”
'
'Guardar valores de configuracion personal, para el envio de alertas por email
'
Private Sub btnSalvar_Click(ByVal sender A s Object, ByVal e A s _
System.EventA rgs) Handles btnSalvar.Click
'a la pulsacion de btnSalvar, guardar valores de configuracion de los textbox
A plicacion.SalvarConfig("app.config", "email_From", Me.txtEmail_From.Text)
A plicacion.SalvarConfig("app.config", "email_To", Me.txtEmail_To.Text)
A plicacion.SalvarConfig("app.config", "email_Cc", Me.txtEmail_Cc.Text)
A plicacion.SalvarConfig("app.config", "email_User", Me.txtEmail_User.Text)
A plicacion.SalvarConfig("app.config", "email_Pwd", Me.txtEmail_Pwd.Text)
End Sub
'
' Expulsar una capsula
'
Private Sub btnExpulsar_Click(ByVal sender A s System.Object, ByVal e A s _
System.EventA rgs) Handles btnExpulsar.Click
'a la pulsacion del btnExpulsar
Dim peticion A s Tramas.SolicitarExpulsion = New Tramas.SolicitarExpulsion
'Trama de expulsion
Dim miPregunta A s String = ""'Inicializar variables
Me.lblInicidencia.Text = ""
Me.lblRespuesta.Text = ""
'Componer la peticion utilizando los campos de entrada ISBN/NIFCIF
miPregunta = peticion.Trama(2, 1, Me.txtISBN.Text, Me.txtNIFCIF.Text)
Try
Me.PuertoSerie.Enviar(miPregunta) 'Enviar peticion
Me.lblPregunta.Text = "(" + miPregunta + ")" 'testigo peticion etiqueta
Catch ex A s Exception
Me.lblInicidencia.Text = ex.Message 'En caso de problema..
Me.lblPregunta.Text = "(" + miPregunta + ")"
End Try
End Sub
Fuente 8.14. Al pulsar el botón de expulsión, generaremos una solicitud de entregar una
cápsula.
Fuente 8.16.Al hacer un clic en la pestaña “Estatus” del control tab, generaremos una solicitud
“03” para conocer el estado del Entregon+.
[F5]
¡No me lo puedo creer! En un tristrás hemos des-
arrollado una librería de enlace para el Entregon+ y ade-
más nos hemos entretenido implementado un cliente
para probar y explotar sus funciones.
Sí amigos, si hemos seguido los pasos correctamente,
no hay nada que temer, he aquí nuestra recompensa, nos
merecemos un [F5].
figura 8.9
figura 9.1
figura 9.2
figura 9.4
Conclusiones
En mis años de vida, he observado que existen algu-
nos lectores que empiezan leyendo el final de libro. Tam-
bién he observado que muchos otros lectores, sienten tal
impaciencia por iniciar la lectura que omiten las primeras
páginas del libro, para irse directamente al primer capítu-
lo.
Siguiendo la inteligencia que me ha caracterizado du-
rante todo este tiempo y después del riguroso análisis an-
terior, aprovechando esta situación de omitir las primeras
hojas y empezar por el final, voy a colocar lo mejor del li-
bro (dedicatorias, agradecimientos, pensamientos filosófi-
cos)… ¡AQUÍ!
La reflexión (pero en serio)
Con la mano en el corazón, a todos los que empeza-
ron leyendo el libro en sus primeras páginas y han llegado
a este su final, mi más sincero agradecimiento.
Mi trabajo ha sido simple y muy divertido, tal como
los exploradores, he iniciado un viaje cuyo destino era Vi-
sual Studio 2005. Ciertamente he ido y he vuelto con la sa-
tisfacción de poder relataros mi experiencia, sin dudar vues-
tra lectura ha dado sentido a mis esfuerzos. Otra cosa serán
las opiniones, los que hayan sintonizado gozarán de haber
adquirido algún que otro conocimiento útil y desearán más,
otros opinarán que hoy en día cualquier tres al cuarto se
atreve a escribir, pero lo importante para mí, aunque sue-
ne cursi, es que lo he escrito pensando en los que como yo,
tenéis ganas de aprender.
Realmente ha sido un buen viaje, repleto de retos, aven-
turas, dificultades, aunque lo único que haya echado en fal-
ta es la presencia de algún compañero.
Empecé a escribir con la ilusión de que me ocurriera
lo que a la Wooling, ¡sí hombre!... la del Jarry Poster, que
mi obra se convirtiera en un Guest Seler, para poder dedi-
carme a hacer películas... ¡eso sí! películas informáticas. Sin
embargo, el mercado laboral, mi precaria situación técni-
ca y el futuro poco esperanzador, me ha llevado a presen-
tar una solicitud en regla para cubrir una plaza de monje
informático en la abadía de Montserrat. A todo ello…
Dedicatorias
Toda mi gratitud a las Gemmas (hija y esposa) por ha-
cerme la vida imposible todos los fines de semana, mientras
intentaba escribir y poner un poco de orden a todo esto que
habéis leído. Mi reconocimiento a tan ardua tarea, no es fácil
sembrar de obstáculos el camino de un escritor tan prolífico.
Sin embargo, ellas lo han conseguido.
Agradecimientos
Mi absoluto rechazo a los esfuerzos de Alfonso Rodrí-
guez y David Carmona, responsables directos de “Desarro-
lla con MSDN”, y de Paco Marín de dotNetManía, que ha-
ciéndome caso omiso, me han ayudado para que este
“montón de hojas” a las que ellos llaman “aportación” vean
la luz en dotNetManía. ¡Espero que sea la última vez!
Este libro pertenece a: