proyecto de control distribuido de una planta

Anuncio
PROYECTO DE CONTROL DISTRIBUIDO
DE UNA PLANTA
FECHA: 1/ 2/ 2001
REALIZADO POR: Carlos Blanco Morcillo
SITUACIÓN: UNIVERSIDAD ROVIRA I VIRGILI
TARRAGONA
0
DOCUMENTACIÓN DEL PROYECTO
1 - Memoria descriptiva
2 - Memoria de cálculo
3 - Planos
4 - Presupuesto
5 - Pliego de condiciones
1
Índice General
1 Memoria descriptiva
1.1 Objeto el proyecto
1.2 Titular
1.3 Situación
pg.6
1.4 Posibles soluciones y solución adoptada
1.4.0 Introducción al control distribuido y a los buses de campo
pg.8
- Antecedentes
- Actualidad
- Tendencias
- Buses de campo
pg.7
1.4.1 Modelo de referencia OSI
1.4.1.1 Ejemplo de utilización del modelo OSI
1.4.1.2 Aplicación
1.4.1.3 Terminología OSI
pg.17
1.4.2 Medio de transmisión, Estándares RS232 y RS485
pg.26
1.4.3 Interfaces para las comunicaciones
1.4.3.1 La capa física en los PCs
1.4.3.1.1 El puerto serie
1.4.3.1.2 La UART
1.4.3.2 La capa física en los microcontroladores SAB80c537
1.4.3.2.1 El puerto serie
1.4.3.3 Tarjetas de comunicaciones a fabricar
pg.36
pg.37
pg.43
pg.45
pg.49
1.4.4 Topología de la red y del bus de campo
pg.52
1.4.5 El proyecto 802 del IEEE
1.4.5.1 Comparativa de protocolos de buses de campo y elección de este
1.4.5.1.1 Comparativa de buses de campo (características)
1.4.5.1.2 Protocolo del 80c537
1.4.5.2 Protocolo Modbus (introducción)
1.4.5.2.1 Formatos de las funciones Modbus
1.4.5.2.2 Códigos de función
1.4.5.2.2.1 Subfunciones de diagnóstico Modbus
pg.111
1.4.5.2.2.2 Códigos de diagnósticos soportados por los controladores
pg.112
1.4.5.2.3 Respuestas a excepciones
1.4.5.2.4 Códigos de excepción
1.4.5.2.5 Máximo número de parámetros
pg.55
pg.56
pg.59
pg.73
pg.75
pg.87
pg.90
2
pg.13
pg.23
pg.118
pg.119
pg.120
1.4.5.2.6 Tiempos estimados en transmisiones
1.4.5.2.7 Generación de LRC y CRC
pg.121
pg.123
1.4.6 La Norma IEEE 802.2
1.4.6.1 Especificaciones de servicio
1.4.6.2 Protocolo del subnivel LLC
1.4.6.2.1 La PDU LLC
1.4.6.2.2 Tipos y clases de LLC
1.4.6.2.3 Estructura de la PDU LLC
1.4.6.2.3.1 Formato Información
1.4.6.2.3.2 Formato Supervisión
1.4.6.2.3.3 Formato no numerado
1.4.6.3 Métodos de acceso al medio
1.4.6.3.1 Visión general del IEEE 802.4
1.4.6.3.2 Interfaz LLC-MAC
1.4.6.3.3 Protocolo subnivel MAC
1.4.6.3.4 Gestión de acceso al medio
1.4.6.3.5 Esquema de prioridades en el TOKEN BUS
1.4.6.3.6 Estructura interna del MAC
pg.126
pg.137
pg.140
pg.141
pg.142
pg.144
pg.147
pg.148
1.4.7 Descripción final de la red a implementar
pg.150
1.5 Descripción general
1.5.1 Bus de campo
1.5.2 Red Local
1.5.3 Adaptación del protocolo Modbus a los SAB80c537
1.5.3.1 Descripción general
1.5.3.2 Disposición de la SRAM externa
1.5.3.3 Disposición de la EPROM
1.5.3.4 Asignación de recursos
1.5.3.5 Conformidad con el protocolo Modbus RTU
pg.151
1.6 Prescripciones Técnicas
1.7 Puesta en marcha y funcionamiento
1.8 Planificación y programación
1.9 Resumen del presupuesto
1.10 Glosario
1.11 Anexo
pg.131
pg.132
pg.135
pg.153
pg.154
pg.155
pg.157
pg.159
pg.160
pg.162
pg.164
pg.168
pg.169
pg.171
2 Memoria de cálculo
2.1 Tarjeta conversora para PC
2.2 Programación bus de campo
2.2.1 Programa de los SAB80C5375
2.2.2 Diagramas de flujo
2.2.3 Código Ensamblador
2.2.3.1 Librería de definiciones
pg.173
pg.175
pg.178
pg.185
pg.224
3
2.3 Programación red local
2.3.1 Workstation
2.3.1.1 Código en Turbo C
2.3.1.2 Diagramas de flujo
pg.225
pg.302
2.3.2 Front-End
2.3.2.1 Código en Turbo C
2.3.2.2 Diagramas de flujo
pg.314
pg.397
2.4 - Manuales de los programas
2.4.1 SRM versión Workstation
2.4.2 SRM versión Front-End
pg.398
pg.402
2.5 - Programas de ayuda y apoyo
2.5.1 Código de programación en Turbo C y lenguaje ensamblador
pg.406
3 Planos
pg.410
3.1 Esquema y layout de la tarjeta conversora RS232/485
3.2 Plano de la red local y el bus de campo
3.3 Esquema de conexionado
3.4 Esquema y layout de la tarjeta de expansión
4 Presupuesto
4.1 Mediciones
4.2 Cuadro de precios nº 1
4.3 Cuadro de precios nº 2
4.4 Presupuesto
4.5 Resumen del presupuesto
pg.415
pg.416
pg.420
pg.431
pg.433
5 Pliego de condiciones
5.1 Pliego de condiciones generales de índole legal
5.2 Pliego de condiciones generales de índole facultativa
5.3 Pliego de condiciones generales de índole económica
5.4 Pliego de condiciones generales de índole técnica
4
pg.435
pg.437
pg.439
pg.440
1 MEMORIA DESCRIPTIVA
1.1 - Objeto del proyecto
1.2 - Titular
1.3 - Situación
1.4 - Posibles soluciones y solución adoptada
1.5 - Descripción general
1.6 - Prescripciones Técnicas
1.7 - Puesta en marcha y funcionamiento
1.8 - Planificación y programación
1.9 - Resumen del presupuesto
1.10 - Glosario
1.11 - Anexos
5
1.1 Objeto del proyecto
Definir el soporte software y hardware necesarios, a fin de poner en marcha la
implementación del control distribuido de una planta. Para ello el sistema
implementará hasta la subcapa LLC de la capa de enlace del modelo MARISA (OSI
en inglés) de ISO, también se dispondrá de una aplicación para que el usuario pueda
interactuar.
La implementación de dicha red y bus de campo se realizará empleando ordenadores
personales y microcontroladores. Las comunicaciones que se lleven a cabo en el
ámbito de bus de campo, estarán adecuadas a los dispositivos de control local
prefijados para la simulación de dicha instalación (microprocesadores SAB80c537).
1.2 Titular
Nombre: UNIVERSIDAD ROVIRA I VIRGILI
Dirección social: Ctra. Salou s/n
Localidad: TARRAGONA
Teléfono: 977/559600
977/559610
977/559608
1.3 Situación
La simulación del presente proyecto se llevara a cabo dentro de las instalaciones del
citado recinto.
6
1.4 Posibles soluciones y solución adoptada
Este proyecto lo podemos dividir en 6 partes principalmente:
1.4.0 - Introducción al concepto de control distribuido y al de bus de campo.
1.4.1 - Estudio del modelo de referencia para redes OSI, y establecimiento de las
necesidades propias a implementar para este proyecto.
1.4.2 - Estudio del medio físico de transmisión a utilizar para las comunicaciones.
1.4.3 - Estudio y diseño de las interfaces para las comunicaciones, con el fin de
adecuar el medio físico seleccionado a los dispositivos existentes en el sistema.
1.4.4 - Estudio de la topología de la red y bus de campo a establecer.
1.4.5 - Comparativa de los diferentes protocolos de bus de campo existentes, y
elección del protocolo a usar.
1.4.6 - Comparativa de los diferentes protocolos de red de área local existentes, y
elección del protocolo a emplear.
1.4.7 - Descripción final de la red a implementar.
7
1.4.0 Introducción
A continuación se hace una introducción a los sistemas distribuidos en la industria,
donde se podrá ver la evolución de estos con el paso del tiempo y algunos de las
aplicaciones mas conocidas en la actualidad.
El Control Distribuido
Antecedentes
Durante muchos años, control distribuido se ha asociado a la distribución de las
funciones de control de proceso en un sistema complejo. Hoy en día se sigue
hablando de control distribuido, pero ahora este concepto es mucho más amplio y
afecta a los actuadores, sensores, elementos de control, bases de datos y estaciones
de supervisión y análisis de datos recogidos, todo ello integrado en un sistema único
interconectado.
Las razones son múltiples. Por una parte, la evolución de la tecnología que ha
comportado la utilización de algoritmos de control más complejos, incluyendo en
algunos casos el control multivariable, control óptimo, control adaptativo o la
inteligencia artificial, por citar algunos de los más importantes. Por otra, se ha
producido un gran desarrollo, estandarización y modularización del hardware de
soporte, junto con un gran aumento de capacidad de tratamiento de datos a bajo
coste, a lo que han contribuido enormemente los autómatas programables y los PC
industriales. Finalmente, la miniaturización a bajo coste posibilitada por el desarrollo
de la microelectrónica ha supuesto una revolución en la instrumentación y actuadores,
que permiten disponer de microcontroladores y de circuitos especializados en el
tratamiento y gestión de las comunicaciones digitales, así como de ASIC específicos.
A todos estos aspectos hay que añadir las necesidades que
la creciente
competitividad crea en las empresas (fabricar series cortas, una amplia gama de
productos con un estricto control de costes, inversiones ajustadas a las necesidades
de cada momento pero abiertas a futuras ampliaciones, etc.), que exigen a los nuevos
sistemas de control disponer de una arquitectura y características que permitan la
necesaria flexibilidad, escalabilidad y gestión de datos de proceso.
En 1959 se puso en marcha el primer sistema de control por ordenador en una
refinería de Texas. En 1964 su uso fue extendiéndose en el control directo de
procesos mediante controladores digitales específicos. Diferentes compañías
químicas, especialmente en USA y UK, fueron aplicando los nuevos equipos de
control. En general, se trataba de sistemas caros, con una puesta en marcha y un
mantenimiento que también lo eran.
En esta época se popularizaron las computadoras IBM 360 y PDP-8 en este tipo de
aplicaciones. Se trataba siempre de un único equipo que centralizaba las funciones
8
de control y supervisión, registrando datos y enviando señales de mando a los
actuadores o consignas a dispositivos de control analógico específicos, siempre
conectados directamente a este equipo central. En los años 70, las empresas
Yokogawa y Honeywell, crearon sistemas con diferentes equipos de proceso. Las
funciones de control empezaban a distribuirse y a jerarquizarse. En 1977 aparecieron
los primeros sistemas de control redundantes. Esta nuevas estructuras ya requerían
la característica básica de los sistemas de control distribuido: la intercomunicación
entre diversos equipos, inicialmente entre controladores y supervisores. Los años 80
se caracterizaron por la aparición de los ordenadores personales de IBM y por un
gran desarrollo de software para aplicaciones de control y supervisión. A mediados de
los 80 aparecieron los transmisores inteligentes, que abrieron la puerta a las
comunicaciones digitales entre equipos. En esta década se popularizó el concepto de
CIM (fabricación asistida por computadora) y la General Motors impulsó el desarrollo
del sistema MAP orientado a la implementación generalizada del CIM.
Respecto a los algoritmos de control, la potencia de las nuevas herramientas posibilitó
el desarrollo de nuevos algoritmos más complejos: control óptimo y control adaptativo,
entre otros. En 1987, Foxboro presentó en el mercado controladores con inteligencia
artificial.
Honeywell ha plasmado las nuevas tendencias relativas a la utilización de sistemas
abiertos y buses de campo estándar tanto en su propuesta denominada Total Plant y
el sistema Total Plant Solution, desarrollado en Windows desde el principio, así como
en la amplia gama de instrumentación que fabrica desde transmisores de presión
inteligentes hasta caudalímetros o interfaces para válvulas ,cumpliendo todos ellos los
estándares de la Fieldbus Foundation.
Por otra parte, un acuerdo con SAP ha hecho que se incorpore como socio de
implementación del famoso R/3 para gestión de la producción de la planta,
confirmando así la otra gran tendencia a la integración de la información de planta con
la de gestión.
Foxboro forma parte también del grupo de empresas que cabe calificar de históricas
en el campo de los sistemas de control distribuido. Aunque, al contrario de Honeywell
o Fisher-Rosemount, no ha presentado hasta ahora una propuesta global alternativa
a sus sistemas, tanto desde el punto de vista de su oferta en instrumentación de
campo como de algunas novedades que presentó en la pasada ISA, no hay duda que
también ha optado claramente por los buses estándar.
En la mayoría de los casos, sus nuevas gamas de instrumentación y sus interfaces
para válvulas son compatibles, además de con FoxCom, con Fieldbus Foundation y
Hart. Por otra parte, en la citada ISA presentaba un nuevo módulo para las
comunicaciones de conexión directa a su sistema de control distribuido ,que
posibilita la conexión directa como un nodo más de la red sin necesidad de
gateway. Delta V es un sistema escalable dirigido, según sus creadores, a monitorizar
aplicaciones de nivel medio (hasta 500 E/S), que puede operar con múltiples
estándares del mercado (Win32, OLE, IEEE, ANSI, etc.) y, por supuesto, soporta
los protocolos Fieldbus Foundation. Delta V, que en la última ISA de Chicago fue una
de las indiscutibles estrellas, es un auténtico sistema integrado que trabaja con una
9
única base de datos, la cual coordina la configuración de todas las actividades. La
declarada opción de la empresa Fisher-Rosemount por la interoperabilidad y los
estándares queda clara si se observa que ha sido uno de los principales propulsores
del protocolo Hard, de Fieldbus Foundation, y, más recientemente, de OPC Process
Control Technology, que impulsó junto con Intellution, Intuitive Technology, Opto-22 y
Rockwell Software para adaptar OLE a las necesidades de las aplicaciones de control
de procesos. Posteriormente se les ha unido Honeywell, Siemens y Toshiba. Por
supuesto, Delta V es compatible con OPC.
Actualidad
En la gran mayoría de casos, hablar de sistemas de control distribuido es hablar de
sistemas de control. Todo sistema de control que supere una mínima complejidad
está constituido por varios elementos: uno o más controladores industriales o
dispositivos de entrada salida, una o más computadoras de supervisión y/o control,
una o más aplicaciones software y un sistema de comunicaciones digitales. Se trata
de sistemas distribuidos tanto por lo que se refiere al reparto de las funciones
específicas de control como a la ubicación de datos y al control de los flujos de
información. Si hacemos un repaso a las características esenciales de estos
elementos, en relación con su aportación a la distribución del control, encontramos
que:
- Las comunicaciones son el elemento clave en dichos sistemas, ya que ponen en
contacto los diferentes elementos físicos que lo constituyen, permiten establecer una
estructura de flujo de información y actúan como integrador.
- Dado que su función es la de interconectar diferentes equipos, si se desea que no
necesariamente todos ellos correspondan a un mismo proveedor, es preciso que
estas comunicaciones respondan a un estándar ampliamente aceptado y reconocido
por los diferentes proveedores.
- El desarrollo e implantación efectiva de estos estándares han sido decisivos en la
evolución de las estructuras de control y de la propia tecnología del software y
hardware de los sistemas de control.
- Dado que la comunicación entre PC supera el ámbito del control industrial y que ya
existen estándares claramente definidos para las redes locales, el estándar específico
para las comunicaciones en las aplicaciones de control industrial, sobre el que
conviene centrar la atención, es el correspondiente al bus de campo que se encarga
de las comunicaciones en planta.
Actualmente existen varios estándares definidos que responden a diferentes
realidades. En algunos casos se trata de estándares desarrollados en diferentes
áreas geográficas (Interbus-S en Europa, Fieldbus en EEUU). En otros casos
responden a desarrollos tipo propietario de alguna empresa o grupo de empresas del
sector con una fuerte implantación que han popularizado su propio estándar, que ha
sido tomado como opción por otros proveedores (por ejemplo el MAP de la General
Motors o el TOP de Boeing). Por otra parte, dentro de los estándares también existen
10
diferencias sobre la base del grado de la complejidad de las aplicaciones para las que
han sido desarrollados (DeviceNet, Profibus, Bitbus).
Así por ejemplo nos encontramos con la norma Fieldbus específica para fábricas para
la interconexión de sensores y el control de procesos, la CAN específica para las
comunicaciones en automóviles y la CEBus para la automatización de hogares
(implementada con cables PLBus (power line bus) que en el futuro derivará en TPBus
CXBus FOBus RFBus o IRBus según el medio empleado para las comunicaciones
(pares trenzados, coaxial, fibra óptica, radio frecuencia o Infrarrojos). De todas
maneras, si se tiene en cuenta el punto de partida inicial, ya se puede empezar a
hablar de un número relativamente reducido de estándares.
Otro elemento característico de los actuales sistemas de control son los dispositivos
de entrada salida diseñados específicamente para trabajar en forma distribuida. Los
dispositivos de entrada/salida incorporan funciones de control y tratamiento de datos y
permiten al usuario final acercar la interfaz de entrada/salida a los sensores y
actuadores, consiguiendo reducir el cableado necesario y facilitar la detección de
fallos y el mantenimiento. El dispositivo de entrada/salida distribuido incluye tres
funciones: adaptador de señal, regla de conexión y tratamiento de comunicaciones.
Entre los dispositivos de entrada se encuentran: DeviceNet, ControlNet, Fieldbus y
Interbus-S.
Con una caracterización específica, se encuentran los que se conocen como
instrumentación inteligente.Se trata de dispositivos de captación de señal que
incluyen una electrónica integrada que realiza funciones de gestión de
comunicaciones, permitiendo la conexión directa a un bus de campo, funciones de
calibración y selección de parámetros de medida (ganancia, offset, rango) y, en
algunos casos, también funciones de almacenamiento de datos. Por citar algunos
ejemplos ,encontramos actualmente en la industria arrancadores y variadores de
velocidad para motores asíncronos ALTIVAR que se comunican con buses de campo
Jbus, Modbus o Interbus, también los convertidores de frecuencia DF4 de Moeller
utilizan buses de campo Inter-bus o Profibus-DP. También encontramos otros
ejemplos en sistemas de alimentación ininterrumpida como los de Merlin Gerin que se
pueden comunicar mediante tarjetas Ethernet para red local (el EX7 o el EX10) o por
bus de campo Jbus o Batibus (Galaxy PW o el COMET serie 11 y 13).
Los PC y los autómatas programables se han consolidado como los dispositivos
estándar para la realización de funciones de control, supervisión y registro de datos,
así como de comunicación, vía
red, con otros dispositivos del sistema. La
utilización de PC conectado en red local permite la distribución de diversas
funciones de supervisión, control y seguridad, así como de distribución y
almacenamiento de datos.
El software de control, a partir de la estandarización de los PC, de sus entornos
operativos y de la interfaz de usuario ha experimentado un gran crecimiento.
11
Actualmente está disponible una amplia oferta de software abierto trabajando bajo
estándares de amplia difusión: Windows, ODBC, enlaces DDE, etc.
Los flujos de información responden a la arquitectura Cliente/Servidor: un dispositivo
requiere un dato determinado y actúa como Cliente, solicitándolo al Servidor que le
proporciona dicha información. Según las diferentes estructuras, los dispositivos se
especializan como Clientes o como Servidores o realizan funciones de Cliente y
funciones de Servidor.
En realidad, la estructuración del flujo de comunicaciones es un punto clave para el
paso de un sistema de control centralizado a uno de control distribuido. Los actuales
sistemas se caracterizan por una integración de las aplicaciones, ubicación distribuida
de los datos y su disponibilidad para diferentes dispositivos mediante una red. La
selección de los datos a manejar y almacenar en
cada estación y de los datos
que deben transmitirse a la estación principal de control, que también puede actuar
como servidor de datos para los Sistemas Empresariales de Información (MIS), así
como asegurar la correcta sincronización de los
mismos, son aspectos básicos
para que la estructuración del flujo de las comunicaciones sea correcta.
Tendencias
Las tendencias que marcan el futuro inmediato en los sistemas de control se centran
en:
- Disminución de cableado y de hardware utilizando un único estándar de bus de
campo o un conjunto de buses de campo, orientados a diferentes grados de
complejidad del dispositivo, según el nivel de funcionalidad soportado, pero
manteniendo una compatibilidad en sentido ascendente, lo que posibilita la
escalabilidad del sistema.
- Avance en el desarrollo de sistemas abiertos, permitiendo la intercambiabilidad de
elementos: estaciones de supervisión, dispositivos de control, sensores y actuadores
y red de comunicaciones.
- Selección de la topología y el protocolo de red para integrar procesadores y
dispositivos de entrada/salida.
- Simplificación de los procesos de incorporación de nuevos módulos o dispositivos al
sistema de control, como el sistema Delta V de la empresa Fisher-Rosemount. El
objetivo es similar a las capacidades plug & play popularizadas en el ámbito de los
PCs: se trata de permitir la fácil y rápida expansión del sistema mediante la adición
de módulos de software o hardware, con capacidad para reconocer y configurar los
dispositivos y aplicaciones en el momento de su instalación en el sistema.
- La mejora de la escalabilidad, que junto a la utilización de sistemas abiertos
garantiza la máxima protección de la inversión. En cada momento, de acuerdo con las
necesidades presentes, se utilizan los elementos con la capacidad y potencia
requeridos para las funciones de control y supervisión.
12
Cuando, por necesidades de mantenimiento o por la evolución de las condiciones de
entorno, se requiere el uso de dispositivos más potentes, podemos hacerlo con
facilidad sustituyendo el elemento preciso por uno más potente, pero aprovechando el
resto del sistema, sin tener que efectuar necesariamente su reconfiguración.
Los buses de Campo
Los buses de campo son una forma especial de red de área local dedicados a
aplicaciones en el campo de adquisición de datos y el control de sensores y
actuadores en maquinas o en plantas industriales.
Dichos buses operan en un par trenzado de cables de bajo coste. Al contrario que
redes tradicionales como Ethernet, donde el rendimiento se mide en la eficiencia
(troughput) cuando se transmiten grandes bloques de datos, los buses de campo
están optimizados para el cambio de mensajes cortos sobre el estado y ordenes
punto a punto.
Esquema de una red local MODBUS PLUS conectada a otra red basada en el IEEE
802
que se comunica a su vez con buses de campo basados en el protocolo MODBUS.
13
Información técnica especifica de los buses de campo
Los buses de campo son tecnologías de la comunicación y productos usados en
automatización y control de
procesos en la industria. Se puede distinguir entre
buses de campo propietarios y abiertos. Los primeros pertenecen a la propiedad
intelectual de una compañía particular. Para poder emplear estos se necesita una
licencia, aunque solo se conceden unos derechos parciales sobre el bus, en general
son caras. Los segundos son lo contrario al anterior, ya que para ser considerados
buses de campo abiertos han de cumplir con el siguiente criterio: Todas las
especificaciones de estos han de ser publicadas y disponibles a un precio razonable,
los componentes críticos también han de estar disponibles a precios justos ,ser
abiertos a todos los usuarios de buses de campo y tener una validación del proceso
bien definida. Un bus de campo abierto debe permitir lo siguiente:
- Interconectividad Dispositivos de diferentes fabricantes pueden ser conectados al
mismo bus de campo sin tener complicaciones.
- Interoperabilidad La habilidad de poder conectar elementos de diversos
proveedores.
- Intercambiabilidad Dispositivos de un fabricante pueden ser reemplazados con
equipos equivalentes de otro fabricante.
Las ventajas de utilizar los buses de campo son:
- Reducen la complejidad del sistema de control en términos de tirada de cable.
- Existe una reducción en los requerimientos de la maquinaria de los PLCs o DCS.
Reduciendo el número de armarios para instalar el equipo asociado a la conexión de
la maquinaria. Al reducir el cableado se reduce la necesidad de cajas de conexiones,
el personal y el numero de horas empleadas en la instalación. Todo ello repercute en
el coste final de las instalaciones.
- Los diagnósticos de fallos en el bus son más fáciles de realizar.
- Reduce la complejidad del sistema de control ya que lo hace mas eficiente y menos
costoso.
14
- Las modificaciones o mejoras son llevados a cabo de manera menos complicada.
- Los tiempos de parada en la producción por fallos en el proceso son reducidos por
el grado elevado de detección y diagnostico de errores.
Las tecnologías en que se basan los buses de campos son:
-
RS-232
RS-485
CAN
ARCNET
IEC 1158-2
BITBUS (IEEE 1118)
Otras tecnologías:
-
ModBus
HART
Conitel
DF1
Data Highway
Sistemas de buses de campo establecidos:
-
ModBus Plus
ISP SP-50
SINEC
DNP3
PROFIBUS FMS
P-NET
Allen-Bradley
Remote IO
PROFIBUS PA
LonWorks
FOUNDATION Fieldbus
AS-I
IEC 870-5
SERCOS
InterBus
- PROFIBUS DP
- FIPIO
- Omron Sysmac Bus
- CAN Open
- EIB
- DeviceNet
-
CAN Kingdom
CEBus
WorldFIP
FIP
IEEE-P1451.2
Smart Distributed Systems
SERIPLEX
15
La especificación de un bus de campo idealmente debería cubrir todas las 7 capas
del modelo de referencia OSI. A continuación se describen de manera escueta las
principales características de cada capa, que se verán mas a fondo en páginas
posteriores.
- Capa o nivel FÍSICO [1] Define que tipo de señales son presentes, niveles de
tensión, representación de unos y ceros ,el tipo de medio físico empleado,
conexiones, etc.
- Capa de ENLACE [2] Define la técnicas para establecer enlaces entre dos partes
que se estén comunicando.
- Capa de RED [3] Método de selección del nodo de interés y de enrutamiento de los
datos.
- Capa de TRANSPORTE [4] Se asegura de que lo que se envió se reciba
correctamente y de corregir los problemas que se pudieran dar.
- Capa de SESIÓN [5] No aplicable a los buses de campo.
- Capa de PRESENTACIÓN [6] No aplicable a los buses de campo.
- Capa de APLICACIÓN [7] Tiene en cuenta el significado de los datos
El mejor camino para cubrir las 7 capas es definir unos perfiles estándares para
equipos estándar. Por ejemplo definir los parámetros de los equipos, el formato de
dichos parámetros y el tiempo de ejecución de estos. Si el bus de campo y los
dispositivos de entrada/salida asociados definen un estándar de perfil, los dispositivos
de entrada/salida pueden ser reemplazados por equipos que funcionalmente sean
iguales.
Actualmente la IEC (Comité Electrotécnico Internacional) trabaja en un bus de campo
estándar internacional ,el SP50 que consta de 4 capas (PL,LL,AL,UL) conocido como
ISA SP50.02/IEC 1158-2.Su objetivo es de el poder comunicar diferentes tipos de
equipos conectados a un mismo medio físico.
16
1.4.1 Modelo de referencia OSI
La necesidad de intercambiar información entre sistemas con distintas tecnologías
llevó a la ISO (International Standar Organization) a buscar la manera de regular este.
El modelo de referencia OSI (Open Systems Interconnection) para redes surgió en
1983 y es el resultado el trabajo de ISO para la estandarización internacional de los
protocolos de comunicación.
Dentro del modelo de referencia OSI se establecen tres niveles de abstracción:
- La arquitectura OSI ,define los elementos básicos de los sistemas abiertos
abstractos (de que manera ha de verse un sistema desde el exterior).
- Las especificaciones de servicio OSI ,definen los servicios proporcionados a los
usuarios en cada nivel.
- Las especificaciones de protocolos OSI ,definen la información de control
transmitida entre los distintos sistemas ,así como los procedimientos para la
interpretación de dicha información de control.
El modelo de referencia OSI es un modelo de redes estructuradas en capas o niveles.
El objetivo es tratar de manera estructurada la totalidad de un sistema teleinformático.
El conjunto de funciones del sistema se divide en niveles ,que sean fácilmente
controlables
de forma individual y que en conjunto resuelvan las necesidades de comunicación.
17
Cada nivel se desarrolla sobre el anterior ,de forma tal que recibe una serie de
servicios sin conocer los detalles de como se realizan dichos servicios. Las diferentes
funciones de la arquitectura OSI han sido estructuradas en 7 niveles ,siendo las
funciones asignadas a cada uno de ellos complementarias. A continuación se detallan
cada una de las 7 capas de que consta:
Las capas 1,2 y 3 están orientadas a las comunicaciones, las capas 4,5 y 6 están
orientadas al sistema y la capa 7 esta orientada a la aplicación.
Capa Física Se encarga de activar ,mantener y desactivar un circuito físico.
Responsable de la definición de las variables mecánicas ,eléctricas y funcionales de
la transmisión y recepción de la información utilizando un medio de comunicación
específico.
Sus funciones básicas son: identificación de los circuitos de datos, secuenciamiento
de los mismos y la gestión del propio nivel. Se ocupa de la transmisión de bits a lo
largo de un canal de comunicación. Su diseño debe asegurar que cuando un extremo
envía un bit con valor 1, éste se reciba exactamente como un bit con ese valor en el
otro extremo, de cuántos microsegundos deberá durar un bit, la posibilidad de realizar
transmisiones en forma simultánea bidireccionales, la forma de establecer la conexión
inicial y cómo interrumpirla cuando ambos extremos terminan su comunicación o bien
cuántas puntas terminales tiene el conector de la red y cuál es el uso de cada una de
ellas. Los problemas de diseño a considerar son los aspectos mecánico, eléctrico ,de
procedimiento de interfaces y el medio de transmisión física, que se encuentra bajo la
capa física.
Capa de Enlace En una red de múltiple acceso, un subnivel (el subnivel de acceso
medio, o medium access sublayer) controla el acceso al canal compartido.
Responsable de mantener la integridad de los datos de una transmisión sobre un
canal de comunicaciones.
Proporciona un canal flexible para la transmisión de datos sobre un medio físico.
Entre sus funciones están las de detectar y corregir errores de transmisión que
ocurran en el medio físico. Proporciona los elementos necesarios para establecer
,mantener y terminar interconexiones de enlace de datos entre este nivel y el nivel de
red.
Los protocolos del nivel de enlace definen la forma de establecimiento y liberación de
un enlace de datos, controlan la correcta transferencia de información y recuperación
de anomalías, así como la gestión del propio nivel. Su tarea principal consiste en a
partir de un medio de transmisión ,transformarlo en una línea sin errores de
transmisión para la capa de red. Esta tarea la realiza al hacer que el emisor trocee la
entrada de datos en tramas de datos, y las transmita en forma secuencial y procese
las tramas de asentimiento, devueltas por el receptor. Como la capa física acepta y
transmite un flujo de bits sin tener en cuenta su significado o estructura, recae sobre
la capa de enlace la creación o reconocimiento de los límites de la trama. Esto puede
hacerse mediante la inclusión de un patrón de bit especial al inicio y término de la
trama. Si estos patrones de bit pueden parecerse a los datos ,habrá que evitar
18
confusiones.
La trama puede destruirse por completo debido a una ráfaga de ruido en la línea, en
cuyo caso el software de la capa de enlace ,perteneciente a la máquina emisora,
deberá entonces retransmitir la trama. Sin embargo múltiples transmisiones de la
misma trama introducen la posibilidad de duplicar la misma. Corresponde a esta capa
resolver los problemas causados por daño ,pérdida o duplicidad de tramas.
Otro de los problemas que ha de resolver es que el emisor sea más rápido que el
receptor y saturé a este de datos; por esto los procedimientos de control de flujo y
errores se tratan en forma conjunta. También aparecen problemas cuando la línea
tiene la capacidad de utilizarse para transmitir datos de forma bidireccional y los
reconocimientos de una unidad a otra compite por el uso de la línea con las tramas
de datos.
Capa de Red Determina el ruteo de los paquetes desde sus fuentes a sus destinos,
manejando la congestión a la vez. Se incorpora la función de contabilidad.
Responsable de asegurar que la información se transmite correctamente a través de
la red. Proporciona a las entidades del nivel de transporte una transferencia de datos
transparente. Libera al nivel de transporte de la necesidad de conocer los
mecanismos de transmisión de datos o tecnologías utilizadas para conectar sistemas.
Tiene las funciones de conexión y desconexión de las redes, sincronización y control
del flujo de las transferencias, la detección de errores en la transmisión
recuperándolos en caso necesario, también se encarga del encaminamiento entre
redes.
Se ocupa del control de la operación de la subred. Un punto a destacar en su diseño
,es la determinación sobre cómo encaminar los paquetes de origen al destino. Las
rutas podrían basarse en tablas estáticas que se encuentran "cableadas" en la red y
que difícilmente podrían cambiarse.
También podrían determinarse al inicio de cada conversación, por ejemplo en una
sesión de terminal. Por último, podrían ser de tipo dinámico, determinándose en
forma diferente para cada paquete, reflejando la carga real de la red. El control de la
congestión de la red depende de la capa de red. El software deberá saber cuántos
paquetes o caracteres o bits se enviaron a cada cliente, con objeto de producir
información de facturación. Además los problemas de interconexión de redes
heterogéneas recae en esta capa.
Capa de Transporte Es el primer nivel que se comunica directamente con su par en
el destino (los de abajo son
de máquina a máquina). Provee hasta 3 tipos de
servicio:
- Orientados a la conexión.
- Orientados a la difusión de información a muchos usuarios.
19
- Orientados a la realización de transacciones.
Permite establecer múltiples conexiones de red para proveer una alta capacidad. Se
puede usar el encabezamiento de transporte para distinguir entre los mensajes de
conexiones múltiples entrando en una máquina. Provee el control de flujo entre
anfitriones (host).
Su objetivo es proporcionar un mecanismo fiable para el intercambio de datos entre
procesos en diferentes sistemas. Independiza al nivel de sesión y niveles superiores
de los elementos que constituyen la red. El nivel de transporte pasa los datos, del
nivel de sesión
al de red, pero antes los fragmenta en unidades más pequeñas y
asegurando que todos llegan correctos a su destino. También proporciona distintos
niveles de calidad de servicio.
Su función consiste en aceptar los datos de la capa de sesión, dividirlos en unidades
pequeñas, pasarlos a la capa de red y asegurarse que todos lleguen correctos al otro
extremo. Esta capa crea una conexión de red distinta para cada conexión de
transporte solicitada por la capa de sesión. Si la conexión de transporte necesita un
gran caudal, ésta podría crear múltiples conexiones de red, dividiendo los datos entre
las conexiones de la red para mejorar dicho caudal. Para reducir el costo de la
creación o mantenimiento de la conexión de una red esta capa podría multiplexar
varias conexiones de transporte sobre la misma conexión de red. La capa de
transporte determina qué tipo de servicio debe dar a la capa de sesión y a los
usuarios de la red. El
tipo más popular de conexión de transporte corresponde al canal punto a punto sin
error. Otra posibilidad es el transporte de mensajes a destinos múltiples. El tipo de
servicio se determina cuando se establece la conexión. Además de multiplexar varios
flujos de mensaje en un canal ,la capa de transporte debe ocuparse del
establecimiento
y liberación de conexiones a través de la red.
Capa de Sesión Parecido al nivel de transporte, pero provee servicios adicionales.
Por ejemplo, puede manejar tokens (objetos abstractos y únicos) para controlar las
acciones de participantes o puede hacer checkpoints (puntos de recuerdo) en las
transferencias de datos.
Proporciona los medios necesarios para controlar el diálogo entre entidades de
presentación ,ese diálogo se realiza a través el establecimiento y uso de una
conexión llamada sesión. Los servicios que proporciona son: establecimiento y
liberación de la conexión de sesión ,intercambio de datos ,sincronización y
mantenimiento de la sesión.
Permite a los usuarios de diferentes máquinas establecer sesiones entre ellos. A
través de una sesión se puede llevar a cabo un transporte de datos ,como la de
transporte pero mejorando los servicios que proporciona ésta. Uno de los servicios de
la capa e sesión consiste en gestionar el control del diálogo. Las sesiones permiten
que el tráfico vaya en ambas direcciones al mismo tiempo o en una sola.
20
La administración del testigo es otro de los servicios relacionados con ésta capa,
además de la sincronización de procesos.
Capa de Presentación Se encarga de la transferencia de los datos ,intervienen la
sintaxis de éstos.
Los procesos de aplicación adquieren independencia de la representación de los
datos, e incluyen las posibles transformaciones de códigos (compresión, cifrado
,terminal virtual, etc.).
El trabajo de manejar estructuras abstractas y la conversión de la representación
utilizada en el interior del ordenador a la representación normal de la red, se lleva a
cabo en ésta capa. También está relacionada con otros aspectos de representación
de la información como la compresión de datos o criptografia.
Contiene una variedad de protocolos que se necesitan
Capa de Aplicación
comúnmente. Se encarga por ejemplo de
definir terminales virtuales, con objeto
de transferirlos de una red a un terminal real. También se encarga de la transferencia
de archivos. El correo electrónico, el trabajo a distancia y el servicio de directorio son
otros
de los servicios que corresponden a esta aplicación. El trabajo de manejar estructuras
de datos abstractas y la conversión de la representación utilizada en el interior del
ordenador a la representación normal de la red ,se lleva a cabo en esta capa.
1.4.1.1 Ejemplo de utilización del modelo OSI
21
1.4.1.2 Aplicación
Para conectar los equipos de campo con un ordenador central de control en una
planta industrial ,es suficiente con las capas 1 y 2 de OSI y un protocolo de aplicación.
Si dicho ordenador ha de comunicarse con el exterior de la planta entonces si será
necesario el uso de la capa 3. En control distribuido diferentes unidades de proceso
están dedicadas al control de una parte del proceso físico, una unidad central es la
que se encarga de coordinar las operaciones generales. Según el tipo de planta o
proceso puede existir un control de la producción, controlado a su vez por una
dirección, tal y como se detalla en el siguiente esquema:
22
1.4.1.3 Terminología OSI
Entidades o unidades funcionales se denominan así a los elementos activos que
se encuentran en cada una de
las capas. Por ejemplo un proceso informático o un
chip inteligente de E/S. Las entidades de la misma capa pero de diferentes maquinas
se las denomina entidades pares o iguales. Así por ejemplo a las entidades de la
capa 7 se las conoce como entidades de aplicación. Las entidades de la capa N
(proveedor del servicio) desarrollan un servicio que utiliza la capa N+1
(usuario del servicio).Los servicios se encuentran disponibles en los SAP (puntos
de acceso al servicio).Para que exista un intercambio de información entre dos
capas debe existir un acuerdo sobre un conjunto de reglas acerca de la interfaz.
Los servicios proporcionados a través de la
interfaz de dos niveles adyacentes se expresan en términos de primitivas y
parámetros. Una primitiva especifica la función a realizar y los parámetros se utilizan
para transferir información de datos y control. En una interfaz típica ,la entidad de la
capa (N+1) pasa una IDU (unidad de datos de la interface) a la entidad de la capa
N ,a través del SAP. El IDU consiste en una SDU (unidad de datos del servicio) y
de alguna información de control. La SDU es la información que se pasa a través de
la red ,a la entidad par N y posteriormente a la capa N+1. La información de control es
necesaria para que las capas inferiores realicen su trabajo ,pero no forma parte de los
datos.
Para hacer la transferencia de una SDU ,puede ser necesario su fragmentación por
parte de la entidad de la capa N en
varias partes, de tal forma que a cada una
de ellas se le asigne una cabecera y se envíe como una PDU (unidad de datos de
protocolo).Las entidades pares utilizan la cabecera para llevar a cabo su protocolo
igual a igual. Por medio de ellos se identifica cuales son las PDU que contienen datos
y cuales las que llevan información de control, etc.
Protocolo es el conjunto de reglas que controlan el intercambio de información entre
unidades funcionales del mismo nivel tanto en la transmisión como en el control y
recuperación de errores.
Tipos de servicios: (Cada servicio se caracteriza por la calidad del servicio.)
Servicio orientado a conexión El usuario del servicio establece primero una
conexión, la utiliza y
luego termina la conexión.
Servicio sin conexión (servicio datagrama) El usuario del servicio envía un mensaje
23
con la dirección del destinatario sin establecer ninguna conexión con este.
Cuando se desea transmitir un mensaje pequeño pero que interesa que el proceso
sea fiable se emplea el servicio de datagramas con asentimiento similar al envío de
correo certificado. Otro servicio alternativo es el de respuesta pregunta en el cual se
envía un mensaje corto y le envían una respuesta.
Servicio
Ejemplo
Servicio
Orientado a
conexión
Flujo de mensaje fiable
Flujo de octetos fiable
Conexión no fiable
Secuencia de pag.
Conexión remota
Voz digitalizada
Servicio
Sin conexión
Datagrama no fiable
Datagrama con asentimiento
Pregunta - Respuesta
correo electrónico
correo certificado
búsqueda en base
datos
de
Un servicio esta formalmente especificado por un conjunto de primitivas
(operaciones), a disposición de todos los usuarios o de otras entidades para acceder
al servicio. Estas primitivas le indican al servicio que debe efectuar una acción o
notifican la acción tomada por una entidad par.
Las primitivas de servicio en el modelo OSI se pueden dividir en 4 clases:
Solicitud
Una entidad desea que el servicio realice un trabajo
Indicación
Una entidad es informada acerca de un evento
Respuesta
Una entidad desea responder a un evento
Confirmación
Una entidad va a ser informada acerca de
su solicitud
Los servicios pueden ser o no confirmados ,en el primer caso existe una petición, una
indicación ,una respuesta y
una confirmación; mientras que en el segundo caso
solo hay una petición y una indicación.
Para tener una idea clara del concepto de servicio, a continuación se expone un
pequeño ejemplo.
Se tiene un servicio orientado a conexión ,con 8
24
primitivas de servicio definidas
así:
CONNECT.request Solicitud para establecer una conexión.
CONNECT.indication Aviso de llamada a la entidad solicitada.
CONNECT.response Utilizada para aceptar/rechazar llamadas.
CONNECT.confirm Notifica que la llamada fue aceptada.
DATA.request Solicitud para que se envíen los datos.
DATA.indication Aviso de llegada de datos.
DISCONNECT.request Solicitud para liberar la conexión.
DISCONNECT.indication Aviso de solicitud de desconexión.
El servicio CONNECT es un servicio confirmado y el servicio DISCONNECT es un
servicio sin confirmar.
Se puede hacer una analogía con el sistema telefónico,
manera de emplear estas primitivas.
para
1 CONNECT.request Marca el numero de teléfono.
2 CONNECT.indication Escucha los tonos de llamada.
3 CONNECT.response Descuelgan el teléfono.
4 CONNECT.confirm Escucha que terminaron los tonos.
5 DATA.request Pregunta al otro interlocutor.
6 DATA.indication El interlocutor escucha la pregunta.
7 DATA.request El interlocutor responde.
8 DATA.indication Escucha la respuesta
9 DISCONNECT.request Cuelga el teléfono
10 DISCONNECT.indication El interlocutor oye el tono de la línea.
25
observar
la
1.4.2 Medio de transmisión
Estándares RS485, RS422, RS232 y RS423
Introducción
Los transmisores y receptores son comúnmente empleados para intercambiar datos
entre dos o mas puntos (nodos) en una red. Las comunicaciones son difíciles de
llevarse a cabo con la presencia de ruidos inducidos, diferencias de nivel de masa,
adaptación incorrecta de impedancias y otros daños asociados con la instalación de
una red.
La conexión entre dos o mas elementos se considera una línea de transmisión si el
tiempo de subida y/o de bajada de la señal es superior a la mitad del tiempo que tarda
la señal para viajar desde el transmisor al receptor. Los estándares se han
desarrollado para asegurar la compatibilidad entre unidades suministradas por
diferentes fabricantes y para permitir transferencias correctas de datos a unas
determinadas distancias y velocidades.
La EIA (Electronics Industry Association) ha desarrollado estándares para RS485,
RS422, RS232 y RS423, que tratan con comunicaciones de datos. Estos estándares
previamente se les reconocía como "RS" para indicar que eran los estándares
recomendados, en la actualidad se les denomina estándares EIA.
Las comunicaciones de datos entre elementos se pueden agrupar en dos categorías:
- Transmisiones en modo principio - fin.
- Transmisiones en modo diferencial.
Transmisiones en modo Principio - Fin (punto a punto)
RS232 Fue introducida en 1962 por la EIA (Electronic Industries Association) y ha
sido ampliamente usada en la industria. Esta especificación permite la transmisión de
26
datos de un a unas velocidades de transmisión relativamente bajas (hasta 20Kbits/s)
y distancias cortas (hasta 15 m a la máxima velocidad permitida).Varios canales se
establecen de manera independiente para una comunicación full-duplex (en ambos
sentidos). Las señales RS232 son representadas por un nivel de tensión con respecto
a un común del sistema(masa del sistema).
El estado inactivo(marca) tiene el nivel de señal negativo con respecto al común y el
estado activo (espacio) está representado por un nivel positivo respecto al común.
La RS232 tiene numerosas líneas para establecer un entendimiento entre dispositivos
y también especifica un protocolo de comunicación. Para que estas líneas no den
problemas al no usarse los módems, se han de inhabilitar por programa o de manera
física con resistencias "pull-up" conectadas a la alimentación o en forma de lazo
cerrado. La línea RTS (Request to send) tiene algunas utilidades en ciertas
aplicaciones.
La RS423 es otra especificación en modo principio - fin, pero su uso no ha sido tan
extenso en la industria como el anterior.
Transmisiones en modo Diferencial
Cuando las comunicaciones se realizan a altas velocidades o a través de largas
distancias para aplicaciones reales el anterior método resulta ineficaz. Las
transmisiones en modo Diferencial (señales en modo diferencial balanceadas o
equilibradas) ofrecen mayores posibilidades. Las señales balanceadas pueden
ayudar a anular los efectos del offset y señales de ruido inducido que pueden
aparecer como tensiones de modo común en la red. Los datos manejados se
codifican y decodifican en forma de voltaje diferencial entre dos conductores ( Si Va Vb es < -0'2V, corresponde al '0' lógico ,mientras que si es > +0'2 V, corresponde al '1'
lógico).El rango de voltaje es modo común soportable va de -7 a +12 V.
RS422 (modo diferencial) fue diseñado para grandes distancias (hasta 1200 m ) y
altas velocidades de transmisión (hasta 100 Kbits/s). RS422 esta especificada para
aplicaciones multipunto donde solo existe un emisor activo y hasta 10 receptores en
el bus. Aunque las aplicaciones tipo multiusuario tienen muchas ventajas deseables,
los dispositivos RS422 no pueden ser usados para construir una red realmente
multipunto; ya que ello implicaría la existencia de múltiples emisores y receptores
conectados en un único bus, donde cada nodo puede transmitir o recibir datos. Las
redes casi multipunto, constan de un bus a 4 hilos con dispositivos RS422. Estas
redes son usadas en modo half_duplex (un único dispositivo maestro o anfitrión envía
comandos a uno de los dispositivos esclavo de la red).Usualmente un dispositivo
(nodo) es direccionado por la computadora huésped y esta recibe la respuesta de
este. Se suelen construir así las redes para evitar el problema de las colisiones de
datos (bus contention) que se originan en configuraciones multipunto.
RS485 cuenta con los requerimientos anteriormente citados para las comunicaciones
multipunto.El estándar especifica hasta 32 emisores y 32 receptores en un único bus
de 2 hilos. Con la introducción de repetidores automáticos y emisores/receptores en
27
alta impedancia esta limitación puede extenderse a cientos o miles de nodos en una
red. La especificación RS485 extiende el rango de modo común para emisores y
receptores en el modo tri-estado y con la alimentación apagada. También los
emisores son capaces de tratar las colisiones de datos y problemas en el bus. Para
resolver los primeros las unidades físicas (como convertidores, repetidores, controles
de los microprocesadores) han de soportar permanecer en un modo de recepción
hasta que son capaces de transmitir datos de nuevo.
En sistemas basados en la filosofía maestro - esclavo, el maestro o anfitrión inicia la
comunicación preguntando al nodo esclavo direccionando dicha unidad. El soporte
físico detecta el bit de comienzo de la transmisión y automáticamente habilita el
transmisor RS485. Una vez que el carácter se ha enviado pasa de nuevo al modo
recepción. Cuando una unidad esclava sea direccionada estará habilitada entonces
para responder inmediatamente.
A continuación está representada una tabla con las especificaciones para RS232,
RS423, RS422 y RS485.
Especificaciones
RS232
RS423
RS422
RS485
Modos de operación
Principio-Fin
Principio-Fin
Diferencial
Diferencial
Numero total en una
receptores y emisores
línea
de 1 emisor
1 emisor
1 emisor
1 emisor
1 receptor
10 receptores
10 receptores
32 receptores
Máxima distancia de cable
en (m)
15
1200
1200
1200
Velocidad máxima de transmisión de
datos
en Kbits/s
20
100
10000
10000
Voltaje máximo de salida del emisor
+/-25 V
+/-25V
-0.25V a +6V
-7V a +12V
28
Nivel de señal de salida del emisor +/-5V a +/-15V
con carga mínima
+/-3.6V
+/-2.0V
+/-1.5V
Nivel de señal de salida del emisor +/-25V
sin carga
+/-6V
+/-6V
+/-6V
Impedancia de carga del emisor 3000 a 7000
en Ω 1
>=450
100
54
Especificaciones
RS232
RS423
RS422
RS485
Máximo Slew Rate
30V/uS
Ajustable
N/A
N/A
Corriente máxima del emisor
en estado de alta impedancia con la
alimentación encendida
N/A
N/A
N/A
+/-100uA
con la alimentación apagada
+/-6mA
+/-100μA
+/-100μA
+/-100μA
Rango de voltaje de entrada del +/-15V
receptor
+/-12V
-10V a +10V
-7V a +12V
Sensibilidad de entrada del
receptor
29
+/-3V
+/-200mV
+/-200mV
+/-200mV
Resistencia de entrada del
receptor en Ω 2
3000 a 7000
4000 min.
4000 min.
>=12000
Para la creación de nuestra red local y el bus de campo se utilizaran cables de pares
trenzados ,consiguiendo así una mayor distancia de las comunicaciones. Para una
mayor seguridad en las transmisiones (evitando interferencias) estos cables irán
apantallados.
Las comunicaciones entre DTEs (formados PCs Workstations y Front-Ends) y DCEs
(formadas por las tarjetas convertidoras de RS232 a RS485) seguirán las
especificaciones RS232 ,y sólo entre DCEs (tarjetas convertidoras) seguirán las
especificaciones RS485, a nivel de red local. Mientras que a nivel de bus de campo
las comunicaciones entre los procesadores locales serán basadas en las
especificaciones RS485.
Estándar RS232, conectores
DB-25
Denominado así por el numero de pines ,25 en total. Este tipo de esta
conector descrito en la original especificación de la RS232. Está compuesto por un
cuerpo que puede o no incluir los pines y una cubierta que puede ser de plástico o de
metal. Las cubiertas de metal esta recomendada en aplicaciones que presenten una
gran sensibilidad a las interferencias. De acuerdo con el estándar los conectores
macho están en los equipos de comunicación de datos ,mientras que los conectores
hembra se encuentran en los equipos terminales de datos. Este conector es el
adecuado a emplear en transmisiones síncronas.
DB-9
Este tipo de conector consta de 9 pines y fue desarrollado por IBM para sus
comunicaciones asíncronas en sus ordenadores personales de clase XT. Con solo
tres hilos (recepción, transmisión y masa común) se puede establecer una
comunicación punto a punto asíncrona. Al no incluir señales de reloj no puede ser
utilizado para comunicaciones síncronas. Añadido posteriormente en el documento
EIA/TIA574.
30
A continuación se detalla una lista con cada pin y las correspondencias entre estos
conectores.
Descripción
Detector portadora
DCD
Pin DB-25 nº
Pin DB-9 nº
8
1
Datos recibidos
RD
3
2
Datos enviados
TD
2
3
DTE encendido
DTR
20
4
7
5
DSR
6
6
RTS
4
7
5
8
Tierra de señal
DCE encendido
Pregunta para enviar
SG
Preparado para enviar
CTS
9 (*)
Tierra de chasis
FG
1
alimentación positiva
9
alimentación negativa
10
11 (*)
Detector de portadora secundario
12
Preparado para enviar secundario
13
Datos transmitidos secundario
14
31
Descripción
Reloj del transmisor
Pin DB-25 nº
TC
15
Datos recibidos secundario
Reloj del receptor
16
RC
17
No asignado
18
Pregunta para enviar secundaria
19
Detector de calidad de la señal
Indicador de timbre
SQ
RI
21
22
Selector de velocidad de los datos SR
23
Reloj del transmisor
24
25 (*)
(*) indica que dichos pines no son usados
Estándar RS232, conexiones
Cuando conectemos un DTE con un DCE el cableado se realiza conectando cada pin
con su homónimo. A este tipo de cable se le conoce como cable modem. Si
conectásemos dos DTEs entre si ,deberemos cruzar los cables de recepción y
transmisión de cada uno ,así el transmisor del primero se conecta con el receptor del
segundo , mientras que el emisor de este se conecta al receptor del primero. A este
cable se le denomina cable de módem nulo.
Estándar RS232, características eléctricas
Utiliza como se menciono anteriormente lógica bipolar negativa. Voltajes entre -25 y
-3 V respecto a tierra representan un '1' lógico, mientras que voltajes entre +3 y +25 V
se consideran un '0' lógico. El rango entre +3 y -3 V se considera una región de
transición donde el estado de la señal es indefinido ,se busca así una mayor
discriminación de interferencias en la señal.
Actualmente los rangos de voltaje se han visto reducidos, así entre -14 y -8 V
tenemos una señal '1' lógica y entre 8 y 14 V se considera un '0' lógico. De todas
formas hay que tener en cuenta que estos márgenes de tensión se ven reducidos
cuando se conectan el emisor y el receptor.
El generador está diseñado para soportar la condición de circuito abierto ,o
cortocircuito entre cualquiera de las señales ,incluyendo la señal de tierra ,sin sufrir
daños o causarlos a los circuitos asociados. Lo que da mayor garantía de seguridad
en caso de conexión errónea.
32
Estándar RS232, tiempo de las señales
Las velocidades de transmisión están restringidas por esta especificación a 20 Kbits/s
,y la longitud de la línea a 15 m. Estas restricciones vienen por el empleo de cables
gruesos cuya capacitancia era alta. Actualmente el RS232 es adecuado para trabajar
hasta 200 Kbits/s.
La mayoría de los puertos serie RS232 de los ordenadores personales son capaces
de trabajar a velocidades mayores de 19'2 KBits/s. Usualmente pueden trabajar libres
de
errores a 56 Kbits/s.
Esta especificación establece que los cambios de nivel de '1' a '0' lógico o viceversa
deben cumplir:
1- Las señales que entren en la región de transición durante un cambio de transición
pueden moverse hacia el estado opuesto de señal sin inversiones de la dirección.
2- Para señales de control el tiempo que se emplee para atravesar dicha zona de
transición a de ser de menos de 1 ms.
3- La pendiente de los flancos de subida o bajada de una transición no debe exceder
de 30 V/μs.
4- Para señales de datos y de reloj ,el tiempo necesario para pasar de un nivel lógico
'1' a '0' o al revés debe ser:
- Menor de 1 ms para períodos de bit mayores de 25 ms
- El 4% del período de bit para períodos de bit entre 25 ms y 125 μs.
- Menor de 5 μs para períodos de bit menores de 125 μs.
Estándar RS232, definición de las señales
Las funciones de las señales se dividen en 6 tipos:
Señal de tierra y protección Tenemos el pin 1 y el pin 7 ,a menudo conectados
ambos a la malla del cable. Todas las señales van referenciadas a un común definido
por el voltaje del pin 7. La tierra del DCE puede o no ir conectado a este ultimo.
Canal de comunicaciones primario Se emplea para el intercambio de datos ,además
del control de flujo de datos. Encontramos los pines 2,3,4 y 5. El pin 2 se activa al
transmitir datos desde el DTE al DCE. Si no se transmiten datos la señal se encuentra
a un nivel '1' lógico. El pin 3 se activa al recibir datos el DTE desde el DCE. Si no se
reciben datos la señal se encuentra a un nivel '1' lógico. El pin 4 sirve para preparar
al DCE para aceptar datos transmitidos desde al DTE, se activa a un nivel lógico '0'.
Activa los circuitos de recepción o configura la dirección de las comunicaciones. El pin
5 se activa a un nivel lógico '0' por el DCE para informar al DTE que la transmisión
33
puede comenzar.
Canal de comunicaciones secundario Si se emplea es para el control del módem
remoto ,peticiones de retransmisión cuando existen errores en el intercambio de datos
y gobierno de la configuración del canal primario. Encontramos los pines 13,14,16 y
19 , los cuales son equivalentes a los del canal primario. Actualmente ya casi no se
implementan.
Estado y control de módem Indican el estado del módem y proporcionan chequeos
intermedios. Encontramos los pines 6,20,8,12,22 y 23. El pin 6 se activa a un nivel
lógico '0' cuando un módem: -Esta conectado a una línea telefónica. -Se encuentra en
modo datos. -Ha completado las funciones de llamada y esta generando un tono de
respuesta. Si la señal se activa por otro equipo indica que este esta dispuesto para
funcionar. El pin 20 es activado por el DTE a un nivel lógico '0' cuando desea
establecer comunicación. Si el DCE es un módem este se prepara para conectarse a
la línea telefónica y se mantiene conectado hasta que se desactive este pin. El pin 8
se activa a un nivel lógico '0' por el módem cuando ha establecido una conexión y no
recibe tono de respuesta o es de calidad inadecuada. El pin 12 es similar al anterior
pero referida al canal secundario de comunicaciones. El pin 22 viene activado a un
nivel lógico '0' por el módem cuando se recibe señal de llamada desde la línea
telefónica. El pin 23 activado por el DTE o DCE a un nivel lógico '0' para seleccionar la
velocidad mas alta. A nivel lógico '1' selecciona la otra de las dos velocidades de
transmisión predeterminadas.
Señales de reloj de transmisor y receptor Si se emplea un protocolo síncrono, estas
señales dan la información de reloj para el transmisor y el receptor , que pueden estar
funcionando a velocidades distintas. Se encuentran los pines 15,17 y 24. El pin 15
es usado por un DCE (en este caso un módem) al operar en protocolo síncrono para
establecer la velocidad a la que los datos se emiten desde el DTE hacia el. La
transición del '1' al '0' lógico provoca la transición al siguiente dato en la línea de
transmisión de datos. El pin 17 similar al anterior ,sólo que proporciona al receptor del
equipo DTE información del reloj. El pin 24 proporciona una señal de reloj generada
por el DTE para su uso por un módem ,empleada solo cuando no se usan los
anteriores pines.
Señales de test
Antes de transmitir los datos puede ser comprobada la integridad
del canal y la velocidad de transmisión ajustada automáticamente al máximo
soportado por el canal. Encontramos aquí los pines 18,21 y 25. El pin 18 es activado
a nivel lógico '0' por el DTE y usado para poner al DCE en modo test. El módem pasa
a redireccionar su señal de salida hacia el circuito de recepción. Así los datos
generados por el DTE son devueltos en forma de eco. El pin 21 viene activado por el
DTE para poner al módem remoto en modo test. El DCE remoto redirecciona su señal
de recepción a su circuito de transmisión. El pin 25 se utiliza para confirmar el DCE
que ha pasado al modo test ya sea de módem local o remoto. (*Nota: todos los
números de pin empleados están referidos al conector de tipo DB-25 )
34
RS485 , emisor y receptor
En un sistema diferencial equilibrado el voltaje que produce el emisor aparece a
través de un par de líneas de señal que transmiten solo una señal. El voltaje que da
entre los terminales de salida se encuentra entre 2 y 6V ,para ello ha de estar
activado el pin de la habilitación del emisor a nivel alto de tensión. Aunque posee
conexión a masa el receptor no la usa para determinar el estado lógico de la línea.
Para poder recibir el pin de habilitación de la recepción ha de estar activado a nivel
bajo de tensión. El receptor lee el voltaje de la línea a través de los dos terminales de
entrada ,si el voltaje diferencial es mayor de +200 mV el receptor lo interpreta como '1'
lógico y si es menor de -200 mV se considera como '0' lógico. El rango de 200 mV a 6
V es necesario por la atenuación producida en la línea de transmisión.
RS485 ,terminación de línea
A mayor velocidad de transmisión y mayor distancia de transmisión aumenta el
problema de reflexión de la señal. Para que no se de este efecto las líneas deben
terminarse con una resistencia que haga que el cable se comporte eléctricamente
como si tuviese una longitud infinita. Esta resistencia de terminación debe tener el
mismo valor característico de la impedancia de las líneas de transmisión (Zo,
impedancia característica) por lo que dependerá de la geometría del cable empleado.
35
1.4.3 Interfaces para las comunicaciones
1.4.3.1 La capa física en los PCs
Las funciones de la capa física son realizadas en los ordenadores personales por una
circuitería adecuada y canalizada al exterior por su puerto serie.
1.4.3.1.1 El Puerto serie
Cumple con las especificaciones del estándar RS232C de la EIA (Electronic Industries
Association). El estándar define el uso de 25 líneas para la conexión entre DTE
(Equipo terminal de datos) y DCE (Equipo de comunicación de datos) ,la mayoría
reservadas para transmisiones síncronas. Una transmisión es síncrona cuando se
precisan señales adicionales (reloj) a la de datos ,encargadas de indicar cuando el bit
de datos es valido. Por otro lado las comunicaciones asíncronas sólo necesitan de 9
líneas, ya que tanto el emisor como el receptor trabajan a la misma frecuencia de reloj
y además la secuencia de bits incorpora un bit de arranque y uno de parada para la
sincronización.
Es posible la existencia de un bit de paridad entre los datos ,pero no se empleara ya
que la capa de nivel superior será la encargada del tratamiento de errores en los
datos.
La unidad de datos serie SDU estará formada de:
- 1 bit de arranque.
- 8 bits de datos.
- 1 bit de parada.
36
Ésta será común tanto al receptor como al emisor.
1.4.3.1.2 La UART (receptor/transmisor asíncrono universal)
Este chip (UART 8250/16450/16550) es el que realiza las funciones de la interfaz
serie. Ha de ser programado para satisfacer las necesidades de comunicación. Para
acceder
a las funciones de dicho chip se emplea la interrupción 21h del DOS o a través de la
BIOS por la interrupción 14h:
Interrupción 21h
Función
Descripción
03h
lectura de un carácter
04h
escritura de un carácter
3Fh
lectura de una cadena
40h
escritura de una cadena
Interrupción 14h
Función
Descripción
00h
inicialización del puerto serie
01h
escritura de un carácter
02h
lectura de un carácter
37
03h
lectura del estado de un puerto
04h
inicialización extendida
05h
registro de control de módem
Para un mayor control y optimización de las funciones del integrado se programará de
forma directa sus registros.
Registros de la UART
Estos se pueden encontrar a partir de la dirección base de cada puerto, además cada
uno de ellos tiene asociada una línea de interrupción.
Interfaz
Dirección base
IRQ
com1
3F8 h
4
com3
3E8 h
4
com2
2F8 h
3
com4
2E8 h
3
Para la implementación de la red local se emplearán ordenadores de dos puertos
serie además de un ratón PS2. Los registros de control y estado disponibles y sus
offsets relativos a la dirección base son:
Registro
Offset
buffer receptor
00h
buffer transmisor
00h
activación de interrupciones
01h
identificación de interrupciones
02h
formato de datos
03h
control de salida RS232
04h
estado de la línea
05h
estado de entrada RS232
06h
Scratch-pad
07h
Latch divisor bajo (velocidad de transmisión)
00h
Latch divisor alto (velocidad de transmisión)
01h
38
Registro del buffer de receptor
Cada bit que es recibido por el puerto serie se incorpora a este registro ,aunque el
dato sea de 5 bits se recogen siempre 8 bits (paridad, bit arranque, de parada...).Para
acceder a él ,el bit 7 (DLAB) del registro de formato de datos ha de estar a 0 para
diferenciarlo de un acceso al latch divisor. El tamaño de este buffer variará según el
integrado utilizado.
Registro del buffer de transmisor
Cuando escribimos un dato en este registro ,este se serializa y se transmite a la salida
serie con el formato y velocidad de transmisión elegidos.
Registro de activación de interrupciones
Permite des/habilitar cuatro tipo de interrupciones soportadas por la UART. Se
habilitan a '1' lógico. Para acceder a él ,el bit 7 (DLAB) del registro de formato de
datos ha de estar a 0 para diferenciarlo de un acceso al latch divisor.
7
6
5
4
3
2
1
0
0
0
0
0
RS232 IN
BREAK
TBE
RxRDY
RxRDY (bit 0)
des/habilita la interrupción generada
disponible un byte para lectura en el registro del buffer del receptor.
cuando
hay
TBE (bit 1)
des/habilita la interrupción generada cuando se desplaza un byte
desde el registro de retención del transmisor al registro de desplazamiento.
BREAK (bit 2)
des/habilita la interrupción generada cuando se produce un fallo
en la línea, error de paridad o sobreescritura de un carácter.
RS232 IN (bit 3)
des/habilita la interrupción generada cuando cambia el estado de
cualquiera de las entradas RS232.
Registro de identificación de interrupciones
Cuando se da una interrupción podemos descubrir su procedencia accediendo a este
registro. Un bit a 0 indica que la interrupción está pendiente.
bit2
bit1
bit0
prioridad
identificación
0
0
1
ninguna
ninguna
1
1
0
0
BREAK
1
0
0
1
RxRDY
0
1
0
2
TBE
0
0
0
3
RS232 IN
39
Cuando existe una interrupción pendiente no se informa
de la llegada de otras
de menor o igual prioridad .Dicha prioridad no es programable.
Registro de formato de datos
Permite configurar la Unidad de Datos Serie:
bit1/bit0
0/0
0/1
1/0
1/1
nº bytes datos
5
6
7
8
7
6
5
DLAB
BREAK
4
3
2
1
PARIDAD
BITS PARADA
0
bit5/bit4
0/0
0/1
1/0
1/1
paridad
impar
par
mark
space
BITS PARADA (bit 2) Indica el número de bits de parada a emplear ('0' = 1, '1' = 2).
PARIDAD (bit 3) Des/habilita ('0' o '1') el uso de paridad.
BREAK (bit 6) Cuando se activa a '1' se fuerza al transmisor a adoptar el estado
lógico '0' (Space)hasta que no se resetee dicho bit.
DLAB Se activa para acceder al latch divisor de 16 bits contenido en los registros 00h
y 01h de la UART.
Registro de control de módem
Controla el estado de las salidas invertidas RTS y DTR dos salidas de propósito
general y un bit para realizar una comprobación de bucle cerrado.
7
6
5
4
3
2
1
0
0
0
0
Test Local
GP2
GPO1
RTS
DTR
DTR (bit 0) activa la señal Terminal de Datos Preparado al poner este bit a '1' lógico.
RTS (bit 1) activa la señal Solicitud para Envío al poner este bit a '1' lógico. Para este
proyecto se empleará para la activación del transmisor RS485 del integrado
SN75176B.
GPO1 Salida de datos general 1 definible por el usuario
40
(reset del módem).
GPO2 Salida de datos general 2 definible por el usuario
de la UART).
(habilita
interrupciones
Test Local Cuando dicho bit se encuentra activado a un '1' lógico sucede lo siguiente:
-1º La salida del transmisor se activa a un '1' lógico.
-2º La entrada del receptor se desconecta.
-3º La salida del registro de desplazamiento del transmisor se conecta directamente
con el registro de desplazamiento del receptor.
-4º Las cuatro entradas de control RS232 se conectan directamente con las salidas
de la siguiente forma:
Entrada
Salida
CTS
RTS
DSR
DTR
DCD
GPO2
RI
GPO1
Se permite así comprobar que las funciones de la UART actúan de forma correcta.
Los datos del transmisor han de aparecer en el receptor.
Registro de estado de línea
Informa del estado del proceso de serialización, de la detección de Break ,errores de
receptor y de la actividad de los registros de recepción y transmisión.
7
6
5
4
3
2
1
0
0
TXE
TBE
BREAK
TRAMA
PARIDA
D
SOBREESCRITUR
A
RxRDY
RxRDY (bit 0) Se pone a '1' cuando se ha enviado un byte al buffer receptor. Al leer
dicho bit pasa a '0' . Lo mismo sucede para los siguientes.
SOBREESCRITURA (bit 1) Indica que un byte del buffer ha sido borrado por la
entrada de un nuevo byte. El carácter anterior se pierde.
PARIDAD (bit 2) Error de paridad del byte recibido según el registro de formato de
datos.
TRAMA (bit 3) Tras ensamblar el byte recibido el bit de parada era incorrecto.
BREAK (bit 4) Si el receptor detecta una condición SPACE durante un periodo mayor
41
que una SDU.
TBE (bit 5) Informa de que se ha desplazado un byte desde el registro de retención
del transmisor al registro de desplazamiento. Si esta a '1' nos indica que el buffer del
transmisor esta vacío y que si escribimos en dicho registro no se borrará el byte
anteriormente transmitido.
TXE (bit 6) Indica que no existen bytes en el buffer del transmisor ni en su registro de
desplazamiento. Se considera que es un flag de "todos los bytes enviados".
Registro de estado de módem
Indica si ha existido algún cambio de estado en la patilla correspondiente RS232
desde la última vez que se leyó (bits 0 a 3). Los bits 4 a 7 informan del estado
absoluto de sus respectivas entradas RS232. Un '1' indica la presencia de una tensión
positiva en la interfaz RS232.
7
6
5
4
3
2
1
0
DCD
RI
DSR
CTS
∆ 3DCD
∆ 4RI
∆ 5DSR
∆ 6CTS
Durante la comprobación en bucle cerrado , el bit 2 se activa en el flanco de subida
del pulso de timbre telefónico que recibe el módem. Los bits 4 a 7 informan del estado
actual de las salidas RS232
BIT 4
CTS = RTS
BIT 5
DSR = DTR
BIT 6
DCD = GPO2
BIT 7
RI = GPO1
Registro Scratch Pad
Usado como byte de RAM ,al no tener asignada función alguna de momento ,algunas
versiones anteriores de UART no lo tienen.
Latch divisor
Al poner a '1' el bit 7 (DLAB) del registro de formato de datos ,los registros 00h y 01h
se transforman en el byte bajo y byte alto del divisor. El reloj de referencia de la UART
se divide entre este word de 16 bits para obtener la frecuencia de transmisión de los
datos.
Frecuencia del reloj de referencia
42
velocidad [Baudios] =
-----------------------------------------(16 x Divisor)
1.4.3.2 La capa física en los microcontroladores SAB80c537
Interface RS485
Creado para el control de sistemas y distribución de datos, usa un par simétrico de
cables para una transmisión half-duplex(transmisión y recepción pero no simultánea).
En este sistema todas las estaciones están conectadas a un mismo par de hilos. La
configuración de red es en estrella.
En el plano industrial se usa como bus de
campo para comunicar los Front-End con los procesadores locales. Las transmisiones
pueden ser realizadas a una velocidad de hasta 10 MBits/s y hasta una distancia de
1,2 Km.
Cuenta con una baja susceptibilidad al ruido al usar entradas tipo diferenciales en los
receptores. Genera poco ruido por los bajos niveles de señal empleados.
Hardware
El SN75176B contiene un transmisor y un receptor RS485. Para su instalación,
primero hay que desconectar la línea R1out (patilla número 3 del MAX232) de la
entrada P3.0 (RXD) de la CPU 80c537 dejando abierto el puente JP12 y luego
conectar a esa entrada la línea R (pin 1 del
SN75176B) cerrando el puente JP10.
Al ser una comunicación half-duplex, es preciso gestionar la activación o
desactivación del transmisor a través del software, conectando DE (patilla número 3
del SN75176B) a un nivel alto de tensión. El receptor se deja habilitado, por ello se
conecta /RE (patilla 2 del SN75176 ) a masa ,esto provoca el eco de las
transmisiones y ha de ser tratado por software ,en cambio si se conecta junto con la
anterior al ser opuestas permite que la habilitación de una suponga la desactivación
43
de la otra y al in revés.
El integrado SN75156 en el μ80c537
Con el JP9 conectamos la impedancia de la línea, sólo en el comienzo y final del bus
de campo.
Patilla
Símbolo
Conexión al μ
Descripción
1
R
P3.0
Rxd bit a recibir
2
/RE
Gnd
Habilita recepción
3
DE
Px.x
Habilita transmisión
4
D
P3.1
Txd bit a transmitir
5
Gnd
0V
masa
6
A
PA (*)
Salida diferencial A
7
B
PB(*)
Salida diferencial B
8
Vcc
5V
Alimentación
(*) NOTA : conector externo RS485 , salida diferencial.
Interface R232
El integrado MAX232 en el μ80c537
Contiene dos transmisores y dos receptores para RS232 hasta 20 Kbits/s, cumple las
especificaciones EIA -232Ey CITT V.28. La versión MAX232A es de mayor velocidad
de transmisión (hasta 116 Kbits/s).
Descripción de conexiones
Conexión de condensadores de 100 μF entre:
- la patilla 1 y 3
- la patilla 2 y 16
- la patilla 4 y 5
- la patilla 6 y 15
- alimentación de +5 V (Vcc) y masa (Gnd)
Conectar la patilla 16 a Vcc, mientras que la patilla 15 y las masas de los conectores
DB9 se conectan a Gnd.
Patilla
Símbolo
Conexión al Descripción
μ
10
T2IN
P6.2
44
Txd/1 bit a transmitir
9
R2OUT
P3.0
Rxd/1 bit a recibir
11
T1IN
P3.1
Txd/0 bit a transmitir
12
R1OUT
P6.1
Rxd/0 bit a recibir
13
R1IN
Dsub9/0-2
Rxd rs232/0
7
T2OUT
Dsub9/0-3
Txd rs232/0
8
R2IN
Dsub9/1-2
Rxd rs232/1
14
T1OUT
Dsub9/1-3
Txd rs232/1
El integrado MAX233
Tiene las mismas características que el MAX232 sólo que no necesita componentes
externos al llevarlos integrados en el mismo encapsulado. La versión MAX233A es
igual que la MAX232A pero tampoco necesita de componentes externos.
1.4.3.2.1 Los puertos serie en el μ80c537
Este microcontrolador posee dos interfaces serie full-duplex (pueden recibir y
transmitir datos a la vez) con generador de señal de transmisión propio. Como
receptores tienen un registro de retención que les permite recibir un segundo byte
antes de que el registro receptor haya leído el anterior (si un byte no se lee antes de
acabar de montar el siguiente este se pierde. El canal serie 0 es 100 % compatible
con el del 8051 y el canal serie 1 funciona igual en modo asíncrono, pero no tiene
modo síncrono. Para acceder al registro receptor y emisor se emplea S0BUF o
S1BUF según el canal utilizado.
Canal serie 0
La velocidad del reloj de esta interfaz viene de la
frecuencia
del
oscilador
(modos 0 y 2) o bien generada por el timer 1 o por un generador de señal de
transmisión dedicado (modos 1 y 3).
Tiene 4 modos de operación:
- Modo 0
- Modo 1
- Modo 2
- Modo 3
Modo de desplazamiento de registro (síncrono).
UART de 8 bits ,velocidad de transmisión variable.
UART de 9 bits ,velocidad de transmisión fija.
UART de 9 bits ,velocidad de transmisión variable.
Canal serie 1
45
La interfaz serie 1 es un canal asíncrono que es capaz de trabajar en dos modos A y
B como UART e 8 o 9 bits. Tiene sus propios flags (avisos) de petición de interrupción
RIx con un vector de interrupción asociado. El reloj de esta interfaz viene de un
generador de señal de transmisión dedicado.
- Modo A
UART de 9 bits ,velocidad de transmisión variable.
- Modo B
UART de 8 bits ,velocidad de transmisión variable.
La razón del uso de 9 bits en varios de los modos citados, es que permiten el uso de
la función multiprocesadora. Esta consiste en que 8 de los bits son datos y el 9º bit
actúa de la siguiente manera: recibidos los 8 bits de datos en el registro SxBUF ,el
último bit aparece en el 2º bit del registro SxCON. Si se programa el canal de forma
que el 9º bit al encontrarse a '1' lógico permita la interrupción del flag RIx ,podremos
direccionar varios microcontroladores y una vez que todos sepan si es o no su
dirección actúen recibiendo la continuación del mensaje o no impidiendo la citada
activación del flag RIx.
Por ejemplo ,un microprocesador que funciona como Front-End y de cara al bus de
campo actúa como un procesador maestro, quiere recibir un bloque de datos
de
uno de los procesadores locales. Lo primero que hace es enviar una unidad de datos
como la siguiente,con el bit 8 a '1' lógico:
'0'
0
1
2
3
4
5
6
7
8
'1'
|
|____________________________| |
|
|
|
|
bit de
bit de
|
9ºbit
parada
arranque
byte de datos
Todos los procesadores locales tienen el bit SM2x (bit 5) del registro de control serie
SxCON a '1' lógico y permiten así que se de la interrupción RIx al recibir dicha unidad
de datos. El controlador que reconozca su dirección en ese byte pondrá su bit SM2x a
'0' lógico y esperará el comando o función a realizar. Entonces el procesador maestro
le enviará la función en una unidad de datos igual a la anterior pero esta vez con el 9º
bit a
'0' ,así sólo el procesador con el bit SM2x a '0' lo
podrá "escuchar". Una vez que
el procesador local determina la función y envía los datos solicitados pone su bit
SM2x (de habilitación de las interrupciones generadas por el flag RIx según el estado
del 9º bit) a
'1'. El procesador maestro puede pasar entonces a direccionar a otro procesador.
Para el presente proyecto se emplearán los equipos microcontroladores SAB80c537
en campo como procesadores
locales y PCs estándar como Front-End entre el
bus de campo y la red local. Los que actúen como procesadores locales sólo
emplearán el canal serie 0 ,anulando la interfaz RS232 (integrado MAX232) y
incorporando la interfaz RS485 (integrado SN75176). El canal serie 1 se dejará para
programar ,mediante un ordenador portátil ,el microcontrolador de manera directa si
ello fuese necesario ,aunque por defecto sólo transmiten los datos principales de la
estación y mensajes de aviso. Mientras que los PCs que actúen como Front-End,
emplearán el puerto serie 1 para comunicarse con esos por el bus de campo; al
conector de 9 pines del canal
serie 1 se le conectará la tarjeta convertidora
RS232/RS485 para poder comunicarlos.
46
En el bus de campo se empleará el canal serie 0 en modo 1 ,ya que la función
multiprocesadora no se puede aplicar al no disponer de los requisitos necesarios los
PCs que actúen de Front-Ends. Para las comunicaciones por el canal serie 1 en los
procesadores locales se empleará el modo B. Estos métodos permiten poder variar
la velocidad de transmisión ,cuando el usuario lo desee y sin ningún tipo de problema.
A continuación se detallan los modos de trabajo de los canales serie 0 y 1 a emplear
para este proyecto:
Canal 0 , modo de trabajo 1
Se transmiten 10 bits a través de TxD0 o se reciben a través de RxD0 : 1 bit de
arranque ,8bits son de datos (primero el menos significativo) y 1 bit de parada. La
velocidad de transmisión puede ser variada por programa ,pero para que los datos de
información sean reconocidos por los demás dispositivos ,antes de variarla hay que
solicitarles a los equipos receptores el cambio de velocidad de transmisión.
La transmisión se inicia al escribir en el registro S0BUF. La recepción se inicia si el bit
de habilitación REN0 está activado a un '1' lógico. Para leer el dato recibido se ha de
hacer del registro S0BUF que se encuentra físicamente en otro sitio de cuando
accedemos para escribir el dato a transmitir. Los interfaces proveen de una
interrupción cuando se ha completado la transmisión o recepción de una unidad de
datos. Los flags o avisos de recepción o transmisión se encuentran en los bits RI0 y
TI0 respectivamente. Estos flags permiten ,en caso de no emplear interrupciones ,la
encuesta periódica de su estado para saber si se ha recibido o enviado algún dato por
el interfaz serie.
Para trabajar en este modo los bits SM0 y SM1 del registro S0CON han de estar
configurados a un valor lógico '0' y '1' respectivamente.
S0CON:
98h
SM0
0
SM
1
SM20
0
REN0
1
TB80
RB80
TI0
RI0
El bit SM20 habilita la función multiprocesadora como se ha explicado anteriormente
,pero en nuestro caso no se hará servir.
En este modo la velocidad de transmisión se puede obtener de un generador de
baudios dedicado o del temporizador 1. Para habilitar al primero el bit BD (bit 7 del
registro ADCON0) debe estar activado a '1' lógico. Este generador de señal de
transmisión divide la frecuencia del oscilador por 2496. El bit SMOD (bit 7 del registro
PCON) se puede usar para habilitar una escala multiplicadora por dos.
SMOD
vel. transmisión en Baudios = 2
_ f osc 7
2496
Para este proyecto el timer 1 se dejará para otros usos y se aprovechara el generador
de baudios interno dedicado.
47
Si se emplease el temporizador 1 se pueden obtener las siguientes velocidades de
transmisión:
TIMER 1
Baudios
F.osc.
SMOD
C/T
Modo
Valor
Recarga
62.500
19200
9600
4800
2400
1200
110
110
12.0
11.059
11.059
11.059
11.059
1
1
0
0
0
0
0
0
0
0
0
0
0
0
0
0
2
2
2
2
2
2
2
1
FF hex.
FD
FD
FA
F4
E8
72
FEEB
11.059
6.0
12.0
Canal 1 , modo de trabajo B
Se transmiten 10 bits a través de TxD0 o se reciben a través de RxD0 : 1 bit de
arranque ,8bits son de datos (primero el menos significativo) y 1 bit de parada. En la
recepción el bit de parada va a parar al bit RB81
del registro S1CON. La
velocidad de transmisión puede ser variada por programa ,pero para que los datos de
información sean reconocidos por los demás dispositivos, antes de variarla hay que
solicitarles a los equipos receptores el cambio de velocidad de transmisión. Este
modo es igual que le modo 1 de la interfaz serie 0 ,lo único que varia es la generación
de velocidad de transmisión.
La transmisión se inicia al escribir en el registro S1BUF. La recepción se inicia por la
llegada del bit de arranque al estar el bit REN1 del registro S1CON activado un '1'
lógico. La interface serie 1 provee de una petición de interrupción cuando una unidad
de
datos esta completa en la recepción o fin de transmisión. Las "banderas" o flags de
aviso de nueva recepción o transmisión finalizada ,son RI1 y TI1 respectivamente.
Estos se pueden emplear también para encuesta del estado del interfaz serie. Los
registros S1CON y S1BUF no son
accesibles a bit ,sólo a byte no
permitiéndose entonces las instrucciones como JNB o CLR (ver anexos sobre códigos
de programación del SAB80c537).
S1CON:
9Bh
SM
1
SM21
0
REN1
1
TB81
RB81
TI1
RI1
El bit SM a '0' indica modo de trabajo A (9 bits UART, velocidad de transmisión
variable) y si esta a '1' indica modo de trabajo B (8 bits UART, velocidad de
48
transmisión variable). El bit SM21 tiene la misma
tampoco se empleará en este proyecto.
función que el SM20 pero
1.4.3.3 Tarjetas de comunicaciones a fabricar
Las comunicaciones a través de RS232 como se ha comentado anteriormente están
diseñadas para un enlace punto a punto con una distancia máxima de 15 m, por lo
que será necesario el uso de el estándar RS485 que permitirá la creación de una red
multipunto de hasta 1200 m de longitud. Para ello se diseñara una tarjeta convertidora
de RS232 a RS485.
A continuación se detalla un pequeño esquema del objetivo a conseguir:
49
A nivel de bus de campo no se requiere ningún interface adicional para las
comunicaciones en los procesadores locales ,si en los PCs que actúen de Front-Ends
para adaptar las comunicaciones RS232 a RS485.
50
En la red local todos los PCs ya sean Front-Ends o Workstations deberán tener una
tarjeta convertidora de RS232 a RS485. Las tarjetas de interface para las
comunicaciones irán alimentadas desde el propio ordenador personal ,así las masas
de estas y de los equipos no estarán desequilibradas ,aspecto muy critico sobretodo
en las comunicaciones basadas en las especificaciones RS232.
En el apartado de planos del presente proyecto se puede observar con mas detalle
dichas tarjetas convertidoras.
Se ha optado por alimentar las tarjetas de los propios equipos para no tener que
garantizar una alimentación exclusivamente para la red (sería necesario un sistema
de alimentación ininterrumpida para evitar problemas). Pero para proteger a dichos
equipos se instalarán
protectores contra sobretensiones para redes ,tanto a las
salidas de estos equipos (PCs y microcontroladores) así como a las salidas de las
tarjetas conversoras.
Otra posible solución seria la detallada en la página siguiente ,con el inconveniente de
que el número de paquetes manipulados tendría que ser fijo ,cosa que no interesa
para ciertas aplicaciones y funciones que se llevan a cabo en este proyecto.
51
Esquema de la red ,conexión de las tarjetas de comunicaciones y alimentaciones
Diagrama del circuito empleado como tarjeta conversora
52
1.4.4 Topología de la red y del bus de campo
La topología o arquitectura de las redes se refiere a la manera de distribuir
físicamente cada estación o nodo de las mismas y como interconectarlas entre si
,existen varios tipos de topologías que se detallan seguidamente:
Estrella Se llama así pues hay un centro denominado HUB o concentrador hacia el
cual convergen todas las líneas de comunicación. Cada estación tiene un enlace
exclusivo con el HUB. Los sistemas basados en la filosofía de servidor usan esta
topología ,con el servidor en el centro ,pero se diferencian en la forma de
comunicación. En las redes locales el HUB es un dispositivo ya sea pasivo o activo
que permite que todas las estaciones reciban la transmisión de una, en los sistemas
con servidor sólo este recibe. En este último sistema un terminal se comunica con el
servidor y este a su vez con el otro.
Árbol Similar al anterior sólo que de un punto central divergen varias secciones que a
su vez se ramifican en otras más y así. Las estaciones que se ramifican actúan
también como repetidoras. Es un sistema más distribuido que el anterior que se
encuentra más
concentrado a un punto.
53
Bus En esta topología hay un cable que recorre todas las estaciones sin formar
caminos cerrados ni tener bifurcaciones. Eléctricamente equivale a un único nodo,
pues los transceptores de todas las máquinas quedan conectados en paralelo. A los
efectos de mantener una impedancia constante en el cableado e la red ,se deben
conectar dos "terminadores" en ambos extremos el cableado de la misma.
Anillo En este caso ,las líneas de comunicación forman un camino cerrado. La
información generalmente recorre el anillo en forma unidireccional, cada máquina
recibe la información de la maquina previa ,la analiza ,y si no es para ella ,la
retransmite a la siguiente.
Esta topología se distingue porque cada estación se conecta con la
Cascada
siguiente y la última no. La comunicación es full-duplex por lo que las comunicaciones
se dan en ambas direcciones. Cada estación actúa de repetidora de los datos que
recibe si no están dirigidos a la misma.
54
Para este proyecto se ha pensado en la topología en bus pues es la más adecuada al
medio a emplear (RS485) ,mayor facilidad de instalación y menor coste. Además
permite mediante un protocolo común el acceso a todo tipo de información de
equipos heterogéneos lo que le da un carácter mas abierto. El único inconveniente es
la menor seguridad por rotura de la línea o bus.
Para solucionar este problema se cuenta con los protocolos de enlace y acceso al
medio que permiten controlar en todo momento el estado de las comunicaciones y en
caso de avería notificarlo y dejar las transacciones de datos en un estado de espera
segura ;guardando la información de los datos enviados o que falten por enviar. La
topología en bus es la que especifica el estándar IEEE 802.4 para acceso al medio
por uso de testigo en bus.
Para definir una red lo primero es definir el soporte físico a emplear ,seguidamente
decidir según las necesidades el empleo ,el uso o no de algún interfaz adicional (para
adaptar el medio a los equipos disponibles) ;luego según criterios económicos
,técnicos o de seguridad se escoge una topología o arquitectura de red mas
adecuada. Para finalizar se decide el protocolo mas idóneo para dicho medio físico y
topología.
55
1.4.5 El proyecto 802 del IEEE
Su tarea es la de especificar los medios mediante los cuales los dispositivos pueden
comunicarse a través de una red local. Su objetivo es asegurar la compatibilidad entre
equipos suministrados por diferentes fabricantes de forma tal que la comunicación de
información pueda tener lugar entre los dispositivos con un mínimo esfuerzo por parte
de los usuarios o por los fabricantes de un sistema que contenga tal equipo.
Para su consecución ,el estándar de redes locales proporciona especificaciones que
establece interfaces y protocolos comunes para las redes locales de datos.
Fundamentalmente el modelo del proyecto 802 cubre los siguientes aspectos:
- Nivel físico relacionado con la naturaleza del medio de transmisión y con los
detalles de los dispositivos de conexión y señalización eléctrica.
- Nivel de enlace que en el caso de redes locales se divide en dos subniveles:
- Control de enlace lógico (LLC)
- Control de acceso al medio (MAC)
- Nivel de Red incluye la Gestión de la red.
Modelo de la comisión IEEE 802
Para los buses de campo el nivel de enlace sólo precisa de un control de acceso al
medio y de ello se encargan los protocolos de bus de campo existentes. En la página
siguiente se explican detalladamente las características fundamentales de los
protocolos de bus de campo más implantados en la industria. Su visión se basa más
a nivel físico para
adaptar el más conveniente a nuestras necesidades.
Posteriormente nos centraremos a estudiar a nivel enlace (concretamente de acceso
al medio) el que se adecue más a nuestras perspectivas. Para la red local no se
precisa de una capa de Red ya que no es necesario ningún tipo de enrutamiento al
ser de área local.
56
1.4.5.1 - Comparativa de los diferentes protocolos de bus de campo
existentes, y elección del protocolo a emplear.
En la actualidad existen diversos buses de campo, cada uno de ellos desarrollado por
diferentes compañías y para distintos propósitos. A continuación se comparan
algunos de estos buses:
Desarrollado como un sistema remoto de I/O,basado en inteligencia
FILBUS
distribuida y comunicación punto a punto. Las funciones de estos módulos FILBUS
I/O permiten básicamente contaje de pulsos, retardo antes de actuación y enviar y
recibir mensajes de o hacia otros módulos de la misma red.
Principales Características:
Velocidad
Max. nodos con repetidores
sin repetidores
Max. distancia con repetidores
sin repetidores
Arbitración del bus
Tipo de cable
Tamaño de cabecera/datos
Aplicación
375 Kbits/s
250
32
13.2 Km
1.2 Km
Maestro/Esclavo
Par de cables trenzados
1 a 256 bytes
Adquisición de datos
BITBUS Introducido originalmente por Intel como una via para añadir capacidad de
entrada /salida remota al sistema Multibus. Este bus ha sido muy extendido y usado
en redes. Permite a los programas ser descargados y ejecutados en un nodo remoto
para un sistema de configuración realmente distribuida.
Principales Características:
Velocidad
Max. nodos con repetidores
sin repetidores
Max. distancia con repetidores
sin repetidores
Arbitración del bus
Tipo de cable
Tamaño de cabecera/datos
Aplicaciones
375 Kbits/s
250
32
13.2 Km
1.2 Km
Maestro/esclavo
Par de cables trenzados
13 a 52 bytes
Módulos inteligentes de entrada salida y
control de proceso
Provee un esquema determinístico y realizable para la comunicación de
FIP
variables de un proceso (generadas por sensores y ejecutadas por actuadores)y
mensajes (eventos ,configuración, comandos) a una velocidad de transmisión de
hasta 1Mbit/s en unos pares de cables trenzados de bajo coste. FIP usa un
mecanismo original donde el arbitro del bus transmite una variable identificadora a
57
todos los nodos de la red y haciendo que sea escrito su valor en la red por el nodo
que la posea.
Una vez en la red, todos los módulos que necesiten dicha información la utilizan
simultáneamente.Este concepto se lleva a cabo en una base de datos de variables
descentralizada y con características de tiempo real. Así se elimina la noción de
dirección de nodo y hace posible el diseño real de un sistema de control de proceso
distribuido.
Principales Características:
Velocidad
Max nodos con repetidores
sin repetidores
Max distancia con repetidores
sin repetidores
Arbitración del bus
Tipo de Cable
Tamaño de cabecera/datos
Aplicaciones
1 Mbits/s
256
64
10.0 Km
2.0 Km
Arbitro de Bus
Par de cables trenzados
1 a 128 bytes
control en tiempo real
Es una red de bus de campo diseñada para una comunicación
PROFIBUS
determinística entre ordenadores y PLCs. Basado en un principio de testigo de bus
asíncrono en tiempo real. Define relaciones de comunicación maestro/esclavo y
multi-maestros, con acceso cíclico o no, permitiendo transferencias a velocidades de
hasta 500 Kbits/s. La capa física 1 (2 cables RS485), la capa de enlace 2 y la capa
de aplicación están estandarizadas. Profibus distingue entre servicios orientados o no
a conexión. Permite comunicación entre procesos y multitareas.
Principales Características:
Velocidad
Max nodos con repetidores
sin repetidores
Max distancia con repetidores
sin repetidores
Arbitración del bus
Tipo de cable
Tamaño de cabecera/datos
Aplicaciones
Automatización
500 kbits/s
127
32
0.8 Km
0.2 Km
paso de testigo
Par trenzado
250 bytes
Comunicaciones entre PLCs y
industrial
(Controller Area Network) es un bus serie rápido, diseñado para proveer un
CAN
eficiente, realizable y muy económico enlace entre sensores y actuadores. Utiliza un
par de cables trenzados para comunicar a unas velocidades de hasta 1 Mbit/s con
hasta 40 dispositivos. Originalmente desarrollado para simplificar el conexionado en
los automóviles, su uso se ha extendido gracias a que: - Cualquier nodo puede
acceder al bus cuando este esta inactivo. - arbitración no destructiva para permitir el
uso del 100% del ancho de banda sin perdida de datos - Prioridad variable de los
mensajes basada en un paquete identificador de 11 bits. - Recepción multimaestro,
58
punto a punto o multipunto. - Detección automática de error. - Paquetes de datos de 8
bytes de longitud.
CAN es la base de diversos buses de sensores como DeviceNET de Allen Bradley, la
capa de aplicación (CAL) de CAN en automatización, o el SDS de Honeywell.
Principales Características:
Velocidad
Max nodos con repetidores
sin repetidores
Max distancia con repetidores
sin repetidores
Arbitración del bus
Tipo de cable
Tamaño de cabecera/datos
Aplicaciones
> 1 Mbits/s
n/a
30
n/a
40m a 1Mb/s o 1Km a 20kb/s
CSMA (detección de portadora)
Par trenzado
8 bytes fijos
En sensores y actuadores para automoción
59
1.4.5.1.1 Comparación de buses de campo
A continuación se detallan una tablas con las características principales de los buses
de campo más extendidos:
Tecnología
Año de
introducción
Promotor
PROFIBUS DP/PA
DP-1994,PA-1995
PNO/PTO
INTERBUS-S
1984
Phoenix Contact
DeviceNet
1994
Rockwell,
Allen-Bradley
ARCNET
1977
Datapoint/ SMC
AS-I
desapareció
en 1993
AS-I Consortium
Foundation FieldBus H1
1995
FieldBus
Foundation
Tecnología
Directriz estándar
Abierta a:
PROFIBUS DP/PA
EN 50170
DIN 19245
parte 3 (DP)
parte 4 (PA)
IEC 1158-2 (PA)
ASICs de Siemens
y Profichip,
Productos de 300
vendedores
INTERBUS-S
DIN 19258
EN 50.254
Productos de mas
de 400 fabricantes
DeviceNet
ISO 11898
ISO 11519
chips de 17
vendedores,
mas de 300
productos
ARCNET
ANSI/ATA 878.1
Chips,placas
,documentos
ANSI
AS-I
Traspasado al IEC
Articulo
AS-II.C.
60
Foundation FieldBus H1
ISA SP50
IEC TC65
Chips,
programas y
productos de
múltiples
vendedores
Tecnología
Año de
introducción
Promotor
Foundation FieldBus High
Speed Ethernet (HSE)
En desarrollo
FieldBus
Foundation
IEC/ISA SP50 Fieldbus ISA
1992-1996
FieldBus
Foundation
Seriplex
1990
APC,Inc. ahora
AEG Modicon
WorldFIP
1988
WorldFIP
LonWorks
1991
Echolon Corp.
SDS
1994
Honeywell
Tecnología
Directriz estándar
Abierta a:
Foundation FieldBus High
Speed Ethernet (HSE)
IEEE 802.3 RFC
para IP, TCP y UDP
Chips,
programas
productos de
múltiples
vendedores que
suministran
productos
Ethernet
IEC/ISA SP50 Fieldbus ISA
IEC 1158
ANSI 850
chips de
diversos
vendedores
Seriplex
Seriplex
chips disponibles
de múltiples
interfaces
WorldFIP
IEC 1158-2
chips de
diversos
vendedores
LonWorks
n/a
Documentación
publica del
protocolo
61
SDS
Especificación
Honeywell
Traspasado al IEC,
ISO 11989
chips de 17
vendedores,
mas de 200
productos
Tecnología
Año de
introducción
Promotor
ControlNet
1996
Rockwell
Allen-Bradley
CANopen
1995
CAN automatización
Modbus Plus
1980
AEG Modicon
Modbus RTU/ASCII
1970
AEG Modicon
Industrial Ethernet
después de 1970
Intel/DEC
/Xerox
Tecnología
Directriz estándar
Abierto a:
ControlNet
ControlNet Internacional
chips de 2
vendedores
CANopen
CiA
chips de 17
vendedores y
300 productos
Modbus Plus
Ninguno
Controlado
por AEG Modicon
Modbus RTU/ASCII
EN 1434-3
IEC 870-5
usa UART
(RS232,422/485)no
requiere
un hardware
especial
Industrial Ethernet
IEEE 802.2
miles de
vendedores
y proveedores
de chips
Características Físicas de la red
PROFIBUS DP/PA
Topología
medio físico
max. nº nodos
62
max. distancia
estrella anillo
par
trenzado
o fibra
127 nodos
(124 esclavos
4 segmentos
3 repetidores)
100 m entre
segmentos a
12 Mbaudios
y hasta 24 Km
con fibra
INTERBUS-S
Topología
medio físico
max. nº
nodos
max. distancia
segmentado
par trenzado
o fibra
256 nodos
400 m por segmento,
12.8 Km en total
Topología
medio físico
max. nº
nodos
max. distancia
en árbol
par trenzado
64 nodos
500 m y hasta 6
Km con repetidor
Topología
medio físico
max. nº
nodos
max. distancia
estrella o
bus
par trenzado
coaxial o
fibra
255 nodos
61 m con coaxial
122 m con el par
1.8 Km con fibra
DeviceNet
ARCNET
AS-I
Topología
medio físico
max. nº
nodos
max. distancia
anillo
estrella
bus
par de cables sin
trenzar
31 esclavos
100 m y 300 m
con repetidores
FieldBus Foundation H1
Topología
medio físico
max. nº
nodos
max. distancia
estrella
o bus
par trenzado o
fibra
65000
segmentos
1.9 Km a
31.25 Kbaudios
FieldBus Foundation HSE
63
Topología
medio físico
max. nº nodos
max. distancia
estrella
par
trenzado o
fibra
direccionado
por IP
nº ilimitado
de nodos
100 m a
100 Mbaudios
2 Km con fibra
y full-duplex
IEC/ISA SP50 Fieldbus
Topología
medio físico
max. nº
nodos
max. distancia
estrella
o bus
par trenzado
fibra,radio
hasta 128
1.7 Km a
31.25 Kbaudios
Seriplex
Topología
medio físico
max. nº
nodos
max. distancia
estrella
anillo
o árbol
4 cables
trenzados
> 500
equipos
152 m
Topología
medio físico
max. nº
nodos
max. distancia
bus
par trenzado
o fibra
256
> 40 Km
Topología
medio físico
max. nº
nodos
max. distancia
estrella
anillo
o bus
par trenzado
fibra,lineas
de fuerza
32000 por
dominio
2 Km a
78 KBaudios
WorldFIP
LonWorks
SDS
Topología
medio físico
max. nº nodos
max.
distancia
árbol
par trenzado
o líneas
de fuerza
64 nodos
126 direcciones
500 m
64
ControlNet
Topología
medio físico
max. nº
nodos
max. distancia
estrella,
árbol o
combinado
coaxial o
fibra
99 nodos
1000 m coaxial
3 Km con fibra
hasta 30 Km
con repetidores
CANOpen
Topología
medio físico
max. nº
nodos
max. distancia
árbol
par trenzado
o líneas
de fuerza
127 nodos
1000 m
Topología
medio físico
max. nº nodos
max.
distancia
lineal
bus
par trenzado
64 max. por
segmento con
capacidad para
puentes
500 m por
segmento
Modbus Plus
Modbus RTU/ASCII
Topología
medio físico
max. nº nodos
max. distancia
lineal,
estrella,
árbol
par
trenzado
250 por segmento
350 m
Industrial Ethernet
Topología
medio físico
max. nº nodos
max. distancia
estrella,
bus
10 Base-T
(par trenzado)
10 Base- FL (fibra)
48 bits para
direcciones
no disponible
65
Mecanismo de transporte
Propiedades de
la transmisión
Tamaño de
datos
Método
PROFIBUS
DP/PA
punto a punto
DP:hasta
12MBaudios
PA:hasta
31.25 KBaudios
hasta
244 bytes
Maestro/Esclavo
INTERBUS-S
500 KBaudios
full-duplex
bloque
ilimitado
Maestro/Esclavo
Devicenet
500 KBaudios
Maestro/Esclavo
multi-Maestro
ARCNET
hasta
10MBaudios
mensajes
variables
de >8byte
hasta 507
bytes
AS-I
resistente a
EMIs
hasta 31
esclavos con 4
entradas y 4
salidas
Maestro/Esclavo
con encuesta
cíclica
Método de
arbitración
Corrección de
errores
Diagnósticos
PROFIBUS
DP/PA
paso de testigo
HD4 CRC
Estación, módulo y
canal
INTERBUS-S
Ninguno
16-bit CRC
DeviceNet
CSMA
CRC
localización del
segmento con error
y rotura de cable
monitorización del
bus
ARCNET
paso de testigo
16-bit CRC
66
Punto a punto
reconocimiento
en la capa de
enlace
AS-I
Maestro/Esclavo
con encuesta
cíclica
código
Manchester
distancia de
Hamming 2
Fallo en el esclavo
o el equipo
Propiedades de
la transmisión
Tamaño de
datos
Métodos de
comunicación
Fieldbus
Foundation H1
31.25 Kbits/s
128 octetos
Cliente/servidor
notificación de
eventos
Fieldbus
Foundation HSE
100 Mbits/s
usa el
estándar
TCP/IP
Cliente/servidor
notificación
de eventos
IEC/ISA SP50
hasta
5 Mbits/s
64 octetos
Cliente/servidor
Seriplex
200 Mbits/s
7680 por
transferencia
Maestro/Esclavo
o igual a igual
WorldFIP
6Mbits/s
(con fibra)
hasta 128bytes
igual a igual
Método de
arbitración
Corrección de
errores
Diagnósticos
Fieldbus
Foundation H1
Esquematizado
16 bit CRC
remotos,
monitoriza
la red
Fieldbus
Foundation HSE
CSMA/CD
CRC
configurable
por el
mantenedor
de la red
IEC/ISA SP50
Testigo,
maestro
o por esquema
16 bit CRC
Seriplex
CSMA
fin de paquete
y eco
67
problemas
de cableado
WorldFIP
Arbitración
central
16 bit CRC
cableado
redundante y
time-out de
mensajes
Propiedades
de la
transmisión
Tamaño de
datos
Métodos de
comunicación
LonWorks
>1.25 Mb/s full
duplex
> 228 bytes
maestro/esclavo
o igual a igual
SDS
>1Mbps
mensaje >8 bits
variable
maestro/esclavo
, igual a igual
, multi-maestro
o difusión
ControlNet
>5 Mbits/s
hasta 510 bytes
según el modelo
fabricante /
consumidor
CANOpen
1 Mbits/s
mensajes 8 bits
variables
maestro/esclavo
o multi-maestro
Modbus Plus
> 1 Mbits/s
>256 bytes de
datos mas
cabecera
Paso de testigo
Método de
arbitración
Corrección de
errores
Diagnósticos
LonWorks
CSMA
16 bit CRC
base de datos de
errores de CRC y
del
equipo
SDS
CSMA
CRC
monitoriza
la red ,y
diagnostico
del esclavo
68
ControlNet
CTDMA
CCITT 16 CRC
ID de nodo
duplicada
fallos en
equipo o
esclavo
CANOpen
CSMA
CRC
mensajes de
error y
alarmas
Modbus Plus
igual a igual o
paso de testigo
16 bit CRC
Chip local
y programa
Propiedades de
la transmisión
Tamaño de
datos
Métodos de
comunicación
Modbus
RTU/ASCII
38.4 Kbits/s
hasta 254 bytes
maestro/
esclavo
Ethernet
Industrial
100 Mbits/s
>1500 bytes de
datos
CSMA/CD
Método de
arbitración
Corrección de
errores
Diagnósticos
CD
32 bit CRC
detecta colisiones
y
mantenimiento
de la red
Modbus
RTU/ASCII
Ethernet
Industrial
69
Comparación de características de protocolos de buses de campo
Protocolo
Cuenta con:
Coste por
equipo
conectado
Coste por chip
IEC SP50
Esta siendo
definido
No disponible
No disponible
Profibus ISP
soporte amplio
1000 $
elevado
WorlFIP
soporte amplio
1000 $
elevado
CAN
múltiples
vendedores
35 $
5$
LON
amplios productos
50 $
6$
(Nota: $ significa valor en dólares)
70
Protocolo
Seguridad
intrínseca
Capa de enlace
Determinístico
IEC SP50
Si
Esta siendo
definida
Si
Profibus ISP
No
Semi-duplex
síncrono
Si
WorlFIP
No
síncrono mas
mensajes
Si
CAN
No
síncrono mas
difusión mensajes
Si
LON
No
paquetes con
16 bit CRC
No
Protocolo
Acceso
Distancia
N º estaciones
IEC SP50
igual a igual
2000 m
256
Profibus ISP
maestro/
esclavo
1200 m
32 a 127 por
segmento
WorlFIP
maestro/
esclavo
2000 m
256
CAN
maestro/
esclavo
o igual a igual
1000 m
en DeviceNet
64 nodos ,en
SDS 426 nodos
LON
igual a igual
2000 m
127 nodos por
segmento y 32.385
nodos por dominio
71
Protocolo
Arbitración
Medio físico
Max. vel.
transmisión
IEC SP50
Modular
par trenzado
2.5 MBy/s
Profibus ISP
Modular y paso
de
testigo
par trenzado
2.5 MBy/s
WorlFIP
Comando/
respuesta
y acceso
maestro
esclavo
síncrono
par trenzado
2.5 MBy/s
CAN
Comando/
respuesta
mas prioridad
par trenzado
1 MBy/s
LON
CSMA
predictivo
mas opción de
prioridad
par trenzado,
línea de
fuerza y radio
frecuencia
1.25 MBy/s
Protocolo
Capa de aplicación
posibilidad de
alimentar
sensores
IEC SP50
Esta siendo definida
Si
Profibus ISP
servicio de mensajes
en bus de campo
Si
72
WorlFIP
servicio de mensajes
en bus de campo
Si
CAN
soporte
SDS y DeviceNet
Alimentación por
separado
LON
No tiene
Posibilidad de 2 o 4
hilos
Protocolo
Tiempo de
ciclo para
256 señales
discretas
Tiempo de
ciclo para 128
señales
analógicas
Transferencia de
un bloque de 128
bytes
PROFIBUS
DP/PA
2 ms
2 ms
no disponible
INTERBUS-S
1.8 ms
7.4 ms
140 ms
DeviceNet
2 ms (polling)
10 ms
4.2 ms
AS-I
4.7 ms
no posible
no posible
Fieldbus
Foundation H1
100 ms
600 ms
36 ms
Fieldbus
Foundation
HSE
5 ms
5 ms
1 ms
IEC/ISA SP50
depende de
configuración
depende de
configuración
1 ms a 1 Mbps
Seriplex
1.32 ms
10.4 ms
10.4 ms
WorldFIP
2 ms
2 ms
2 ms a 1 Mbps
LonWorks
20 ms
5 ms
5 ms a 1 Mbps
SDS
1 ms
1 ms
2 ms a 1 Mbps
ControlNet
0.5 ms
0.5 ms
0.5 ms
CANOpen
1 ms
1 ms
1 ms
Modbus Plus
no
está
73
disponible
Modbus
RTU/ASCII
no
está
disponible
Industrial
Ethernet
5 ms
5 ms
1ms
ARCNET
depende de
la capa de
aplicación
1.4.5.1.2 Protocolo del μ80c537
El microcontrolador 80c537 puede comunicarse con una red local en estrella de 32
estaciones empleando el interface RS485. A nivel Europeo el protocolo estándar que
existe consta de las siguientes características: - Ningún mensaje ha de durar más de
1 s en la línea. - Después de enviar el mensaje hay que dejar pasar un tiempo de 125
ms. - Durante los primeros 80 ms de espera ningún transmisor puede hacerse con el
control del bus. - Entre los 85 ms y 115 ms cualquier transmisor puede coger el
control del bus. Cada estación debe tener asignada una prioridad que se traduce en
un tiempo de espera distinto (alta prioridad = 85 ms ,baja prioridad = 110ms). - Un
transmisor no toma el control del bus si no puede leer de él lo que escribe. - El
receptor debe saber si hay o no datos y si estos han de ser leídos por él. La cabecera
de cada mensaje ha de tener una dirección de destino como mínimo.
Protocolo del Sistema Operativo del μ80c537
- Tramas: [C]omando + ( [P]arámetro + [F]cs )
Descripción:
Mandatos enviados al S.0.
Comando
Parámetro
Respuesta del S.0.
FCS
129
Comando
Parámetro
FCS
129
PC
X
D.M.E.
X
D.M.I
X
ejecuta
programa
X
130
@/L
X
130
131
@/L/D.M.E.
X
131
132
@/L
X
132
133
@/L/D.M.I.
X
133
134
PC
X
134
74
135
135
reset
136
136
paso a paso
137
137
/paso a paso
138
138
reg.general
139
139
punto ruptura
Comando
Parámetro
FCS
Comando
140
PC
X
140
141
reg.
generales
X
141
Parámetro
255
255
31.2
KBaudios
150
150
57.6
KBaudios
151
151
9.6 KBaudios
X
X
FCS
Para este proyecto sólo se empleará el protocolo del S.0. para visualizar el estado por
un ordenador portátil o si fuese necesario para efectuar cambios del programa de los
procesadores locales de campo. Se creará un protocolo propio basado en las
especificaciones de Modbus RTU y que si contemplará las necesidades para
multiproceso (es decir el poder direccionar a varios dispositivos).
75
1.4.5.2 Protocolo Modbus
Para este proyecto se ha escogido el protocolo Modbus por la facilidad de aplicarlo a
nuestras existencias (usa UART : RS232 ,422 o 485) y no necesitar ningún otro
hardware específico. Cumple la EN 1434-3 y la IEC 870-6. Las características
generales se han descrito con anterioridad ,ahora a continuación se detallan todos los
aspectos principales relacionados con dicho protocolo.
Introducción al protocolo Modbus
Los controladores programables Modicon pueden comunicarse entre ellos o con otros
equipos sobre una gran variedad de redes. Las redes industriales que soportan son:
la Modicon Modbus y la Modbus Plus; y como redes estándar soportan Ethernet y
MAP. Para acceder a dichas redes se incorporan puertos en los controladores o se
incluyen adaptadores de redes, módulos o gateways de que dispone Modicon. Para
los vendedores de equipos originales de fabrica ,los programas Modicon Modconnect
están
disponibles para redes cerradas como Modbus Plus en un diseño de producto
propietario.
El lenguaje empleado por los controladores Modicon es el protocolo Modbus. Este
protocolo define una estructura de mensaje que los controladores reconocen y usan,
sin
importar el tipo de red sobre el que se comunican. Describe el proceso que un
controlador usa para acceder a otro dispositivo, como debe responder a peticiones de
otros equipos y como han de ser detectados y informar los errores. Establece un
formato común para la base y los contenidos de los campos del mensaje.
El protocolo Modbus provee el estándar interno que los controladores Modicon usan
para pasar mensajes. Durante las comunicaciones en una red Modbus , el protocolo
determina como cada controlador conoce su propia dirección , reconoce que el
mensaje recibido esta dirigido a el, determina el tipo de acción que ha de tomar y
extrae cualquier dato o información contenida en el mensaje. Si el mensaje necesita
contestación ,el controlador construirá el mensaje de respuesta y lo enviara usando el
protocolo Modbus.
76
Sobre otras redes, los tramas de información (Frames) de esa red ,contendrán al
mensaje en protocolo Modbus dentro de su estructura. Por ejemplo, los controladores
Modicon de red para Modbus Plus o MAP, con aplicaciones de librerías de programas
y "drivers" asociados ,proveen la conversión entre el mensaje en protocolo Modbus a
introducir y los protocolos específicos de tramas que usan estas redes para
comunicar sus dispositivos. Esta conversión también resuelve las direcciones de
nodo, enrutamiento y métodos específicos usados por cada tipo de red para la
comprobación y corrección de errores . Por ejemplo la dirección del dispositivo
Modbus contenida en el protocolo Modbus será convertida en una dirección de nodo
antes de transmitir los mensajes.
Aplicación del protocolo Modbus
Esta figura muestra como deben ser interconectados los equipos en un conjunto de
redes que emplean diferentes técnicas de comunicación. En la transacción de
mensajes,
el protocolo Modbus fijado en la estructura de tramas de cada red provee el lenguaje
común por el cual los dispositivos pueden intercambiar datos.
Transmisiones en redes Modbus
Los puertos estándar Modbus en los controladores Modicon usan una interface serie
compatible con RS232C. Dichos controladores pueden ir directamente conectados a
77
la red o vía módems. Se comunican entre ellos usando la técnica
maestro/esclavo
,en la cual solo un dispositivo (el maestro) puede iniciar las transmisiones (preguntas).
Los otros dispositivos (esclavos) responden enviando los datos solicitados al maestro,
o actuando según la acción que les llegue. Normalmente los dispositivos maestro
incluyen procesadores anfitriones (host) y paneles programables ,mientras que los
esclavos llevan controladores programables. El maestro puede direccionar de manera
individual o por difusión (broadcast) los esclavos. Los esclavos devuelven el mensaje
(respuesta) a
las solicitudes individuales. No se envía respuesta a los mensajes realizados por
difusión general.
El protocolo Modbus establece el formato para las solicitudes del maestro ,colocando
en el la dirección del equipo a enviar el mensaje o si es de difusión general, un código
de función definiendo la acción solicitada ,cualquier dato para ser enviado y un campo
de comprobación de errores.
El mensaje de respuesta del esclavo esta también construido usando el protocolo
Modbus. Contiene campos para confirmar la acción tomada, cualquier dato para ser
devuelto y un campo de comprobación de errores. Si ocurre algún error en el mensaje
recibido o el esclavo no esta disponible para ejecutar la acción solicitada ,el esclavo
enviara un mensaje de error como respuesta.
Transmisiones en otro tipo de redes
Algunos de los modelos de controladores Modicon, tienen además de sus
capacidades Modbus estándar la de comunicar sobre redes Modbus Plus usando
puertos incorporados o adaptadores; y sobre redes MAP usando adaptadores de red.
En estas redes, los controladores se comunican usando la
técnica de igual a igual,
en la cual cualquier controlador puede iniciar transmisiones con otros controladores.
Así que un controlador puede trabajar como esclavo o maestro en diferentes
transmisiones.
Múltiples rutas internas son suministradas para permitir el procesamiento concurrente
de transmisiones en modo esclavo o maestro.
En los mensajes ,el protocolo Modbus continua aplicando el principio maestro/esclavo
aunque el método de la red sea de igual a igual .Si un controlador origina un mensaje,
lo hace como un dispositivo maestro y espera la respuesta de un dispositivo esclavo.
Igual que cuando un controlador recibe un mensaje ,envía una respuesta al
controlador origen.
El ciclo de Pregunta-Respuesta
78
Ciclo de Pregunta/Respuesta en modo Maestro-Esclavo
Pregunta del maestro
Dirección del esclavo
Codigo de función
función
Datos de 8 bytes
bytes
Comprobación de error
Dirección del esclavo
Código de
Datos
de
8
Comprobación de error
Respuesta del
esclavo
La Pregunta o Solicitud
El código de función en la pregunta le indica al dispositivo esclavo direccionado que
tipo de acción debe llevar a cabo. Los bytes de datos contienen cualquier información
que el esclavo necesite para realizar su función. Por ejemplo ,el código de función 03
indicará al esclavo que lea los registros de retención y responda con sus contenidos.
El campo de datos deberá contener la información indicando al esclavo desde que
registro empezar y cuantos registros ha de leer. El campo de error provee de un
método para validar la integridad del contenido del mensaje.
La Respuesta
Si el esclavo envía una respuesta normal, el código de función en la respuesta es un
eco del código de función de la pregunta o solicitud. Los bytes de datos contienen los
datos recogidos por el esclavo, como los valores o estados de los registros. Si ocurre
algún error , el código de función se modifica para indicar que la respuesta es una
respuesta de error y los bytes de datos contienen un código que describe el error. El
campo de comprobación de error permite al maestro confirmar que el contenido del
mensaje es valido.
Dos modos de transmisión serie
Los controladores pueden ser configurados para comunicar en redes estándar
Modbus usando dos modos de transmisión distintos: ASCII o RTU. Los usuarios
seleccionan el modo deseado ,además de los parámetros de comunicación del puerto
serie (velocidad de transmisión de datos, paridad, etc.) durante la configuración de
cada controlador. El modo y los parámetros serie debe ser los mismo para todos los
dispositivos de la red Modbus.
La selección del modo ASCII o RTU pertenece solo a las redes estándar Modbus.
Define el contenido de bit de los campos del mensaje transmitidos en serie en estas
redes. Determina como irá codificada y empaquetada la información en los campos
del mensaje. En otras redes como MAP y Modbus Plus ,los mensajes Modbus se
colocan en tramas que no están relacionados con el tipo de transmisión serie. Por
79
ejemplo ,una petición de lectura de los registros de retención puede ser manipulada
entre dos controladores en Modbus Plus sin considerar la configuración establecida
de cada puerto Modbus serie de los controladores.
Modo ASCII Cuando los controladores están configurados para comunicarse en una
red Modbus usando el modo ASCII (American Standard Code for Information
Interchange) ,cada 8-bit (byte) en un mensaje es enviado como dos caracteres
ASCII. La principal ventaja de este modo es que permite que transcurran intervalos de
tiempo de más de 1 segundo entre caracteres sin causar un error.
Sistema Codificador:
- Hexadecimal, caracteres ASCII 0 ... 9, A ... F
- Un carácter hexadecimal contenido en cada carácter ASCII del mensaje.
Bits por Byte:
- 1 bit de arranque.
- 7 bits de datos, el menos significante se envía primero.
- 1 bit de paridad par/impar o 0 bits sin paridad.
- 1 bit de parada si se usa paridad 2 bits si no se usa paridad.
Campo de comprobación de error:
-LRC (Longitudinal Redundancy Check) comprobación de errores por redundancia
longitudinal
Modo RTU Cuando los controladores están configurados en una red Modbus
usando el modo RTU (Remote Terminal Unit) , cada 8-bit (byte) en un mensaje
contiene dos números hexadecimales de 4 bits. La principal ventaja de este modo es
que su mayor densidad de carácter permite una mayor eficiencia (througput) que el
modo ASCII para la misma velocidad de transmisión. Cada mensaje debe ser
transmitido en una cadena continua.
Sistema Codificador:
- 8-bit binarios, hexadecimal 0 ... 9, A ... F
- dos caracteres hexadecimales contenidos en cada campo de 8-bit del mensaje.
Bits por Byte:
- 1 bit de arranque.
- 8 bits de datos, el menos significante enviado el primero.
- 1 bit para paridad par/impar 0 bit si no se emplea paridad.
- 1 bit de parada si se emplea paridad o 2 si no se usa.
Campo de comprobación de error:
- CRC (Cyclical Redundancy Check) comprobación cíclica de redundancia.
80
Trama de los mensajes Modbus
En cualquiera de los dos modos serie de transmisión (ASCII o RTU), un mensaje
Modbus se coloca por el equipo transmisor en un trama, que tiene un patrón conocido
al
principio y al final de este. Esto permite a los dispositivos receptores empezar al
principio del mensaje ,leer la porción de dirección y determinar que dispositivo es
direccionado (o todos los equipos si el mensaje es una difusión general) y saber
cuando el mensaje esta completo. Mensajes parciales pueden ser detectados y los
errores pueden ser enviados como respuesta.
En redes como MAP o Modbus Plus, el protocolo de red manipula la trama de los
mensajes con delimitadores al principio y fin que son específicos de la red. Estos
protocolos también manejan los envíos a los dispositivos de destino ,haciendo
innecesario el campo Modbus de direcciones fijado en el mensaje ,para la actual
transmisión. La dirección Modbus es convertida en una dirección de nodo de red y
enrutada por el controlador que la origino o por su adaptador de red.
Trama ASCII En modo ASCII ,los mensajes empiezan con dos puntos (:),carácter
ASCII 0x3A en hexadecimal, y acaba con un salto y retorno de línea(CR +
LF),caracteres ASCII 0x0D y 0x0A en hexadecimal.
Los posibles caracteres transmitidos por los otros campos son hexadecimales 0 ... 9,
A... F. Los dispositivos conectados a la red supervisan el bus de la red continuamente
esperando el carácter (:). Cuando se recibe, cada equipo decodifica el siguiente
campo (campo de direcciones) para averiguar si se trata de su dirección. Puede pasar
intervalos de mas de 1 segundo entre caracteres durante el mensaje. Si transcurre un
intervalo mayor ,el dispositivo receptor asume que a ocurrido un error.
A continuación se muestra un típico trama de mensaje ASCII ,con el número de
caracteres que ocupa cada campo.
Inicio
:1
Direcc.
2
Func.
2
Datos
LRC
Fin
Nx2
2
CR+LF 2
(* Nota:
Con los controladores 584 y 984A/B/X ,un mensaje ASCII puede
normalmente terminar después del campo LRC sin ser enviados posteriormente los
caracteres CR+LF. Entonces debe al menos transcurrir un intervalo de 1 segundo. Si
esto ocurre ,el controlador asume que el mensaje termino correctamente. )
Trama RTU En el modo RTU ,los mensajes empiezan con un intervalo en silencio de
al menos el tiempo de 3'5 caracteres. Esto es fácilmente implementado como un
múltiplo del tiempo de carácter a la velocidad de transmisión a la que esta siendo
usada la red (mostrado como T1-T2-T3-T4 en la figura de mas adelante). Entonces el
primer campo transmitido es la dirección del equipo. Los posibles caracteres
81
transmitidos para todos los campos son los números hexadecimales 0 ... 9, A ... F.
Los dispositivos conectados a la red examinan el bus de la red continuamente
,incluyendo durante los intervalos de silencio.
Cuando el primer campo (el de direcciones) se recibe, cada equipo lo decodifica para
averiguar si se refiere a él. A continuación del ultimo carácter transmitido ,un intervalo
similar de al menos el tiempo de 3'5 caracteres indica el final del mensaje. Un nuevo
mensaje puede empezar después de este intervalo. El mensaje de la trama debe ser
transmitido como una cadena continua. Si transcurre un intervalo de silencio de un
tiempo de más de 1'5 caracteres antes de completar la trama ,el dispositivo receptor
rechaza el mensaje incompleto y asume que el próximo byte será el campo de
dirección de un nuevo mensaje.
Igualmente , si un nuevo mensaje empieza antes de un tiempo menor que el de 3'5
caracteres ,a continuación de un mensaje previo ,el equipo receptor lo considerara
una continuación del mensaje anterior. Esto dará un error ,ya que el valor final del
campo CRC no será válido. A continuación se muestra el trama de mensaje típico en
modo RTU ,con el número de bytes que ocupa cada campo.
Inicio
t1..t4
Direcc.
2
Func.
2
Datos
CRC
Fin
Nx1
2
t1..t4
Manejo del campo de dirección
El campo de dirección del arco del mensaje contiene dos caracteres (ASCII)o 8 bits
(RTU).Las direcciones validas de los esclavos están en el rango de 0 a 247 en
decimal.
Los dispositivos individuales esclavos están en el rango de 1 a 247 y para difusión
(para todos) la dirección es la 0. El maestro direcciona a los esclavos colocando la
dirección del dispositivo a preguntar en el campo de dirección del mensaje. Cuando el
esclavo envía su respuesta coloca su dirección en el campo de dirección de la
respuesta para permitir al maestro saber quien le responde. La dirección 0 es
reconocida por todos los esclavos. Cuando se usa el protocolo Modbus en redes de
nivel superior la difusión (broadcast) no esta permitida o es reemplazada por otros
métodos. Por ejemplo, Modbus Plus usa una base de datos global compartida que
puede ser actualizada en cada rotación del testigo.
Manejo del campo de función
El campo de código de función en el trama de un mensaje contiene 2 caracteres
(ASCII) o 8 bits (RTU). Los códigos
validos van de 1 a 255 en decimal.
De estos ,algunos códigos son aplicables a todos los controladores Modicon ,
mientras que otros códigos solo se aplican en ciertos modelos y otros están
reservados para un uso futuro.
82
Cuando un mensaje es enviado desde un maestro a un
esclavo
el
campo
código de función indica que acción debe realizar. Ejemplos de funciones a realizar:
-leer el estado des/activado de un grupo discreto de relés o entradas. -leer el
contenido de un grupo de registros. -leer el diagnostico del estado del esclavo.
-escribir a determinados relés o registros. -permitir la carga, grabación o verificación
del programa dentro del esclavo.
Cuando el esclavo responde al maestro ,utiliza el campo de código de función para
indicar una respuesta normal (libre de errores) o que algún tipo de error ha ocurrido
(denominada respuesta a una excepción) .Para una respuesta normal simplemente
hace el eco al código de función original. Mientras que para una respuesta a una
excepción ,el esclavo devuelve un código equivalente al original pero con el bit mas
significativo activado a un '1' lógico.
Por ejemplo, un mensaje de un maestro a un esclavo para leer un grupo de registros
de retención tendría el siguiente código de función:
0000 0011
(Hexadecimal 03)
Si el esclavo ejecuta la acción solicitada si error ,devuelve el mismo código en su
respuesta. Si ocurre una excepción ,devuelve:
1000 0011
(Hexadecimal 83)
Además de la modificación del código de función en respuesta a una excepción, el
esclavo coloca un código único en el campo de datos del mensaje de respuesta. Esto
indica al maestro que tipo de error ha ocurrido ,o la razón de la excepción.
El programa de aplicación del dispositivo maestro tiene la responsabilidad de manejar
la respuesta a excepciones. El procedimiento mas usual es enviar la subsiguiente
recuperación del mensaje para intentar diagnosticar los mensajes del esclavo y
notificar los operadores empleados.
Contenidos del campo de datos
El campo de datos esta construido usando grupos de 2 dígitos hexadecimales en el
rango de 0x00 a 0xFF en hexadecimal. Estos pueden ser construidos a partir de un
par de caracteres ASCII o de un carácter RTU ,de acuerdo con el modo de
transmisión serie de la red.
El campo de datos de los mensajes de un maestro a un esclavo contiene información
adicional ,la cual debe ser usada por el esclavo para realizar acción definida por el
código de función. Esto puede incluir parámetros como direcciones discretas y de
registros, la cantidad de parámetros manejados y la cuenta del numero actual de
bytes en dicho campo de datos.
Por ejemplo, si el maestro solicita al esclavo leer un grupo de registros de retención
(código de función 03),el campo de datos especifica el registro de inicio y cuantos
registros han de ser leídos. Si el maestro escribe a un grupo de registros en el esclavo
83
(código de función 10), el campo de datos especifica el registro de comienzo ,cuantos
registros ha de escribir ,la cuenta de bytes de datos que siguen a continuación en el
campo de datos y los datos a ser escritos en los registros.
Si no se produce errores ,el campo de datos de una respuesta del esclavo al maestro
contiene los datos solicitados. Si ocurre un error ,el campo contiene un código de
excepción que la aplicación maestro puede usar para determinar la siguiente acción a
realizar.
El campo de datos puede no existir en ciertos tipos de mensajes. Por ejemplo en una
solicitud de un maestro a un esclavo a responder con su informe de eventos en las
comunicaciones (código de función 0B) ,el esclavo no requiere información adicional.
El propio código de función especifica la acción a realizar.
Campo de comprobación de errores
En redes Modbus se emplean dos métodos de comprobación de errores. El contenido
del campo de comprobación de error depende del método usado.
Cuando se emplea el modo ASCII para los caracteres de la trama ,el campo de
comprobación de error contiene 2 caracteres ASCII. Los caracteres de comprobación
de error son el resultado del calculo de una comprobación longitudinal de redundancia
LRC que se lleva a cabo sobre el contenido del mensaje, exceptuando el carácter de
principio de trama y los caracteres de final de esta. Los caracteres LRC son añadidos
al mensaje como el ultimo campo antes de los caracteres CR+LF de fin de trama.
Cuando se emplea el modo RTU para los caracteres de la trama ,el campo de
comprobación de error contiene un valor de 16 bits implementado en 2 grupos de 1
byte cada uno. El valor de comprobación es el resultado de una comprobación cíclica
redundante CRC realizada sobre el mensaje enviado. El campo de CRC se añade en
el campo final del mensaje. Cuando se realiza esto el byte de menor peso se añade
primero ,seguido del byte de mayor peso.
Transmisión serie de caracteres
Cuando los mensajes son transmitidos en una red serie estándar Modbus ,cada
carácter o byte se envía en este orden (derecha a izquierda): Bit menos significativo
(LSB) ... Bit mas significativo (MSB).
Con trama de carácter ASCII la secuencia de bit es:
-con paridad
Inicio
1
2
3
84
4
5
6
7
Paridad
Fin
-sin paridad
Inicio
1
2
3
4
5
6
7
Fin
Fin
Con trama de carácter RTU la secuencia de bit es:
-con paridad
Inicio
1
2
3
4
5
6
7
8
Paridad
Fin
Inicio
1
2
3
4
5
6
7
8
Fin
Fin
-sin paridad
Métodos de comprobación de error
Las redes serie estándar Modbus usan dos tipos de comprobación de error:
- Comprobación de paridad (par o impar) puede opcionalmente ser aplicada a cada
carácter.
- Comprobación de trama (LRC o CRC) que se aplica a todo el mensaje.
Tanto la comprobación de carácter como la comprobación de mensaje de trama son
generadas en el dispositivo maestro y aplicadas al contenido del mensaje antes de la
transmisión. El dispositivo esclavo comprueba cada carácter y el mensaje de trama
durante la recepción. El maestro se configura por el usuario para esperar un
determinado intervalo "timeout" (respuesta fuera del tiempo predeterminado) antes de
detener la transmisión si no recibe respuesta alguna. Este intervalo se establece
como el suficiente para que cualquier esclavo responda con normalidad. Si el esclavo
detecta un error de transmisión ,no enviara respuesta al maestro. Así que cuando el
tiempo de espera expire permitirá al programa del maestro tratar el error.
Nota: Un mensaje enviado a un esclavo inexistente provocara un "timeout" (no se
recibió respuesta en el tiempo máximo predeterminado).
Otras redes como MAP o Modbus Plus usan otro tipo de comprobación del contenido
del mensaje de la trama en un nivel superior al Modbus. En estas redes, el campo de
comprobación LRC o CRC del mensaje Modbus no es aplicable. En el caso de un
error de transmisión ,los protocolos de comunicación especifican para estas redes
notificar al dispositivo origen que ha ocurrido un error y permitirle que lo reintente o
85
detenerlo de acuerdo a como se había configurado. Si el mensaje se envía ,pero el
dispositivo esclavo no puede responder ,ocurrirá un error de tiempo de espera
agotado que será detectado por el programa del maestro.
Comprobación de Paridad
Los usuarios pueden configurar los controladores para comprobación de paridad par
o
impar ,o sin paridad. Esto determina como el bit de paridad es activado en cada
carácter.
Si se especifica paridad par o impar ,la cantidad de bits a '1' de cada carácter serán
contados (7 bits de datos para el modo ASCII , o 8 para RTU). El bit de paridad se
pondrá a 0 o 1 según el numero total mas este bit es par o impar.
Por ejemplo, estos 8 bits de datos de un carácter RTU de la trama:
1100 0101
El numero total de bits a '1' es 4. Si la paridad es par el bit de paridad ha de ser 0
,haciendo que el numero total de bits a 1 sea un numero par (4).Si la paridad es impar
,el bit de paridad ha de ser '1' ,para que así el numero total de bits a '1' sea un numero
impar (5).
Cuando el mensaje se transmite ,el bit de paridad es calculado y aplicado a la trama
en cada carácter. El dispositivo receptor cuenta la cantidad de bits a '1' y si no
coincide con la paridad configurada dará error (todos los dispositivos de una red
Modbus deben ser configurados para usar el mismo método de comprobación de
paridad).
La comprobación de paridad solo puede detectar un error si un numero impar de bits
son modificados en una carácter de trama durante la transmisión. Por ejemplo, si se
emplea paridad impar ,y dos bits a '1' de un carácter que tenía tres bits a '1' ,el
resultado sigue siendo impar.
Si no se especifica paridad ,no se transmite bit de paridad y se añade un bit mas de
parada.
Comprobación LRC
En modo ASCII , los mensajes incluyen un campo de comprobación de error basado
en un método LRC. El campo LRC comprueba el contenido del mensaje ,excluyendo
los patrones de inicio y fin de trama. Se aplica sin importar si se usa o no el método
de comprobación de paridad para cada carácter.
El campo LRC es un solo byte ,que contiene un valor de 8 bits binario. El valor LRC
es calculado por el dispositivo emisor ,el cual lo incluye en el mensaje. El equipo
receptor calcula el LRC durante la recepción del mensaje y compara su valor
86
calculado con el actual valor recibido en el campo LRC. Si los dos valores son
distintos indica que hay errores en el mensaje.
El LRC se calcula añadiendo sucesivamente todos los bytes del mensaje descartando
los acarreos y entonces haciendo el complemento a 2 del resultado. Esto se realiza
en contenido del campo de mensaje ASCII ,excluyendo los patrones de inicio y fin de
trama.
Comprobación CRC
En modo RTU los mensajes incluyen un campo de comprobación de errores basado
en el CRC. El campo CRC comprueba el contenido de todo el mensaje. Se aplica sin
tener en cuenta si se emplea o no el método de comprobación de paridad de cada
carácter. El campo CRC consta de 2 bytes ,contiene un valor de 16 bits en binario. El
valor CRC es calculado por el dispositivo emisor ,el cual lo incluye en el mensaje. El
equipo receptor recalcula el CRC durante la recepción del mensaje y compara el valor
calculado con el actual valor recibido en el campo CRC. Si ambos valores difieren
indica que hay errores.
El CRC comienza precargando primero un registro de 16 bits todo a '1'. Entonces un
proceso comienza a aplicarsucesivos bytes del mensaje al contenido del registro.
Sólo los 8 bits de datos de cada carácter son usados para generar el CRC. Los bits
de arranque y parada no se aplican al CRC.
Durante la generación del CRC, cada carácter de 8 bits se le aplica una XOR con el
contenido del registro. Entonces el resultado es desplazado en la dirección del bit
menos significativo (LSB) , al bit mas significativo (MSB) se le asigna un '0' y así
consecutivamente. El LSB extraído se examina ,si era un '1' ,al registro entonces se le
aplica una XOR con el valor prefijado. Si el LSB era un '0', no se le aplica XOR.
Este proceso se repite hasta que se hayan realizado 8 desplazamientos hacia la
derecha del registro. Después del ultimo desplazamiento ,a los 8 bits siguientes se les
aplica una XOR con el valor actual del registro ,y el proceso se repite otras ocho
veces. El contenido final del registro ,después de que hayan sido aplicados todos los
bytes del mensaje es el valor CRC. Cuando el CRC se agrega al mensaje, el byte de
menor peso se añade primero y luego el byte de mayor orden.
87
1.4.5.2.1 Formatos de las funciones Modbus
Nota: A no ser que se especifique lo contrario los valores numéricos que se muestran
en el texto están expresados en decimal, mientras que los valores expresados en los
campos del mensaje de las figuras están expresados en hexadecimal.
Direcciones de datos en mensajes Modbus
Todas las direcciones de datos en los mensajes Modbus están referenciadas a cero.
La primera aparición de un parámetro dato esta direccionado como parámetro
numero 0. Por ejemplo:
Relé 1 en un controlador programable esta direccionado como relé 0000 en el campo
de
direcciones de datos en un mensaje Modbus.
Relé 127 decimal esta direccionado como relé 007E hex.(126 decimal).
Registro de retención 40001 esta direccionado como registro 0000 hex(001 decimal)
en el campo de direcciones de datos en el mensaje.
El campo de código de función especifica una operación sobre registro de retención.
Por lo tanto la referencia 4x es implícita.
Registro de retención 40108 esta direccionado como registro 006B hex ( 107 decimal
88
).
Contenido del campo en mensajes Modbus
Las siguientes tablas muestran ejemplos de preguntas o solicitudes Modbus y la
respuesta normal (libre de errores). Ambos ejemplos muestran el contenido del
campo en hexadecimal y también muestra como ha de ser incluido el mensaje en la
trama según el modo ASCII o RTU. El maestro solicita la información del esclavo
dirección 06 de tres de sus registros de retención 40108 ... 40110.
Nota: El mensaje especifica la dirección del registro de inicio como 0107 (006B hex).
El valor 63 hex. se envía como un carácter de 8 bits en modo RTU (01100011). El
mismo valor enviado en modo ASCII requiere 2 bytes, para el ASCII 6 (0110110) y el
3 (0110011). El campo de cuenta de bytes cuenta cada parámetro como 8 bits ,ya
sea el método de carácter de trama ASCII o RTU.
Solicitud/Pregunta:
ASCII
Cabecera
RTU
:
Dirección
06
06
0000 0110
Función
03
03
0000 0011
dirección
inicio Hi
00
00
0000 0000
dirección inicio Lo
6B
6B
0110 1011
Nºregist. Hi
00
00
0000 0000
Nºregist. Lo
01
01
0000 0001
Comprobación
error
LRC
2char
CRC
16bits
Trailer
CR+LF
nº total Bytes
17
Respuesta:
89
8
ASCII
Cabecera
RTU
:
Dirección
06
06
0000 0110
Función
03
03
0000 0011
Nº bytes
02
02
0000 0010
dato1 Hi
00
00
0000 0000
dato1 Lo
2B
2B
0010 1011
Comprobación
error
LRC
2char
CRC
16bits
Trailer
CR+LF
nº total Bytes
15
7
El esclavo responde con el eco del código de la función, indicando que es una
respuesta normal. El campo de bytes contados especifica cuantos datos de 8 bits se
envían al maestro. Muestra la cuenta de bytes que siguen de datos, tanto para ASCII
como RTU. Con ASCII, este valor es la mitad de los caracteres de la cuenta en ASCII
.En ASCII, el valor de cada cuatro bits en hexadecimal requiere un carácter ASCII ,así
que dos caracteres ASCII deben seguir en el mensaje conteniendo cada parámetro
de 8 bits de datos.
Campo de cuenta de bytes
Cuando se construyen respuestas en registros de retención, se utiliza un valor de
cuenta de bytes que equivale al numero de datos de 8 bits del mensaje. El valor no
tiene en cuenta los contenidos de otros campos, incluyendo el de cuenta de bytes.
Contenidos de campo en Modbus Plus
Los mensajes Modbus enviados en una red Modbus Plus están incluidos en el nivel
de control lógico de enlace de trama (LLC). Los campos del mensaje Modbus
consisten en 8 bits ,similar en las tramas usadas con Modbus RTU.
El campo de dirección del equipo esclavo se convierte en una ruta Modbus Plus para
enviar datos. El campo CRC no se envía en el mensaje Modbus porque seria
redundante a
la comprobación CRC realizada en el HDLC (Control de enlace
de datos de nivel alto). El resto del mensaje permanece con el formato estándar serie.
El software de aplicación (por ejemplo bloques MSTR en controladores o Modcom III
en los anfitriones) maneja la trama del mensaje en un paquete de red.
90
La figura 7 muestra como una solicitud de lectura de registros es introducida en una
trama para transmisión Modbus Plus.
1.4.5.2.2 Códigos de función
A continuación se detallan los códigos de función soportados por los controladores
Modicon (384 ,484 ,584 ,884 ,M84 ,984).
Las funciones 1 a 7 y 15 a 17 son soportadas por todos los controladores Modicon.
Las funciones 9 y 10 sólo las soporta el 484. La función 11 es soportada por el 384,
584 y 984. La función 21 sólo la soportan el 584 y el 984. Las funciones 18 a 20 son
soportadas por el 884 y el M84. Las funciones 22 y 23 sólo las soporta el M84. Por
último las funciones 12 a 14 son soportadas únicamente por el M84.
Lectura del estado de relés (01)
Lee el estado des/activo de salidas discretas (0x hace referencia a relés) en el
esclavo. No soporta la
difusión.
Pregunta
El mensaje pregunta especifica el relé de comienzo y la
cantidad de relés que
han de ser leídos. Los relés son direccionados empezando desde 0 relés, de 1º .. 16º
son direccionados como 0 ... 15.A continuación se muestra un ejemplo de pregunta
para leer los relés del 20 .. 56 (ambos incluidos) del esclavo numero 17:
91
Campo
Dirección Esclavo 11
Función
01
Dirección Inicio Hi 00
Dirección Inicio Lo 13
Nº de relés Hi
Nº de relés Lo
25
CRC/LRC
00
Respuesta
El estado de los relés en el mensaje de respuesta se empaqueta como un relé por bit
del campo de datos .El estado se indica como: 1 = ON (activado) , 0 = OFF
(desactivado). El LSB (bit menos significativo) del primer byte de datos contiene el
relé de menor orden direccionado en la pregunta. Los otros relés le siguen hacia el
MSB (bit mas significativo) de este byte y desde el LSB hacia el MSB en los
subsiguientes bytes. Si la cantidad de relés devueltos no es múltiplo de 8 ,el resto de
bits en el byte de datos ultimo se rellena con ceros (hacia el MSB).El campo del
contador de numero de bytes especifica la cantidad de bytes completos de datos.
Un ejemplo de respuesta seria el siguiente:
Campo
Dirección Esclavo
Función
Nº Bytes
Dato (27..20)
Dato (35..28)
Dato (43..36)
Dato (51..44)
Dato (56..52)
CRC/LRC
11
01
05
CD
6B
B2
0E
1B
El estado de los relés 27 ... 20 se muestra como el valor CD hex. o binario 1100 1101.
El relé 27 es el MSB de este byte, y el relé 20 es el LSB. De izquierda a derecha el
estado de los relés 27 ... 20 es ON-ON-OFF-OFF-ON-ON-OFF -ON.
Por convención, los bits dentro de un byte se muestran con el MSB a la izquierda y el
LSB a la derecha. Así que los relés en el primer byte van del 27 al 20, de izquierda a
derecha. El próximo byte tiene los relés del 35 al 28, de izquierda a derecha.
Los bits son transmitidos en serie de LSB a MSB: 20 . . . 27, 28 . . . 35. En el ultimo
92
byte de datos ,el estado de los relés 56 ..52 se muestra como el valor 1B hex. o
binario 0001 1011. El relé 56 esta en el 4º bit desde la izquierda y el relé 52 es el LSB
de este byte. El estado de los relés 56 ... 52 es: ON-ON-OFF-ON-ON.
Nota: Los tres bits restantes hacia el MSB son rellenados con ceros.
Leer el estado de las entradas (02)
Lee el estado des/activado de entradas discretas (1x hace referencia a las
entradas)en el esclavo . No soporta difusión.
Pregunta
El mensaje pregunta especifica la entrada de inicio y la cantidad de entradas a leer.
Las entradas estas direccionadas empezando desde 0 entradas ,de la 1ª a 16ª
entrada son direccionadas como 0 ... 15. A continuación de muestra un ejemplo de
solicitud de lectura de entradas de la 10197 a la 10218 del equipo esclavo 17:
Campo
Dirección Esclavo
Función
Dirección Inicio Hi
Dirección Inicio Lo
Nº de entradas Hi
Nº de entradas Lo
CRC/LRC
11
02
00
C4
00
16
Respuesta
El estado de las entradas en el mensaje de respuesta se empaqueta como una
entrada por bit del campo de datos. El estado se indica como: 1 = ON; 0 = OFF. El
LSB del primer byte de datos contiene la entrada de menor orden direccionada en la
pregunta. Las otras entradas la siguen hacia el MSB (bit mas significativo) de este
byte y desde el LSB hacia el MSB en los subsiguientes bytes. Si la cantidad de
entradas devueltas no es múltiplo de 8 ,el resto de bits en el byte de datos ultimo se
rellena con ceros (hacia el MSB).El campo del contador de numero de bytes
especifica la cantidad de bytes completos de datos.
Respuesta a la petición anterior:
Campo
Dirección Esclavo
Función
Nº Bytes
Dato (10204..10197)
Dato (10212..10205)
Dato (10218..10213)
CRC/LRC
11
02
03
AC
6B
35
El estado de las entradas 10204 ... 10197 se muestra como el valor AC hex. o binario
93
1010 1100. La entrada 10204 es el MSB de este byte y la entrada 10197 es el LSB.
De
izquierda a derecha ,el estado de las entradas 10204 ...
10197 es: ON- OFFON- OFF- ON-ON- OFF-OFF.
El estado de las entradas 10218 ... 10213 se muestra como el valor 35 hex. o binario
0011 0101. La entrada 10218 esta en la tercera posición desde la izquierda y la
entrada 10213 es el LSB. El estado de las entradas 10218... 10213 es: ON -ON -OFF
-ON-OFF-ON.
Nota: Los tres bits restantes hacia el MSB son rellenados con ceros.
Lectura de los registros de retención (03)
Lee el contenido binario de los registros de retención (referenciado como 4x) en el
esclavo. No soporta difusión.
Pregunta
El mensaje pregunta especifica el registro de inicio y la cantidad de registros a leer.
Los registros son
direccionados empezando desde 0 del 1º a 16º registros son
direccionados como 0 ... 15.
A continuación de muestra un ejemplo de solicitud de lectura de registros del 40108 al
40110 del dispositivo esclavo 17:
Campo
Dirección Esclavo
Función
Dirección Inicio Hi
Dirección Inicio Lo
Nº de registros Hi
Nº de registros Lo
CRC/LRC
11
03
00
6B
00
03
Respuesta
El registro de datos en el mensaje de respuesta es empaquetado como dos bytes por
registro ,con su contenido en binario justificado a la derecha dentro de cada byte.
Para cada registro ,el primer byte contiene la parte alta y el segundo la parte baja.
Los Datos son examinados en el esclavo a una velocidad de 125 registros por
escrutinio para los controladores 984-X8X (984-685, etc),y a la velocidad de 32
registros por escrutinio para los otros controladores. La respuesta es enviada cuando
los datos están completamente ensamblados. Aquí se propone un ejemplo de
respuesta a la pregunta:
Campo
94
Dirección Esclavo
Función
Nº Bytes
Dato (40108)
Dato (40108)
Dato (40109)
Dato (40109)
Dato (40110)
Dato (40110)
CRC/LRC
11
03
06
02
2B
00
00
00
64
El contenido del registro 40108 se muestra como un valor de 2 bytes (02 2B hex. o
555 decimal). El contenido de los registros 40109 y 40110 son 00 00 y 00 64 hex. o 0
y 100 decimal.
Lectura de los registros de entrada (04)
Lee el contenido binario de los registros de entrada (referenciado como 3x) en el
esclavo. No soporta la difusión.
Pregunta
El mensaje solicitante especifica el registro de inicio y la cantidad de registros a ser
leídos. Los registros son direccionados empezando desde 0 del 1º a 16º registros son
direccionados como 0 ... 15.
A continuación de muestra un ejemplo de solicitud de lectura del registro de entrada
30009 del dispositivo esclavo 17:
Campo
Dirección Esclavo
Función
Dirección Inicio Hi
Dirección Inicio Lo
Nº de registros Hi
Nº de registros Lo
CRC/LRC
11
04
00
08
00
01
Respuesta
El registro de datos en el mensaje de respuesta es empaquetado como dos bytes por
registro ,con su contenido en binario justificado a la derecha dentro de cada byte.
Para cada registro ,el primer byte contiene la parte alta y el segundo la parte baja.
Los Datos son examinados en el esclavo a una velocidad de 125 registros por
escrutinio para los controladores 984-X8X (984-685, etc),y a la velocidad de 32
registros por escrutinio para los otros controladores. La respuesta es
enviada
cuando los datos están completamente ensamblados.
Aquí se propone un ejemplo de respuesta a la pregunta:
95
Campo
Dirección Esclavo
Función
Nº Bytes
Dato (30009)
Dato (30009)
CRC/LRC
11
04
02
00
0A
El contenido del registro 30009 se muestra en un valor de dos bytes (00 0A hex. o 10
decimal).
Forzado de un único relé (05)
Fuerza un único relé (referencia 0x) a un estado activo o inactivo. Cuando es por
difusión ,la función fuerza la misma referencia de relé en todos los esclavos.
Nota: La función tendrá prioridad al estado de protección de la memoria del
controlador y el estado de inhabilitación del relé. El estado forzado permanecerá
valido hasta que la próxima lógica del controlador resuelva el estado del relé. El relé
permanecerá forzado si no esta programado en la lógica del controlador.
Pregunta
El mensaje solicitante especifica la referencia del relé a ser forzado. Los relés son
direccionados empezando desde el relé 0, el 1º es direccionado como 0. El solicitado
estado se especifica por una constante en el campo de datos de la solicitud .Un valor
de FF 00 hex. solicita que el relé se quede forzado en activo .Un valor de 00 00 hex.
solicita que el relé se quede forzado en inactivo.
Otros valores son ilegales y no afectan al relé. Un ejemplo de esto es el siguiente: se
pide forzar el relé 173 a un estado activo en el esclavo nº 17.
Campo
Dirección Esclavo
Función
Dirección Relé Hi
Dirección Relé Lo
Forzado
Hi
Forzado
Lo
CRC/LRC
11
05
00
AC
FF
00
Respuesta
La respuesta normal es un eco de la pregunta ,transmitido después de que haya sido
forzado el estado del relé.
Un ejemplo de respuesta seria el siguiente:
Campo
Dirección Esclavo
11
96
Función
Dirección Relé Hi
Dirección Relé Lo
Forzado
Hi
Forzado
Lo
CRC/LRC
05
00
AC
FF
00
Prefijar un único Registro (06)
Prefija un valor en un único registro de retención (referencia 4x). Cuando es por
difusión ,la función prefija la misma referencia de registro en todos los esclavos.
Nota: La función tendrá prioridad al estado de protección de la memoria del
controlador y el estado de inhabilitación del relé. El valor prefijado permanecerá valido
hasta que la próxima lógica del controlador resuelva el contenido del registro. El valor
prefijado del registro permanecerá así si no esta programado en la lógica del
controlador.
Pregunta
El mensaje solicitante especifica la referencia del registro a ser prefijado. Los registros
son direccionados empezando desde el 0, así el 1º es direccionado como 0. El
solicitado valor a prefijar se especifica en el campo de datos de la solicitud. Los
controladores M84 y 484 usan un valor binario de 10 bits ,con los 6 bits de mayor
peso a '0'. Todos los demás controladores usan valores de 16 bits.
Un ejemplo de solicitud de prefijar al valor 00 03 hex. el registro 40002 en el esclavo
nº 17 seria el siguiente:
Campo
Dirección Esclavo
Función
Dirección Registro Hi
Dirección Registro Lo
Dato a prefijar Hi
Dato a prefijar Lo
CRC/LRC
11
06
01
AC
00
03
Respuesta
La respuesta normal es un eco de la pregunta ,transmitido después de que haya sido
prefijado el valor del registro.
Un ejemplo de respuesta seria el siguiente:
Campo
Dirección Esclavo
11
Función
06
Dirección Registro Hi 01
97
Dirección Registro Lo AC
Dato a prefijar Hi
00
Dato a prefijar Lo
03
CRC/LRC
Leer los estados de excepciones (07)
Lee el contenido de 8 relés de estados de excepción dentro del controlador esclavo.
Ciertos relés tienen predefinidos trabajos o misiones en los diversos controladores.
Otros relés pueden ser programados por el usuario para mantener la información
sobre el estado del controlador ,por ejemplo si esta encendido, cabezales retraídos
,seguridades satisfechas ,existencia de condiciones de error o otras banderas (flags
,condiciones que solo pueden ser ciertas o falsas)de usuario definidas. No soporta
difusión.
La función provee de un método simple para acceder a esta información, porque las
referencias de los relés de excepciones son conocidas (no hay necesidad de
referencias de relés en esta función).
Las asignaciones predefinidas de los relés de excepciones son:
Controlador
Relé
Asignación
M84,184/38458
4 ,984
1..8
según el usuario
484
257
258..264
estado batería
según el usuario
884
761
762
763
764..768
estado batería
estado protección memoria
estado RIO
según el usuario
Pregunta
Un ejemplo de lectura del estado de las excepciones en el esclavo 17:
Campo
98
Dirección Esclavo
Función
CRC/LRC
11
07
Respuesta
La Respuesta normal contiene el estado de los 8 relés de estado de excepciones. Los
estados de los relés están empaquetados en un byte de datos, con un bit por relé. El
estado del relé de menor orden de referencia esta dentro del LSB del byte. Un
ejemplo de respuesta seria el siguiente:
Campo
Dirección Esclavo
Función
Dato de Relé
CRC/LRC
11
07
6D
En este ejemplo, el dato de relé es 6D hex. (0110 1101 binario). De izquierda a
derecha los relés están: OFF-ON-ON-OFF-ON-ON-OFF-ON.
El estado se muestra desde el mas alto al mas bajo de los relés direccionados.
Si el controlador es un 984, estos bits son los estados de los relés 8 ... 1. Si el
controlador es un 484, estos bits son los estados de los relés 264 ... 257. En este
ejemplo, el relé 257 esta ON, indicando que las baterías del controlador están
correctas.
Obtención del contador de eventos en comunicaciones (0B)
Devuelve la palabra (16 bits ) de estado y un contador de eventos de el contador de
eventos de las comunicaciones del esclavo. Primero la cuenta actual y después de
una serie de mensajes, el maestro puede determinar si los mensajes fueron
manejados de manera normal por el esclavo. No soporta difusión.
El contador de eventos del controlador se incrementa una vez cada mensaje
completado con éxito. No se incrementa para respuestas a excepción , comandos de
encuesta (poll) o obtención (fetch) de los comandos de contador de eventos.
El contador de eventos se puede borrar por la función de diagnostico (código 08) o
con una subfunción de restablecer comunicaciones (código 00 01) o bien de borrar
contadores y registro de diagnostico (código 00 0A).
Pregunta
Un ejemplo para solicitar la obtención del contador de eventos de comunicaciones del
99
esclavo nº 17:
Campo
Dirección Esclavo
Función
CRC/LRC
11
0B
Respuesta
La respuesta normal contiene 2 bytes para la palabra de estado y otros 2 bytes para
el contador de eventos. La palabra de estado debe estar todo unos (FF FF hex.) si un
comando de programa previo se esta todavía procesando por el esclavo (condición de
ocupado).Si no es así la palabra de estado es todo ceros.
Un ejemplo de respuesta seria el siguiente:
Campo
Dirección Esclavo
Función
Estado Hi
Estado Lo
Contador eventos Hi
Contador eventos Lo
CRC/LRC
11
0B
FF
FF
01
08
En este ejemplo la palabra de estado es FF FF hx. ,indicando que una función de
programa está en progreso en el esclavo. El contador de eventos muestra que se han
contado 264 (01 08 hex.) eventos por el controlador.
Obtención del archivo de eventos de comunicaciones (0C)
Devuelve una palabra de estado , contador de eventos , contador de mensajes y un
campo de bytes de eventos del esclavo. No soporta difusión. La palabra de estado y
el contador de eventos son idénticos a los que devuelve la función anterior.
El contador de mensajes contiene la cantidad de mensajes procesados por el esclavo
desde su ultimo restablecimiento ,borrado de contadores o encendido del controlador.
Este contador es idéntico al que devuelve la función de Diagnostico (código 08),
subfunción Devolución del contador de mensajes del bus (código 11, 0B hex). El
campo de bytes de eventos contiene 0 ... 64 bytes, con cada byte correspondiente al
estado de una operación Modbus de envío o recibo del esclavo. Los eventos son
introducidos por el esclavo en el campo en orden cronológico. Así el byte 0 es el
evento mas reciente. Cada nuevo byte empuja al byte anterior del campo de datos.
Pregunta
100
Un ejemplo para solicitar la obtención del archivo de eventos de comunicaciones del
esclavo nº 17:
Campo
Dirección Esclavo
Función
CRC/LRC
11
0C
Respuesta
La respuesta normal contiene un campo de 2 bytes para la palabra de estado, un
campo de 2 bytes para el contador de eventos, un campo de 2 bytes para el contador
de mensajes y un campo conteniendo 0 ... 64 bytes de eventos ;además de un campo
de 1 byte para la longitud total de datos de los anteriores campos.
Un ejemplo de respuesta seria el siguiente:
Campo
Dirección Esclavo
Función
Nº bytes
Estado Hi
Estado Lo
Contador eventos Hi
Contador eventos Lo
Contador mensajes Hi
Contador mensajes Lo
Evento 0
Evento 1
CRC/LRC
11
0C
08
00
00
01
08
01
21
20
00
En este ejemplo, la palabra de estado es 00 00 hex. indicando que el esclavo no esta
procesando una función de programa. El contador de eventos muestra que 264 (01
08 hex.) eventos han sido contados por el esclavo. El contador de mensajes muestra
que 289 (01 21 hex.) mensajes han sido procesados.
El evento de comunicaciones mas reciente se muestra en el byte de evento 0
.Contiene (20 hex) indicando que el esclavo ha entrado lo mas recientemente en el
modo de "solo escuchar".
El evento previo se muestra en el byte de evento 1. Contiene (00 hex.) indicando que
el esclavo recibió un restablecimiento de comunicaciones.
El contenido del byte de evento
El byte de evento devuelto por la función obtener archivo de eventos de las
comunicaciones ,puede ser
de 4 tipos. El tipo viene definido por el bit 7 (bit de
101
mas peso) en cada byte. También puede ser definido por el bit 6.
Evento de recepción por el esclavo Modbus Este tipo de byte de evento es
almacenado por el esclavo cuando se recibe un mensaje pregunta. Es almacenado
antes que el esclavo procese el mensaje.
Este evento se define por la
activación del bit 7 a un valor lógico '1'. Todos los otros bits se activan a '1' si la
correspondiente condición es verdadera. La base de bit es: bit 0,2 y 3 no se usan ,bit
1 error en comunicaciones ,bit 4 sobreescritura de carácter ,bit 5 si se encuentra en
modo escucha y bit 6 indica si se ha recibido un mensaje de difusión general.
Evento de emisión por parte del esclavo Modbus Este tipo de byte de evento es
almacenado por el esclavo cuando acaba de procesar el mensaje pregunta recibido.
Es almacenado si el esclavo devuelve una respuesta normal ,sino responde o si envía
una respuesta debido a una excepción. Este evento se define por el bit 7 a '0' ,con el
bit 6 a '1' .Los demás bits se ponen a '1' si la condición es verdadera .La base de bit
es: bit 0 excepción en lectura ,bit 1 aborta ,bit 2 ocupado ,bit 3 (NACK) reconocimiento
negativo ,bit 4 timeout y bit 5 en modo escucha.
El esclavo ha entrado en modo "solo escuchar" Este tipo de byte de evento es
almacenado por el esclavo cuando entra en el modo de "solo escuchar". Este evento
se define por el contenido 04hex.
El esclavo ha iniciado el restablecimiento de las comunicaciones Este tipo de
byte de evento es almacenado por el esclavo cuando su puerto de comunicaciones es
restablecido. El esclavo puede ser restablecido por la función de diagnostico (código
08), por la subfunción restablecer comunicaciones (código 00 01).
Esta función también coloca al esclavo en un modo continuar si hay otro error o parar
si hay otro error. Si se coloca en el primer modo el byte de evento se añade al archivo
de eventos , en caso contrario si esta en el 2º modo el byte se añade al archivo y el
resto del archivo se borra con ceros. El evento es definido por el contenido de 00 hex.
Forzado de múltiples relés (0F)
Fuerza cada relé (referencia 0x) en una secuencia de relés a ON o OFF. Cuando es
por difusión ,la función fuerza a las mismas referencias de relés en todos los
esclavos.
Nota: La función tendrá prioridad al estado de protección de la memoria del
controlador y el estado de inhabilitación del relé. El valor prefijado permanecerá valido
hasta que la próxima lógica del controlador resuelva el estado de cada relé. Los relés
permanecerán
forzados si no están programados en la lógica del controlador.
Pregunta
El mensaje pregunta especifica las referencias de los relés a ser forzados. Los relés
son direccionados empezando desde 0 ,el relé 1 será direccionado como 0. Los
estados solicitados son especificados por el contenido del campo de datos de la
102
solicitud. Un bit del campo a '1' lógico solicita al relé correspondiente activarse , si esta
a '0' solicita que dicho relé sea desactivado.
A continuación de muestra un
ejemplo de solicitud de forzado de una serie de 10 relés empezando desde el relé 20
(direccionado como 19 o 13 en hex. )en el esclavo nº17:
Campo
Dirección Esclavo
Función
Dirección relés Inicio Hi
Dirección relés Inicio Lo
Nº de relés Hi
Nº de relés Lo
Dato1
Dato2
CRC/LRC
11
0F
00
13
00
0A
CD
01
El contenido del campo de datos de la solicitud son dos bytes: CD 01 hex (1100 1101
0000 0001 binario). Los bits binarios corresponden a los relés en la siguiente manera:
Bit: 1 1 0 0 1 1 0 1 0 0 0 0 0 0 0 1
Relé: 27 26 25 24 23 22 21 20 - - - - - - 29 28
El primer byte transmitido (CD hex.)direcciona a los relés 27 ... 20, con el LSB dirigido
al relé mas bajo (relé nº 20) del grupo de 8. El siguiente byte transmitido (01 hex.)
direcciona los relés 29 y 28, con el LSB dirigido al relé mas bajo (28) de este grupo de
8. Los bits no usados deben ser llenados con ceros.
Respuesta
La respuesta normal devuelve la dirección del esclavo, el código de función la
dirección de inicio y la cantidad de relés forzados (cada 8 relés 1 byte).A continuación
puede verse un ejemplo:
Campo
Dirección Esclavo
Función
Nº Bytes
Dato (27..20)
Dato (29..28)
CRC/LRC
11
0F
02
CD
01
Prefijar múltiples registros (10)
Prefija los valores en una secuencia de registros de retención (referencia 4x). Cuando
es por difusión la función prefija las mismas referencias de registros en todos los
esclavos.
Nota: La función tendrá prioridad al estado de protección de la memoria del
103
controlador y el estado de inhabilitación del relé. El valor prefijado de los registros
permanecerá así hasta que la próxima lógica del controlador resuelva el contenido de
estos. Los valores de los registros permanecerán forzados si no están programados
en la lógica del controlador.
Pregunta
El mensaje pregunta especifica las referencias de los registros a ser prefijados. Los
registros son direccionados empezando desde el 0, el registro 1 se direcciona como
0. Los valores prefijados solicitados son especificados en el campo de datos de la
pregunta. Los controladores M84 y 484 usan un valor binario de 10 bits ,con los 6 bits
de mayor peso a '0'. Todos los otros controladores usan valores de 16 bits. Los datos
son empaquetados como 2 bytes por registro. A continuación se detalla un ejemplo
de solicitud para prefijar dos registros empezando desde 40002 a los valores 00 0A y
01 02 hex. en el esclavo nº 17:
Campo
Dirección Esclavo
Función
Dirección registro Hi
Dirección registro Lo
Nº registros Hi
Nº registros Lo
Dato registro 1Hi
Dato registro 1Lo
Dato registro 2Hi
Dato registro 2Lo
CRC/LRC
11
10
00
01
00
02
00
0A
01
02
Respuesta
La respuesta normal devuelve la dirección del esclavo, el código de función la
dirección de inicio y la cantidad de registros prefijados. A continuación puede verse un
ejemplo:
Campo
Dirección Esclavo
Función
Dirección registro Hi
Dirección registro Lo
Nº registros Hi
Nº registros Lo
CRC/LRC
11
10
00
01
00
02
Informar del tipo de esclavo (11)
Devuelve una descripción del tipo de controlador presente en una dirección esclavo
determinada ,el estado actual del indicador de funcionamiento del esclavo y otra
104
información especifica del equipo esclavo. No soporta difusión.
Pregunta
Ejemplo de solicitud de informe de la identidad y el estado del dispositivo esclavo nº
17:
Campo
Dirección Esclavo
Función
CRC/LRC
11
11
Respuesta
El formato de una respuesta normal se detalla a continuación. El contenido de los
datos es especifico a cada tipo de controlador.
Campo
Dirección Esclavo
11
Función
11
Nº Bytes
*
Identidad esclavo
*
Estado del indicador
de encendido
00 /FF (off/on)
datos adicionales
*
CRC/LRC
(*) indica que es especifico del controlador.
Lectura de la referencia general (14)
Devuelve el contenido de los registros en el archivo de memoria extendida (referencia
6x) .No soporta difusión. La función puede leer múltiples grupos de referencias. Los
grupos puede estar separados pero las referencias entre cada grupo deben ser
secuenciales.
Pregunta
La Pregunta contiene el campo de la dirección estándar Modbus del esclavo ,el
código de función ,el contador de bytes y el de comprobación de error. El resto de la
pregunta especifica el/los grupo/s de referencia/s que ha/n de ser leído/s. Cada grupo
esta definido en un campo separado de sub-pregunta el cual contiene 7 bytes:
- El tipo de referencia ,1 byte (debe ser especificado a 6).
- El número de archivo de memoria extendida ,2 bytes (1 ... 10, 0001 ... 000A hex).
- La dirección del registro de inicio dentro del archivo,2 bytes.
- La cantidad de registros a ser leídos ,2 bytes.
La cantidad de registros a ser leídos ,combinado con los otros campos en la esperada
respuesta ,no debe superar la longitud máxima permitida en los mensajes Modbus
105
(256
bytes). La cantidad disponible de archivos de memoria extendida Depende del
tamaño de memoria extendida que tenga instalada el controlador esclavo. Cada
archivo excepto el ultimo contiene 10.000 registros, direccionados como 0000... 270F
hexadecimal (0000 ... 9999 decimal).
Ejemplos de solicitud y respuesta:
se solicita leer dos grupos de referencias del esclavo nº 17. El grupo 1 consiste en
dos registros del archivo 4, empezando en el registro 2 (dirección 0001). El grupo 2
consiste en dos registros del archivo 3, empezando en el registro 10 (dirección 0009).
Campo
Dirección Esclavo
Función
Nº bytes
Referencia 1
Nº archivo 1 Hi
Nº archivo 1 Lo
Dirección registro 1 Hi
Dirección registro 1 Lo
Nº registros 1 Hi
Nº registros 1 Lo
Referencia 2
Nº archivo 2 Hi
Nº archivo 2 Lo
Dirección registro 2 Hi
Dirección registro 2 Lo
Nº registros 2 Hi
Nº registros 2 Lo
CRC/LRC
11
14
0E
06
00
04
00
01
00
02
06
00
03
00
04
00
02
Respuesta
La respuesta normal es una serie de sub-respuestas ,una para cada sub-pregunta. El
campo del contador de bytes es la cuenta total combinada de bytes en todas la
sub-respuestas. Cada sub-respuesta a su vez contiene un campo que muestra su
propio contador de bytes.
Campo
Dirección Esclavo
Función
Nº bytes
Nº bytes subpregunta 1
Referencia 1
Dato registro 1 Hi
Dato registro 1 Lo
Dato registro 2 Hi
Dato registro 2 Lo
Nº bytes subpregunta 2
Referencia 2
11
14
0C
05
06
0D
FE
00
20
05
06
106
Dato registro 1 Hi
Dato registro 1 Lo
Dato registro 2 Hi
Dato registro 2 Lo
CRC/LRC
33
CD
00
40
Escribir la referencia general (15)
Escribe el contenido de los registros de los archivo de memoria extendida (referencia
6x) .No soporta difusión. La función puede escribir múltiples grupos de referencias.
Los grupos pueden estar separados (no contiguos) ,pero las referencias entre cada
grupo deben ser secuenciales.
Pregunta
La Pregunta contiene los campos de dirección estándar Modbus del esclavo ,el de
código de función ,el de contador de bytes y el de comprobación de error .El resto de
la pregunta especifica el/los grupo/s de referencia/s que ha/n de ser leído/s y los datos
a ser escritos en el/ellos. Cada grupo esta definido en un campo separado de
sub-pregunta el cual contiene 7 bytes además de los datos:
- El tipo de referencia ,1 byte (debe ser especificado a 6).
- El numero de archivo de memoria extendida ,2 bytes (1 ... 10, 0001 ... 000A hex).
- La dirección del registro de inicio dentro del archivo,2 bytes.
- La cantidad de registros a ser leídos ,2 bytes.
- Los datos a ser escritos 2 bytes por registro.
La cantidad de registros a ser escritos ,combinado con los otros campos en la
pregunta ,no deben exceder de 256 bytes. La cantidad disponible de archivos de
memoria extendida depende del tamaño de memoria extendida que tenga instalada el
controlador esclavo. Cada archivo excepto el último contiene 10.000 registros,
direccionados como 0000 ... 270F hexadecimal (0000 ...9999 decimal).
Un ejemplo de solicitud de escritura de un grupo de referencias en el esclavo nº 17 .
El grupo consiste en tres registros en el archivo 4, empezando desde el registro 8
(dirección 0007).
Campo
Dirección Esclavo
Función
Nº bytes
Referencia 1
Nº archivo 1 Hi
Nº archivo 1 Lo
Dirección registro 1 Hi
Dirección registro 1 Lo
Nº registros 1 Hi
Nº registros 1 Lo
11
15
0D
06
00
04
00
07
00
03
107
Dato registro 1 Hi
Dato registro 1 Lo
Dato registro 2 Hi
Dato registro 2 Lo
Dato registro 3 Hi
Dato registro 3 Lo
CRC/LRC
06
AF
04
BE
10
0D
Respuesta
La respuesta normal es el eco de la pregunta.
Escribir en el registro 4x de máscaras(16)
Modifica el contenido de un registro 4x especifico usando una combinación de
máscara AND y OR y el contenido actual del registro. Se puede utilizar dicha función
para des/activar bits individualmente en el registro. No soporta difusión.
Nota: Esta función solo la soportan los controladores 984-785.
Pregunta
La Pregunta especifica la referencia 4x que ha de ser escrita ,el dato a ser usado
como máscara AND y el dato a ser usado como máscara OR.
El algoritmo de la función es:
R = (C & Máscara_And) | (Máscara_Or & (*Máscara_And) )
Siendo:
&=AND , |=OR ,* = NOT
R =resultado y C = contenido actual
Nota: Si el valor de la máscara_Or es 0 ,el resultado es simplemente una AND lógica
con el contenido actual y la máscara_And. Si el valor de la máscara_And es cero ,el
resultado es igual al valor de la máscara_Or.
Nota: El contenido del registro puede ser leído con la función de lectura de registros
de retención (código de función 03). Pueden ser modificados por el programa lógico
de usuario del controlador.
Ejemplo de escritura del registro de máscaras nº 5 del esclavo nº 17, usando los
valores de máscara:
Campo
Dirección Esclavo
Función
Dirección referencia Hi
Dirección referencia Lo
Mascara AND Hi
Mascara AND Lo
Mascara OR Hi
11
16
00
04
00
F2
00
108
Mascara OR Lo
CRC/LRC
25
Respuesta
La respuesta normal es un eco de la pregunta. La respuesta es devuelta una vez el
registro ha sido modificado.
Lectura/Escritura de registros 4x (17)
Es una combinación de una operación de lectura y una de escritura en una única
transmisión Modbus. La función puede escribir nuevos contenidos en un grupo de 4x
registros y entonces devolver el contenido de otro grupo de registros 4x. No soporta
difusión.
Nota: Esta función solo la soportan los controladores 984-785.
Pregunta
La Pregunta especifica la dirección de inicio y la cantidad de registros del grupo a ser
leído .Especifica también la dirección de inicio y la cantidad de registros a ser escritos.
El campo de contador de bytes especifica la cantidad de bytes que siguen en el
campo de escritura de datos.
Ejemplo de solicitud de lectura de 6 registros empezando en el registro 5, y escritura
de 3 registros empezando en el registro 16,en el esclavo nº 17:
Campo
Dirección Esclavo
Función
Dirección referencia Hi
Dirección referencia Lo
Nº registros a leer Hi
Nº registros a leer Lo
Dirección referencia escritura Hi
Dirección referencia escritura Lo
Nº registros a escribir Hi
Nº registros a escribir Lo
Nº bytes de datos
109
11
17
00
04
00
06
00
0F
00
03
06
Dato registro 1 Hi
Dato registro 1 Lo
Dato registro 2 Hi
Dato registro 2 Lo
Dato registro 3 Hi
Dato registro 3 Lo
CRC/LRC
00
FF
00
FF
00
FF
Respuesta
La respuesta normal contiene los datos del grupo de registros leídos. El campo del
contador de bytes especifica la cantidad de bytes que siguen en el campo de lectura
de bytes.
Un ejemplo de respuesta seria el siguiente:
Campo
Dirección Esclavo
Función
Nº Bytes
Dato registro 1 Hi
Dato registro 1 Lo
Dato registro 2 Hi
Dato registro 2 Lo
Dato registro 3 Hi
Dato registro 3 Lo
Dato registro 4 Hi
Dato registro 4 Lo
Dato registro 5 Hi
Dato registro 5 Lo
Dato registro 6 Hi
Dato registro 6 Lo
CRC/LRC
11
17
0C
00
FE
0A
CD
00
01
00
03
00
0D
00
FF
Lectura de la cola FIFO (18)
Lee el contenido de la cola FIFO (el primer elemento que entra es el primero en
salir)de registros 4x. La función devuelve un contador de los registros en la cola
,seguido de los datos de la cola. Hasta 32 registros pueden ser leídos .El registro
contador de la cola se envía primero seguido de los registros de la cola. La función
lee el contenido de la cola ,pero no la borra. No soporta difusión.
Nota: Esta función la soportan solo los controladores 984-785.
Pregunta
La pregunta especifica la referencia 4x que ha de ser leída de la cola FIFO. Esta es la
dirección del registro apuntador usada con las funciones bloque FIN y FOUT del
controlador. Contiene la cuenta de registros actuales que están en la cola .Los
registros de datos de la FIFO siguen a esta dirección ,de manera secuencial.
110
Ejemplo de lectura de los registros de la FIFO del esclavo nº17
Campo
Dirección Esclavo
Función
Dirección puntero FIFO Hi
Dirección puntero FIFO Hi
CRC/LRC
11
18
04
DE
La solicitud es leer la cola empezando en el registro puntero 41247 (04DE hex.).
Respuesta
En una respuesta normal ,el contador byte muestra la cantidad de bytes que siguen
,incluyendo el contador de bytes de la cola y los registros de bytes de datos (sin incluir
el campo de comprobación de error ). El contador de la cola es la cantidad de
registros de datos que hay en la cola (sin incluir al registro contador). Si el contador
de la cola es mayor de 31 ,se devuelve una respuesta a excepción con el código de
error 03 ( Valor de dato ilegal).
Un ejemplo de respuesta a la anterior solicitud:
Campo
Dirección Esclavo
Función
Nº Bytes Hi
Nº Bytes Lo
Nº registros FIFO Hi
Nº registros FIFO Lo
Registro 1 FIFO Hi
Registro 1 FIFO Lo
Registro 2 FIFO Hi
Registro 2 FIFO Lo
Registro 3 FIFO Hi
Registro 3 FIFO Lo
11
18
00
06
00
03
01
B8
12
84
13
22
111
CRC/LRC
En este ejemplo, el registro puntero de la FIFO (41247 en la solicitud) es devuelto con
la cuenta de los elementos de la cola (3). Los tres registros de datos siguen al
contador de cola. Estos son:
41248 (contiene 440 decimal, 01B8 hex.)
41249 (contiene 4740, 1284 hex.)
41250 (contiene 4898, 1322 hex.)
1.4.5.2.2.1 Subfunciones de diagnostico Modbus
Función 08-Diagnósticos
La función Modbus 08 provee una serie de comprobaciones para el sistema de
comunicaciones entre el maestro y esclavo , o para comprobar varias condiciones de
error internas del esclavo. No soporta la difusión (Broadcast). La función usa un
campo de código de subfunción de dos bytes en la pregunta para definir el tipo de test
que se realizará.
El esclavo hace eco del código de función y del de subfunción en una respuesta
normal. La mayoría de las preguntas de diagnostico usan un campo de dos bytes de
datos para enviar datos de diagnostico o información de control al esclavo. Algunos
de los diagnósticos hacen que el esclavo devuelva los datos en el campo de datos de
una respuesta normal.
112
Efectos de los diagnósticos en el esclavo:
En general, una función de diagnostico emitida a un dispositivo esclavo no afecta al
desarrollo normal del programa de usuario en el esclavo. La lógica de usuario ,como
por ejemplo registros ,no necesita ser accedida por el diagnóstico. Ciertas funciones
pueden opcionalmente borrar los contadores de errores en el esclavo. El dispositivo
esclavo puede ,no obstante ,ser forzado a entrar en un modo de "solo escuchar" en el
cual este supervisara los mensajes en el sistema de comunicaciones pero no
responderá a ellos. Esto puede afectar al resultado de la aplicación del programa si
depende del intercambio de datos con el dispositivo esclavo. Generalmente ,este
modo se impone para apartar a un dispositivo esclavo ,que funcione incorrectamente
,del sistema de comunicaciones.
Un ejemplo de pregunta de diagnostico y respuesta se detalla ahora mas adelante.
Muestra la localización del código de función ,el de subfunción y el campo de datos
dentro del mensaje. Una lista de códigos de subfunción soportada por los
controladores se muestra después de dicho ejemplo. Cada código de subfunción
aparece con un ejemplo del contenido del campo de datos que se aplicaría para dicho
diagnostico.
Pregunta
A continuación se expone un ejemplo de una solicitud al equipo esclavo nº 17 a
devolver los datos de la pregunta. Utiliza el código de subfunción 00 00 hex. en el
campo de dos bytes. Los datos que han de ser devueltos (A5 37 hex) son enviados
en el campo de datos de dos bytes.
Campo
Dirección Esclavo 11
Función
08
Subfunción Hi
00
Subfunción Lo
00
Dato Hi
A5
Dato Lo
37
CRC/LRC
Respuesta
La respuesta normal a la solicitud de devolución de los datos de la pregunta es
devolver los mismos datos enviados. El código de función y el de subfunción también
se les hace eco. Los campos de datos en las respuestas a otras preguntas podrían
contener contadores de errores o otra información solicitada por el código de
subfunción.
1.4.5.2.2.2 Códigos de diagnósticos soportados por los controladores
Los códigos 00 .. 02 y 04 son soportados por todos los controladores Modicon (384
,484 ,584 ,884 ,M84 ,984). Los códigos 03 , 10..13 y 16 .. 18 son soportados por
todos excepto por el 884 y el M84. Los códigos de diagnostico 14 y 15 son soportados
113
por todos menos por el 884 ,el M84 y el 984.El código 21 solo lo soporta el 984 y los
códigos 19 y 20 solo los soporta el 884.
Datos de pregunta devueltos (00)
Los datos pasados en el campo de datos de la pregunta han de ser devueltos en la
respuesta. Todo el mensaje de respuesta debe ser idéntico al de pregunta.
Opción de restablecimiento de comunicaciones (01)
El puerto periférico del esclavo ha de ser inicializado y restablecido ,y todos los
contadores de eventos en las comunicaciones han de ser borrados. Si el puerto
estaba en modo de "solo escuchar" ,no se devuelve respuesta alguna. Esta función
es la única que saca al puerto fuera del estado de solo escucha. Si el puerto no
estaba en dicho modo se devuelve una respuesta normal. Esto se realiza antes de
restablecer el puerto.
Cuando el esclavo recibe la solicitud ,intenta un reinicio y ejecuta su test de confianza
de restablecimiento. Si el test finaliza con éxito el puerto vuelve a estar activo en el
sistema de comunicaciones. Un campo de datos de pregunta que contenga FF 00
hex. provoca que el diario o archivo de eventos de comunicaciones del puerto se
borre. Si el contenido es 00 00 deja al archivo como estaba antes de restablecer el
puerto.
Devolución del registro de diagnostico (02)
El contenido del registro de diagnostico de 16 bits del esclavo se devuelve en la
respuesta.
Organización del registro de datos:
La asignación de los bits del registro de diagnostico de los controladores Modicon se
muestra a continuación. En cada registro, el bit 15 es el de mayor peso. La
descripción es TRUE (verdadera) cuando el correspondiente bit esta activo a un
lógico '1'.
Controladores 184/384
0
continua en fallo
1
falla luz encendido
114
2
fallo test bus
3
fallo test bus asinc.
4
forzado a modo escucha
5
6
7
fallo test ROM 0
8
checksum ROM ejecutándose
9
fallo test ROM 1
10
fallo test ROM 2
11
fallo test ROM 3
12
fallo RAM 5000-53FF
13
fallo RAM 6000-67FF par
14
fallo RAM 6000-67FF impar
15
fallo test TIMER
0
continua en fallo
1
falla luz encendido o test CPU
2
fallo test LPT
Controlador 484
115
3
fallo test bus asinc.
4
fallo timer 0
5
fallo timer 1
6
fallo timer 2
7
fallo test ROM 0
8
fallo test ROM 0000-07FF
9
checksum ROM ejecutándose
10
fallo test ROM 0800-0FFF
11
fallo test ROM 1000-1FFF
12
fallo RAM 4000-40FF
13
fallo RAM 4100-41FF
14
fallo RAM 4200-42FF
15
fallo RAM 4300-43FF
Cambio del delimitador ASCII (03)
El carácter CHAR pasado en el campo de datos de la pregunta pasa a ser el
delimitador de final del mensaje para futuros mensajes (reemplazando el carácter LF).
Esta función es útil en casos donde el LF (alimentación de línea ) no se desea al final
de los mensajes ASCII.
Forzado del modo de "solo escuchar" (04)
Fuerza al esclavo seleccionado al modo de solo escucha para comunicaciones
Modbus .Así lo aísla de los otros dispositivos de la red permitiéndoles comunicar sin
interrupciones del citado esclavo. No se devuelve respuesta.
Cuando el esclavo entra en este modo ,todos los controles activos de comunicaciones
son desactivados. Se le permite al temporizador de control (watchdog) de preparado
que expire ,los controles se apagan .Mientras este en este modo cualquier mensaje
dirigido al esclavo o por difusión son supervisados ,pero no se toman acciones y
tampoco se envían respuestas.
La única función que se procesara será restablecimiento de las comunicaciones
(código de función 8, subfunción 1).
Demanda de flags o banderas del programa (8)
116
Ampliación creada para leer el estado de los flags o avisos generales del programa
instalado en los equipos devuelve un byte con las banderas más significativas del
estado del programa.
Demanda de los contadores (9)
Ampliación creada para recibir el valor de todos los contadores existentes de las
comunicaciones en una sola lectura.
Borrado de los registros de diagnostico y contadores (10)
Para los controladores distintos al 584 y 984 ,borra todos los contadores y registros de
diagnostico ,mientras que para estos borra solo los contadores. Los contadores
también son borrados al encender los controladores.
Devolución del contador de mensajes del bus (11)
El campo de datos de la respuesta devuelve la cantidad de mensajes que el esclavo
ha detectado en el sistema de comunicaciones desde su ultimo restablecimiento
,borrado de sus contadores o encendido del controlador.
Devolución del contador de errores de comunicación en el bus (12)
El campo de datos de la respuesta devuelve la cantidad de errores de CRC
encontrados por el esclavo desde su último restablecimiento ,borrado de sus
contadores o encendido del controlador.
Devolución del contador de errores por excepciones en el bus (13)
El campo de datos de la respuesta devuelve la cantidad de respuestas a excepciones
Modbus devueltas por el esclavo desde su ultimo restablecimiento ,borrado de sus
contadores o encendido del controlador.
Devolución del contador de mensajes respondidos por el esclavo (14)
El campo de datos de la respuesta devuelve la cantidad de mensajes dirigidos al
esclavo ,o por difusión que el esclavo a procesado desde su ultimo restablecimiento
,borrado de sus contadores o encendido del controlador.
Devolución del contador de mensajes no respondidos por el esclavo (15)
El campo de datos de la respuesta devuelve la cantidad de mensajes dirigidos al
esclavo a los que este no ha enviado su respuesta (ya sea una respuesta normal o a
una excepción) desde su ultimo restablecimiento ,borrado de sus contadores o
encendido del controlador.
117
Devolución del contador de NAK enviados por el esclavo (16)
El campo de datos de la respuesta devuelve la cantidad de mensajes dirigidos al
esclavo a los que este ha enviado una respuesta a excepción NAK(reconocimiento
negativo) desde su ultimo restablecimiento ,borrado de sus contadores o encendido
del controlador.
Devolución del contador de mensajes de ocupado enviados por el esclavo (17)
El campo de datos de la respuesta devuelve la cantidad de mensajes dirigidos al
esclavo a los que este ha enviado una respuesta a excepción SDB(dispositivo esclavo
ocupado) desde su ultimo restablecimiento ,borrado de sus contadores o encendido
del controlador.
Devolución del contador de caracteres de bus sobrescritos (18)
El campo de datos de la respuesta devuelve la cantidad de mensajes dirigidos al
esclavo ,que no ha podido atender por darse una condición de sobrescritura
(overrrun) ,desde su ultimo restablecimiento ,borrado de sus contadores o encendido
del controlador. Un carácter sobrescrito se da cuando los caracteres de datos llegan
al puerto tan rápido que no pueden ser almacenados o por la perdida de un carácter
por un mal funcionamiento del soporte físico.
Devolución del contador de IOPs sobrescritos para controladores 884 (19)
El campo de datos de la respuesta devuelve la cantidad de mensajes dirigidos al
esclavo ,que no ha podido atender por darse una condición de sobreescritura de IOPs
del 884 ,desde su ultimo restablecimiento ,borrado de sus contadores o encendido del
controlador. Un IOP sobrescrito se da cuando los caracteres de datos llegan al puerto
tan rápido que no pueden ser almacenados o por la perdida de un carácter por un mal
funcionamiento del soporte físico.
Nota: Esta función es especifica al controlador 884.
Borrado del flag y el contador de sobreescritura para controladores 884 (20)
Borra el contador de errores por sobreescritura y borra el flag de error en los
controladores 884. El estado de dicho flag se encuentra en el bit 0 del registro de
diagnostico del 884 (ver subfunción 02).
118
Nota: Esta función es especifica al controlador 884.
Obtención o borrado de las estadísticas Modbus Plus (21)
Devuelve una serie de 54 words (108 bytes) en el campo de datos de la respuesta
(esta función difiere de la longitud habitual de dos bytes del campo de datos). Los
datos contienen las estadísticas para el mismo procesador Modbus Plus en el
dispositivo esclavo. Además del código de función (08) y el de subfunción (00 15 hex)
en la pregunta ,se usa un campo de Operación de dos bytes para especificar una
operación de obtención o borrado de estadísticas. Las dos operaciones son
exclusivas (la opción de obtener no permite borrar y la opción de borrar no devuelve
previamente las estadísticas antes de borrarlas). Las estadísticas son borradas con el
encendido del controlador esclavo.
El campo de operación sigue inmediatamente al campo de subfunción en la pregunta.
Un valor de 00 03 especifica la operación de obtener estadísticas ,mientras que un
valor 00 04 especifica la operación de borrado de estadísticas.
1.4.5.2.3 Respuestas a excepciones
Excepto para mensajes de difusión (broadcast) ,cuando un maestro envía una
pregunta a un esclavo espera recibir una respuesta normal. Cuatro posibles casos o
eventos pueden suceder a la petición del maestro:
-Si el esclavo recibe la solicitud sin errores de comunicaciones ,y puede manejar la
pregunta de manera normal ,devuelve una respuesta normal (libre de errores).
- Si el esclavo no recibe la pregunta por un error en la comunicación, no envía
119
respuesta alguna .El programa del maestro eventualmente procesa una condición de
"timeout" (tiempo de espera de respuesta agotado).
-Si el esclavo recibe la pregunta ,pero detecta un error en la comunicación (paridad,
LRC o CRC), no envía respuesta alguna. El programa del maestro actuará como
antes.
-Si el esclavo recibe la pregunta sin error de comunicación, pero no puede manejarla
(por ejemplo si la solicitud es para leer el estado de un relé inexistente o un registro)
,el esclavo devolverá una respuesta de excepción ,informando al maestro de la
naturaleza del error.
El mensaje de respuesta a una excepción tiene dos campos que lo diferencian de una
respuesta normal:
Campo de código de función En una respuesta normal ,el esclavo hace eco del
código de función de la pregunta original en el campo de código de función de la
respuesta. Todos los códigos de función tienen su bit más significativo (MSB) a '0'(sus
valores están por debajo del 80 hex.) .En una respuesta a una excepción el esclavo
activa el MSB del código de función a '1'. Esto hace que el valor del código de función
en una respuesta a excepción valga exactamente 80 hex. mas grande que el valor
que debería tener una respuesta normal. Con el MSB del código de función activado
,el programa de aplicación del maestro puede reconocer a la respuesta a la excepción
y puede examinar el campo de datos para averiguar el código de excepción.
Campo de datos En una respuesta normal ,el esclavo debe devolver datos o
estadísticas en el campo de datos. Mientras que en el caso de una respuesta a una
excepción ,el esclavo devuelve un código de excepción en el campo de datos. Esto
define la condición del esclavo que causo la excepción. A continuación se detalla un
ejemplo de una solicitud de un maestro y la respuesta a una excepción del esclavo.
Los ejemplos de campos están en hexadecimal.
Pregunta:
Campo
Dirección Esclavo
Función
Dirección Inicio Hi
Dirección Inicio Lo
Nº relés Hi
Nº relés Lo
LRC
0A
01
04
A1
00
01
4F
120
Respuesta:
Campo
Dirección Esclavo
Función
Código excepción
LRC
0A
81
02
73
En este ejemplo ,el maestro direcciona una pregunta al dispositivo esclavo numero 10
(0A hex). El código de función (01) es para leer el estado de relés. Pregunta por el
estado del relé situado en la dirección 1245 (04A1 hex).
Nota: Solo un relé ha de ser leído ,como especifica el campo de numero de relés
(0001). Si la dirección del relé no existe en el dispositivo esclavo ,este devolverá una
respuesta a excepción con el código de excepción (02). Este especifica una dirección
de dato ilegal para el esclavo. Por ejemplo si el esclavo es un 984-385 con 512 relés ,
este código seria devuelto.
1.4.5.2.4 Códigos de excepción
Valor
Descripción
01
Función ilegal, no soportada.
02
Dirección de dato ilegal, no soportada.
03
Valor de datos ilegal, no soportado.
04
Fallo no solucionable al intentar ejecutar función solicitada.
05
Función solicitada ejecutándose pero tiempo espera respuesta largo
,evita timeout en el maestro
06
Esclavo procesando comando largo ,no puede atender ahora.
07
Función solicitada no se puede realizar ,pedirle el diagnostico de error.
08
Error al leer en memoria externa ,zona de E.M.R.s
1.4.5.2.5 Máximo numero de parámetros
Las listas que siguen muestran la máxima cantidad de datos que cada controlador
puede devolver en una respuesta y la máxima cantidad de datos que cada
controlador puede solicitar en una pregunta. Los espacios en blanco indican que es
una función no soportada.
RESPUESTA:
Función
184/384
484
121
584
884
M84
984
1 relés
2 entradas
3 registros
4 registros
5 relé
6 registros
7 relés
8
9 datos byte
10 datos byte
11
12 datos byte
13 datos byte
14 datos byte
15 relés
16 registros
17
18
19
20 datos byte
21 datos byte
800
800
100
100
1
1
n/a
n/a
512
512
254
32
1
1
n/a
n/a
n/a
n/a
32
n/a
800
100
n/a
2000 2000 64
2000 2000 64
125 125 32
125 125 4
1
1 1
1
1 1
n/a
n/a n/a
n/a
n/a n/a
16
2000
2000
125
125
1
1
n/a
n/a
n/a
n/a
33
800
60
n/a
33
n/a
800
100
n/a
n/a
800 64
100 32
n/a n/a
<257 <257
n/a n/a
<257
<257
800
100
n/a
<257
<257
PREGUNTA:
Función
1 relés
2 entradas
3 registros
4 registros
5 relé
6 registros
184/384 484
800
800
100
100
1
1
512
512
254
32
1
1
584
884
2000 2000
2000 2000
125 125
125 125
1
1
1
1
122
M84
984
64
64
32
4
1
1
2000
2000
125
125
1
1
7 relés
8
9 datos byte
10 datos byte
11
12 datos byte
13 datos byte
14 datos byte
15 relés
16 registros
17
18
19
20 datos byte
21 datos byte
8
n/a
n/a
70
32
32
800
100
n/a
8
n/a
16
16
800
60
n/a
8
n/a
8
8
n/a n/a
n/a
70
33
33
800 800 64
100 100 32
n/a n/a n/a
<257 <257
n/a n/a
<257
<257
8
n/a
70
33
33
800
100
n/a
<257
<257
1.4.5.2.6 Tiempos estimados en transmisiones serie
La siguiente secuencia de eventos ocurre durante una transmisión serie Modbus. Las
letras entre paréntesis se refieren a las notas de los tiempos al final de la lista.
1- El maestro Modbus compone el mensaje.
2- Los estados de RTS y CTS del módem del dispositivo maestro son comprobadas.
(A)
3- El mensaje pregunta se transmite al esclavo (A)
4- El esclavo procesa el mensaje pregunta (B)
5- El esclavo calcula el campo de comprobación de error (C,D)
6- El estado de RTS y CTS del módem del dispositivo esclavo se comprueban. (E)
7- El mensaje respuesta se transmite al maestro.(A)
8- La aplicación del maestro actúa según la respuesta y los datos recibidos. (B)
Notas acerca de los tiempos:
- Si las patillas RTS y CTS están puenteados juntos este tiempo es negligible. Para
módems J478 es de 5 ms.
- Aplicar la siguiente formula para estimar el tiempo de transmisión:
Tiempo (s) = [nºcaracteres]x[bits por carácter] / Baudios
123
- El mensaje Modbus es procesado al final del tiempo de escrutinio (ciclo de
preguntas a los esclavos) del controlador. El peor caso de retardo es un tiempo de
escrutinio ,que ocurre si el controlador ha empezado justamente un nuevo escrutinio.
El tiempo medio es la mitad del tiempo de escrutinio.
El tiempo permitido para dar servicio a los puertos Modbus al final del intervalo de
escrutinio del controlador depende del modelo de controlador. El tiempo de servicio
para cada modelo se describe a continuación:
- Para los controladores 484 el tiempo de servicio es de 1'5 ms. El puerto Modbus
esta disponible en una base de contención con cualquier módem J470 / J474 / J475
que este presente.
- Para los controladores 584 y 984 también es de 1'5 ms para cada puerto Modbus.
Los puertos son servidos secuencialmente ,empezando por el puerto 1.
- Para los controladores 184 y 384 el tiempo de servicio varia según la cantidad de
datos a manejar .Va de un mínimo de 0'5 ms a un máximo de 6'0 ms (para 100
registros) ,0 7'0 ms (para 800 relés).Si se usa un panel de programación con el
controlador el puerto Modbus esta bloqueado.
Funciones Modbus de la 1 a la 4, 15 y 16 permiten al maestro preguntar mas datos de
los que pueden ser procesados durante el tiempo permitido para servir los puertos
Modbus esclavos. Si el esclavo no puede procesar todos los datos ,los guardara en
registros y los procesara al final de los subsiguientes escrutinios.
El tiempo de calculo del LRC es menor a 1 ms, el tiempo de calculo del CRC es de
0.3 ms para cada 8 bits de datos devueltos en la respuesta.
Notas para el 584 y 984A/B/X
Velocidades de transmisión:
Cuando se usan ambos puertos 1 y 2 ,la máxima
velocidad combinada permitida es de 19.200 Baudios.
Bloqueo de Puertos: Cuando se use el modo ASCII, evítese enviar mensajes de datos
de longitud nula o mensajes sin dirección de dispositivo. Por ejemplo este es un tipo
de mensaje ilegal:
: CR LF
(colon, CR, LF)
124
Si se usa este tipo de mensajes puede ocurrir que se bloqueen los puertos de manera
aleatoria ,es decir que no funcionen correctamente.
Mensajes de terminación ASCII: Normalmente los mensajes ASCII debería terminarse
con el par de caracteres CR+LF. Con los controladores 584 y 984A/B/X ,un mensaje
ASCII puede terminar después del campo LRC (sin enviar los caracteres CR + LF) si
se deja transcurrir un intervalo de 1 s después de dicho campo. Si esto ocurre ,el
controlador asume que el mensaje ha terminado de forma normal.
1.4.5.2.7 Generación de LRC y CRC
-LRCEste campo es de 1 byte y contiene un valor binario de 8 bits.El valor LRC es
calculado por el dispositivo emisor,el cual introduce el LRC en el mensaje. El
dispositivo receptor recalcula el LRC durante la recepción,si el valor calculado no
coincide con el actual en el campo de LRC es que existen errores.
El LRC se calcula añadiendo sucesivamente todos los bytes del mensaje,
descartando los acarreos y luego haciendo el complemento a 2 del resultado .Al ser
un campo de 8 bits ,en cada suma de un nuevo carácter puede dar un resultado
mayor que 255 en decimal ,simplemente gira el valor del campo hacia cero.Ya que no
existe un noveno bit ,el acarreo se descarta automáticamente.
Pasos a seguir para generar el LRC:
1- Añadir todos los bytes del mensaje (excluyendo los patrones de inicio y fin) al
campo de 8 bits, descartando los acarreos.
2- Substraer el valor final del campo a FF hex para producir el complemento a 1.
3- Añadir 1 para producir el complemento a 2.
Colocación del LRC en el Mensaje:
Cuando el LRC (2 caracteres ASCII) se transmite en el mensaje, el carácter de mayor
orden se transmite primero y luego el de menor orden.Por ejemplo si el valor LRC es
61 hex (0110 0001):
:
Dir
Func
125
Ndatos
datos
LRC 6
LRC1
-CRCEste campo de 2 bytes ,que contienen un valor binario de 16 bits.Es calculado por el
emisor el cual lo coloca en el mensaje. El dispositivo receptor lo recalcula y si el valor
calculado no coincide con el actual del campo CRC significa que hay errores.
El CRC comienza precargando primero el registro de 16 bits con todo a '1'.Entonces
un proceso comienza aplicando sucesivos bytes del mensaje al contenido actual del
registro. Solo los datos de 8 bits en cada carácter se emplean para generar el CRC.
Los bits de arranque y parada no se tienen en cuenta.
Durante la generación del CRC ,a cada carácter de 8 bits se le hace una XOR con el
contenido del registro. El resultado se rota en sentido al (LSB) bit menos significativo
,colocando un 0 en el (MSB) bit mas significativo. EL LSB se extrae y se examina ,si
es '1 'al registro se le hace una XOR con un valor prefijado ,mientras que si es '0' no
se le hace una XOR.
Este proceso se repite hasta que se realizan hacia la derecha 8 desplazamientos
.Después del 8º al próximo carácter de 8 bits se le hace la XOR con el valor actual del
registro y el proceso se repite como antes. El valor final del registro es el valor CRC.
Pasos para generar un CRC:
1- Cargar el registro con 16 bits todos a '1' (FFFF hex).
2- Hacer una XOR a los primeros 8 bits del mensaje con el byte bajo del registro de
16 bits CRC,dejando el resultado en dicho registro.
3- Desplazar el registro CRC 1 bit a la derecha (hacia el LSB), poniendo a '0' el MSB.
Extraer y examinar el LSB.
4- Si el LSB es '0', repetir el paso 3. Si el LSB es '1',se le hace una XOR al registro
CRC con el valor polinomial A001 hex. (1010 0000 0000 0001).
5- Repetir los pasos 3 y 4 hasta que se realicen 8 desplazamientos. Cuando este
hecho un byte CRC estará acabado.
6- Repetir los pasos 2 al 5 para el próximo byte CRC del mensaje.
7- Repetir el proceso hasta que todos los bytes estén procesados. El valor final del
contenido del registro CRC es el valor CRC.
8- Cuando el CRC se coloque en el mensaje los bytes alto y bajo deben ser
intercambiados como se describe a continuación.
Colocación del CRC en el mensaje:
126
Cuando los 16 bits de CRC son transmitidos en el mensaje ,el byte de menor peso se
transmite primero y luego el byte de mayor peso. Por ejemplo si el valor del CRC es
1241 hex (0001 0010/0100 0001):
Dir
Func
Ndatos
datos
CRC 41
CRC 12
1.4.6 La norma IEEE 802.2
Esta norma describe las especificaciones de la interfaz de servicio del subnivel LLC
con:
- Nivel de red ,define la descripción de los diversos servicios que el subnivel LLC
ofrece a dicho nivel.
- Subnivel MAC ,define una descripción de los diversos servicios que el subnivel LLC
requiere del subnivel MAC.
127
- Función de gestión del subnivel LLC ,proporciona una descripción de los servicios de
administración proporcionados al subnivel LLC por la función de gestión del subnivel
LLC.
Los servicios del subnivel LLC son definidos de forma independiente del modo de
acceso al medio y de la naturaleza del propio medio. Todas las especificaciones de
las interfaces de servicio señaladas anteriormente son proporcionadas mediante
primitivas que representan de manera abstracta el intercambio lógico de la
información y control entre el subnivel LLC y la función de servicio especifica ,según
se trate nivel de red ,subnivel MAC o función de gestión del subnivel LLC.
El estándar proporciona una descripción de los protocolos igual a igual que se definen
para la transferencia de información y control entre cualquier par de Puntos de
Acceso al Servicio al Nivel de Enlace de Datos (SAP).
Los procedimientos LLC son independientes del tipo de control de acceso al medio
utilizado.
1.4.6.1 Especificaciones del servicio
El estándar IEEE 802.2 especifica tres tipos de servicios proporcionados por el LLC a
través de los puntos de acceso al servicio LLC (LSAPs) :
- Servicio no orientado
Connectionless Service).
a
conexión
sin
reconocimiento
(Unacknowledge
- Servicio orientado a conexión ( Connection Mode Service).
- Servicio no orientado a conexión con reconocimiento (Acknowledge Connectionless
Service).
La lista siguiente muestra las primitivas y parámetros del subnivel de control del
enlace lógico:
Servicio no orientado a conexión sin reconocimiento
DL_UNITDATA.request(dirección propia, dirección destino, datos, prioridad)
DL_UNITDATA.indication(dirección propia, dirección destino,datos, prioridad)
Servicio orientado a conexión
DL_CONNECT.request(dirección propia, dirección destino, prioridad)
128
DL_CONNECT.indication(dirección propia, dirección destino, prioridad)
DL_CONNECT.confirm(dirección propia, dirección destino, prioridad)
DL_DATA.request(dirección propia, dirección destino, datos)
DL_DATA.indication(dirección propia, dirección destino, datos)
DL_DISCONNECT.request(dirección propia, dirección destino)
DL_DISCONNECT.indication(dirección propia, dirección destino, motivo)
DL_DISCONNECT.confirm(dirección propia, dirección destino)
DL_RESET.request(dirección propia, dirección destino)
DL_RESET.indication(dirección propia, dirección destino, motivo)
DL_RESET.confirm(dirección propia, dirección destino)
DL_CONNECTION_FLOWCONTROL.request(dirección propia ,dirección destino ,
cantidad de datos)
DL_CONNECTION_FLOWCONTROL.indication(dirección propia ,dirección destino,
cantidad de datos)
Servicio no orientado a conexión con reconocimiento
DL_DATA_ACK.request(dirección propia, dirección destino, datos, prioridad, clase de
servicio)
DL_DATA_ACK.indication(dirección propia, dirección destino , datos, prioridad, clase
de servicio)
DL_DATA_ACK_STATUS.indication(dirección propia, dirección destino , prioridad,
clase de servicio, estado)
DL_REPLY.request(dirección propia, dirección destino, datos, prioridad,clase de
servicio)
DL_REPLY.indication(dirección propia, dirección destino, datos, prioridad, clase de
servicio)
DL_REPLY_STATUS.indication(dirección propia, dirección destino, datos, prioridad,
clase de servicio, estado)
DL_REPLY_UPDATE.request(dirección propia, estado)
DL_REPLY_UPDATE.indication(dirección propia, estado)
Servicio no orientado a conexión sin reconocimiento
Se trata de un servicio de mínima complejidad que simplemente permite el envío y
recepción de datos. En este caso el suministrador del servicio no garantiza que los
datos vayan a llegar al destino ,ni informar del los posibles fallos en la comunicación
al emisor, así como no se hace responsable de que los datos lleguen en el orden en
que fueron enviados. Este tipo de operación puede ser útil cuando los niveles
superiores proporcionan un servicio de recuperación y control de secuencia tal que no
requieren ser referenciados por el nivel de enlace. También es aplicable a
129
aplicaciones en las que no es esencial garantiza el envió de cada unidad de datos en
el nivel de enlace. Se emplean dos primitivas:
DL_UNITDATA.request(dirección propia, dirección destino, datos, prioridad)
DL_UNITDATA.indication(dirección propia, dirección destino, datos, prioridad)
La primitiva request es emitida por el nivel de red al LLC para solicitar la transferencia
de una unidad de datos de servicio. Los parámetros de dirección corresponden a la
combinación de las direcciones SAP LLC y MAC. La dirección destino puede
especificar una dirección individual o colectiva. El parámetro prioridad es pasado al
MAC ,quien tiene la responsabilidad de implementar el mecanismo de prioridad. Los
protocolos paso de testigo en bus, paso de testigo en anillo y FDDI incluyen dicho
mecanismo ,CMSA/CD no. La primitiva <indication> se emite desde el LLC al nivel de
red para indicar la llegada de una unidad de datos.
Servicio orientado a conexión
En este servicio existe un acuerdo entre dos usuarios LLC para el intercambio de
información. Existen tres fases:
1- Establecimiento de la conexión. Uno de los usuarios solicita una conexión a otro
usuario. La conexión lógica se establece en el caso de que el LLC sea capaz de
proporcionar el servicio solicitado y el usuario destino este preparado para el
intercambio de datos. Mediante esta conexión el LLC es capaz de controlar las
unidades de datos transmitidas y recibidas. Se emplean tres primitivas:
DL_CONNECT.request(dirección propia, dirección destino, prioridad)
DL_CONNECT.indication(dirección propia, dirección destino, prioridad)
DL_CONNECT.confirm(dirección propia, dirección destino, prioridad)
2- Transferencia de datos. Una vez establecida la conexión entre los dos usuarios
LLC definidos por sus SAPs correspondientes se produce la transferencia de
información. Durante esta fase el LLC garantiza que todas las unidades de datos se
transmiten y además en el orden correcto. Únicamente se emplean dos primitivas:
DL_DATA.request(dirección propia, dirección destino, datos)
DL_DATA.indication(dirección propia, dirección destino ,datos)
El motivo por el que solo hay dos primitivas es que el usuario emisor no tiene
necesidad de confirmación de los datos enviados ,ya que ,el LLC garantiza su
transmisión libre de errores. Si hubiera problemas se utilizan las funciones de
disconnect o reset. Durante la transferencia se emplea el servicio de control de flujo
con el objetivo de controlar la cantidad de datos que pueden pasarse entre el nivel de
red y el LLC. Las primitivas son:
DL_CONNECTION_FLOWCONTROL.request(dirección propia,
,cantidad de datos)
130
dirección
destino
DL_CONNECTION_FLOWCONTROL.indication(dirección propia, dirección destino,
cantidad de datos)
La cantidad de datos puede ser definida en cada <request> o <indication>. Si es cero
se detiene la transmisión.
La reiniciación o reset de la transferencia provoca que todas las unidades de datos de
las que no se ha recibido confirmación de su transmisión sean descartadas. Puesto
que el LLC no recupera estos datos ,la responsabilidad debe ser asumida por un
protocolo
de nivel superior. Las primitivas son:
DL_RESET.request(dirección propia, dirección destino)
DL_RESET.indication(dirección propia, dirección destino, motivo)
DL_RESET.confirm(dirección propia, dirección destino)
3- Finalización de la conexión. Esta fase puede ser iniciada en cualquier momento
tanto por los usuarios de LLC como por el propio LLC ,dando fin de esta manera a la
conexión lógica y desechando las unidades de datos pendientes. Primitivas
empleadas: DL_DISCONNECT.request(dirección propia, dirección destino)
DL_DISCONNECT.indication(dirección propia, dirección destino, motivo)
DL_DISCONNECT.confirm(dirección propia, dirección destino)
El parámetro motivo en la primitiva <indication> indica la razón de la desconexión.
Servicio no orientado a conexión con reconocimiento
Este servicio fue incluido en el estándar IEEE 802 en 1987. Aunque no está orientado
a la conexión y por lo tanto no existe el establecimiento previo de una conexión lógica
,sí proporciona un reconocimiento inmediato de cada una de las unidades de datos
enviadas. Sólo transmite una unidad de datos a la vez ,esperándose a que se reciba
la correspondiente confirmación antes de transmitir la siguiente. Incluye actualmente
dos tipos de servicios:
Este servicio es de entrega garantizada ,los datos se envían
DL_DATA_ACK
desde el LLC a la vez que se solicita implícitamente su reconocimiento. Las primitivas
empleadas son:
DL_DATA_ACK.request(dirección propia, dirección destino, datos, prioridad, clase de
servicio)
DL_DATA_ACK.indication(dirección propia, dirección destino ,datos, prioridad, clase
de servicio)
DL_DATA_ACK_STATUS.indication(dirección propia, dirección destino , prioridad,
clase de servicio, estado)
Las dos primeras tienen un significado análogo a las correspondientes primitivas del
131
servicio no orientado a conexión sin reconocimiento ,y además indican una solicitud
de reconocimiento. El parámetro clase de servicio indica si el nivel MAC va a
participar en el reconocimiento de la transmisión de datos (sólo soportado por el IEEE
802.4). La última primitiva proporciona el reconocimiento al usuario emisor. El
parámetro estado indica si los datos fueron o no recibidos correctamente.
DL_REPLY Este servicio se basa en una consulta o polling con garantía de
respuesta. Permiten al usuario solicitar a otro unidades de datos previamente
preparados o intercambiar unidades de datos con otro usuario. El suministrador del
servicio LLC es capaz de retener una unidad de datos y pasarla a aquel usuario que
la solicite; para ello el usuario LLC le envía los datos previamente o el usuario puede
consultar directamente al usuario remoto para pedirle los datos. Las primitivas son:
DL_REPLY.request(dirección propia, dirección destino, datos, prioridad, clase de
servicio)
DL_REPLY.indication(dirección propia, dirección
destino, datos, prioridad, clase
de servicio)
DL_REPLY_STATUS.indication(dirección propia, dirección destino , datos, prioridad,
clase de servicio, estado)
DL_REPLY_UPDATE.request(dirección propia, estado)
DL_REPLY_UPDATE.indication(dirección propia, estado)
Las tres primeras primitivas proporcionan un servicio de intercambio de datos. Esta
asociadas con las primitivas dos últimas ,que permiten a un usuario transferir datos al
LLC para que sean enviados opcionalmente cuando se solicite por otra estación
mediante la primitiva DL_REPLY.
1.4.6.2 Protocolo del subnivel LLC
El protocolo LLC sigue el modelo definido por HDLC y tiene formatos similares. Las
diferencias entre ambos protocolos son:
- LLC utiliza sólo el modo de operación asíncrono balanceado de HDLC para soportar
el servicio LLC orientado a conexión. No emplea el resto de modos de operación de
HDLC.
132
- LLC utiliza la PDU de información no numerada para soportar el servicio no
orientado a conexión sin reconocimiento.
- LLC implementa la multiplexación mediante el uso de los LSAPs (Puntos de Acceso
al Servicio del subnivel LLC).
- LLC utiliza dos nuevas PDUs no numeradas para soportar el servicio no orientado a
conexión con reconocimiento.
1.4.6.2.1 Unidad de datos de protocolo PDU LLC
Esta estructura define el método para representar las direcciones de los LLC SAP
desde o hacia las entidades
del Nivel de red y define una partición de éstas en
direcciones individuales o de grupo. También incluye N bytes de control y M bytes de
información.
Dirección
SAP 1
Dirección
SAP 1
Control
N
Información
M
Nota: los números que se ven son el número de bytes de cada campo ; N = 2 para
formato Información o Supervisión ,mientras que N = 1 para formato No Enumerado.
M es un valor entero que puede ser incluso 0.
Campos de la PDU_LLC:
Direcciones
DSAP
I/G
D
D
D
D
D
- DSAP identifica el SAP al que va dirigido
D
D
el campo de información.
SSAP
C/R
S
S
S
S
S
S
S
- SSAP identifica el SAP en el que el campo de información fue generado.
El formato de los campos de dirección es el de la página anterior ,el bit I/G identifica si
la dirección destino es individual (0) o de grupo (1). El bit C/R indica si la PDU_LLC es
un mandato (0) o si se trata de una respuesta (1). Todos los bits "D" o "S" a 0
identifican una dirección nula. La dirección de SAP nula designa el LLC asociado con
el MAC subyacente y no se utiliza para identificar ningún punto de acceso al servicio
al nivel de red. El DSAP y el SSAP pueden utilizar direcciones individuales o nulas.
Sólo el DSAP puede emplear una dirección con todos los bits a "1" ,lo que indica el
grupo de todos los DSAP activos.
133
Esta formado por uno o dos octetos que podrán ser utilizados para
Control
designar mandatos y funciones de respuesta y podrán contener números de
secuencia ,si ello es necesario.
Información Este campo puede estar compuesto por un número entero de octetos
,incluido ninguno. El valor máximo dependerá de la metodología de control de acceso
al medio utilizado.
Orden de los bits: Las direcciones ,mandatos ,respuestas y número de secuencia
serán enviados o recibidos desde el subnivel MAC considerando los bits menos
significativos en primer lugar. El campo de información será enviado al subnivel MAC
en el mismo orden en que ha sido recibido desde el nivel 3 y será enviado al nivel 3
en el mismo orden en que fue recibido del MAC. Una PDU_LLC puede ser definida
como invalida si cumple al menos una de las siguientes condiciones:
- Es identificada como invalida por el nivel físico o por el subnivel MAC.
- No posee la longitud correspondiente a un número entero de octetos.
- No contiene los dos campos de direcciones necesarios, un campo de control y un
campo de datos en el orden establecido en el formato especificado.
- Su longitud es inferior a 3 octetos.
1.4.6.2.2 Tipos y clases de LLC
En el estándar se definen tres tipos de protocolos LLC, denominados tipos de
operación ,uno por cada tipo de servicio definido.
Operación Tipo 1 soporta el servicio no orientado a conexión sin reconocimiento.
Operación Tipo 2 soporta el servicio orientado a conexión.
Operación Tipo 3 soporta el servicio no orientado a conexión con reconocimiento.
Los protocolos descritos son utilizados en entornos multiacceso con múltiples
estaciones. Es posible que una estación soporte mas de un tipo de servicio y ,en
consecuencia ,mas e un tipo de protocolo. En función de los tipos de operación
soportados se definen las clases de estación. Todas las clases soportan el Tipo 1 ,de
esta forma se asegura que todas las estaciones de la red tengan un modo de servicio
común que facilite las operaciones de gestión. En un extremo se encuentran las
estaciones de clase I que soportan únicamente el Tipo 1 y en el otro las de clase IV
que soportan los tres Tipos. Todos los protocolos LLC emplean el mismo formato de
134
PDU.
A continuación se muestran las PDU utilizadas en LLC
Servicio no orientado a conexión sin reconocimiento
No Numerado
UI
TEST
XID
C
C/R
C/R
Intercambio de datos
Test
Tipo de operación y tamaño de ventana
Servicio orientado a conexión
No Numerado
SABME
DISC
UA
DM
FRMR
C
C
R
R
R
Petición de conexión
Conexión terminada
Comando confirmación no numerada
Rechazo de conexión
Información de trama rechazada
Información
I
C/R
Intercambio de datos
Supervisión
RR
RNR
REJ
C/R
C/R
C/R
Preparado para recibir (*)
No preparado para recibir (*)
Reconocimiento negativo
(*) Reconocimiento positivo
Nota: <C> significa comando y <R> respuesta
Servicio no orientado a conexión con reconocimiento
No Numerado
AC
C/R
Intercambio de datos
Operación Tipo 1
Se emplea la PDU UI en la transferencia de datos. No hay reconocimiento o
confirmación ,ni control de errores o de flujo ;pero sí detección y descarte de errores
en el nivel MAC.
Las PDUs XID y TEST tienen como objetivo soportar las
funciones de gestión de los tres tipos de operación.
135
La PDU XID indica el tipo de operación soportado y el tamaño de la ventana de
transmisión. Si los campos DSAP y SSAP son nulos ,es decir todo ceros ,el campo
información indica el tipo de operación LLC proporcionado por la entidad LLC
emisora. Si la PDU XID incluye direcciones en sus campos DSAP y SSAP ,entonces
el campo de información especifica los tipos de operación que el SSAP puede
proporcionar. En el caso de un SAP que soporte la operación Tipo 2 y para una
conexión determinada ,el campo de información incluye también el tamaño de la
ventana utilizado en el mecanismo de control de flujo.
La PDU TEST se emplea para comprobar el enlace de transmisión entre dos
entidades LLC. A la recepción de una PDU TEST en modo mandato la entidad
receptora emite una PDU TEST en modo respuesta tan pronto como le sea posible.
Operación Tipo 2
Se establece una conexión lógica entre las entidades LLC previa al intercambio de
información. Para ello la entidad LLC envía una PDU SABME a la entidad remota. En
el caso de que la solicitud sea aceptada ,la entidad remota devuelve una PDU UA. De
esta forma la conexión viene identificada de manera única por los SAPs de los
usuarios. Si la solicitud es rechazada envía una PDU DM.
Con la conexión establecida ,las PDUs I ,de información ,se emplean para el
intercambio de datos ,al igual que en HDLC. La PDU I incluye los números de
secuencia de emisión y recepción para el control de secuencia y flujo. La PDU S ,de
supervisión ,se utiliza ,como en HDLC ,para el control de errores y de flujo.
Cada una de la entidades LLC puede solicitar lareiniciación o reset de la conexión
,bien por iniciativa propia ,bien por solicitud del usuario LLC. Para solicitar el reset de
una determinada conexión se emplea la PDU SABME con las direcciones apropiadas
DSAP y SSAP. El usuario LLC remoto puede aceptar o no la petición (PDU UA o PDU
DM respectivamente). Cuando se produce un reset ambas entidades inicializan a cero
sus números de secuencia de emisión y recepción.
Cada una de las entidades LLC puede finalizar la conexión enviando la PDU DISC.
Operación Tipo 3
En esta operación cada una de las PDUs transmitidas recibe confirmación. Se define
aquí una nueva PDU de información no orientada a conexión y reconocimiento ,la
PDU AC. Esta PDU no existe en el protocolo HDLC. Los datos enviados a través de
una PDU AC en modo mandato deben recibir la confirmación mediante otra PDU AC
en modo respuesta. Para el control de posibles perdidas de PDUs se emplea un
numero de
secuencia de 1 bit. El emisor alterna en sus PDUs los números de secuencia 0 y 1
136
,respondiendo el receptor en sus PDUs con el numero de secuencia opuesto al que
se recibió.
En este modo ,si el servicio es del tipo DL_DATA_ACK,el bit P/F es siempre 0. En
este caso la PDU AC en modo mandato contiene datos de usuario y en modo
respuesta no. Si el servicio es del tipo DL_REPLY,el bit P/F es siempre 1 y la PDU AC
contiene datos
de usuario si estos están disponibles ;lo contrario ,la no existencia de datos indica una
respuesta negativa.
1.4.6.2.3 Estructura del campo de control de la PDU LLC
El protocolo LLC sigue el modelo HDLC balanceado y tiene formatos y funciones
similares. La trama LLC consta de cuatro campos. LLC requiere las direcciones
fuente y
destino para identificar las dos entidades que se comunican. Tanto la fuente como el
destino son identificadas de manera unívoca por el par (nodo,SAP).
El formato del campo de control es el siguiente:
Formato I
1
2..8
0
9
Ns
10..16
P/F
Nr
9
10..16
P/F
Nr
Formato S
1
1
2
0
3
4
S
S
5
0
6
7
0
0
8
0
Formato U
1
1
2
3
4
5
6
7
8
1
M
M
P/F
M
M
M
Leyenda:
- Ns número de secuencia de la PDU LLC enviada.
- Nr número de secuencia de la última PDU LLC recibida correctamente.
- P/F bit encuesta/final .
- S bits cuyo valor indica el tipo de función de supervisión de la PDU LLC.
- M bits que determinan la función no numerada ejercida por una PDU LLC.
137
Al igual que en HDLC ,se definen tres formatos de tramas para la LLC : transferencia
de información ,supervisión y no numerada. Su uso depende del tipo de operación
empleada.
1.4.6.2.3.1 Formato I: Transferencia de Información
Este formato de PDU se utilizará en transferencias de información numerada en
operaciones de Tipo 2. Ns y Nr son números de secuencia de tramas que soportan
control de error y control de flujo. La estación emisora numerará sus tramas ,modulo
128 y pondrá su número en el campo Ns. Nr es un reconocimiento implícito. Permite a
dicha estación indicar el numero de la siguiente trama que espera recibir. Estos
números soportan control de flujo mediante el procedimiento de ventana deslizante.
1.4.6.2.3.2 Formato S: Supervision
Este tipo de PDU se utiliza para realizar funciones de control y supervisión del enlace
de datos en operaciones de Tipo 2 ,tales como un reconocimiento a una PDU LLC
con formato I o petición de suspensión temporal de transmisión de PDU Tipo 1.El tipo
de función que ejercerá
una de estas PDU vendrá determinado por los bits S del
campo de control.
RR REJ RNR
S4
S3
0
0
1
0
0
1
Sus misiones son idénticas a las tramas HDLC del mismo nombre. RR se emplea
para reconocer la ultima trama recibida indicando en Nr la siguiente trama esperada.
Esta trama se utiliza cuando no hay trafico en sentido inverso para llevar un
reconocimiento implícito. RNR reconoce una trama como RR ,pero solicita a la
estación emisora la suspensión de la transmisión. Cuando la estación receptora esta
de nuevo preparada envía una trama RR. REJ se utiliza para indicar que la trama con
numero Nr es rechazada y que esta ,así como las siguientes tramas ,deben ser
enviadas de nuevo.
1.4.6.2.3.3 Formato U: No numerado
Este formato se emplea en operaciones tipo 1 y 2 ,dependiendo de la función
especifica realizada (definida por los bits M) ,para proporcionar funciones adicionales
de control del enlace de datos e información no numerada:
SABME se utiliza por una entidad LLC para solicitar una conexión con otra entidad
LLC.
DISC se emplea para terminar una conexión lógica ;la estación emisora esta
anunciando que va a suspender las operaciones.
138
UA permite confirmar los mandatos anteriores.
DM indica ,en respuesta a una trama, que el LLC de la estación esta lógicamente
desconectado.
FRMR indica que se ha recibido una trama inapropiada
al protocolo.
AC se utiliza para información de reconocimiento en operación Tipo 3.
Los mandatos y respuestas en operaciones e Tipo 2 pueden ser PDU de formato I,S
y U. El mandato/respuesta de la operación Tipo 3 es de formato U.
1.4.6.3 Los estándares IEEE 802.3 ,IEEE 802.4 y IEEE 802.5.
Métodos de acceso al medio
Los distintos protocolos de arbitraje (acceso a la posibilidad de transmitir datos por la
red)que existen se explican a continuación:
Estándar IEEE 802.3 Método de acceso al medio por detección de la portadora
(CSMA/CD)
En este caso ,cualquier máquina puede iniciar una comunicación (acceso múltiple)
con sólo verificar que no haya ninguna otra comunicación en el cable ;para ello
detecta la presencia de portadora. La información que se está transmitiendo tarda un
cierto tiempo en recorrer la red. Una estación a la que todavía no le llegaron los
primeros bits podría iniciar una transmisión basada en que en ese momento no hay
señal. Un instante después le empezarán a llegar dichos bits ,pero como la
transmisión ya había comenzado ,las estaciones comprendidas entre ambas
máquinas recibirán la suma de las dos señales (colisión). El segundo transmisor debe
seguir transmitiendo un tiempo suficiente como para que el primero se entere de la
colisión. Esta acción recibe el nombre de atascamiento (jamming).
El peor caso de colisión se da cuando las estaciones están a la mayor distancia
posible y la segunda empieza a transmitir justo antes de recibir el primer bit ,pues al
tiempo de propagación de la señal de la primera estación a la segunda ,hay que
sumarle el de propagación del atascamiento. La suma de estos tiempos define la
"ventana de colisión". Para asegurarse la ausencia de colisiones no detectadas ,se
debe cumplir dos
condiciones:
- La transmisión debe durar más que la ventana de colisiones.
139
- La estación transmisora debe chequear la ausencia de colisiones durante ese
tiempo ;después no es necesario.
Una vez detectada la colisión ,ambas estaciones deben dejar pasar un tiempo
aleatorio antes de intentar retransmitir. Si se produce otra colisión ,se reintenta
esperando un tiempo mayor. El tiempo promedio de demora se duplica con cada
reintento. Puede haber colisiones múltiples. Es posible que una estación no pueda
comunicarse durante mucho tiempo debido a una sucesión de colisiones.
Estándar IEEE 802.5 Método de acceso al medio por paso de testigo en anillo
Basado en el protocolo de paso de testigo (token passing) al igual que el estándar
IEEE 802.4. Este sistema evita la colisión pues limita el derecho a transmitir a una
máquina. Esa máquina se dice que tiene el testigo (token o cospel). El testigo va
pasando por
cada estación a intervalos fijos. La circulación del testigo de una
máquina a otra hace que ,desde el punto de vista lógico ,toda red basada en testigo
sea un anillo. Un anillo lógico no implica un anillo físico. En efecto si bien el IEEE
802.5 emplea un anillo físico
,IEEE 802.4 especifica un bus y ARCnet usa una estrella. Por la red circulan dos tipos
de mensajes los testigos y los marcos (frames). Un testigo indica que la red está
disponible. El testigo incluye información de prioridad, de forma tal que el control de la
red lo pueda tomar sólo una estación con igual o mayor prioridad. Hay un
temporizador que asegura que ninguna estación retenga el token demasiado tiempo.
Un marco es un mensaje que contiene la información que se quiere trasmitir ,las
direcciones de las estaciones transmisora y receptora y un campo CRC de
comprobación de errores entre otras cosas.
La ventaja del IEEE 802.3 es que permite un mayor rendimiento para cuando hay
pocas colisiones. Esto ocurre cuando la mayoría de las transmisiones se originan en
la misma máquina o si relativamente hay poco tráfico en la red. La aplicación más
usual es para oficinas. La ventaja del IEEE 802.4 y 802.5 es que puede asegurarse
que ,independientemente del tráfico de una red ,una máquina va a poder transmitir
antes de un tiempo predeterminado. Esto tiene efectos positivos:
- El rendimiento de la red no disminuye tanto al aumentar el tráfico
- En sistemas de control donde es importante asegurarse de que un mensaje llegue a
su destino antes de que pase un cierto tiempo.
- Soporta un esquema de prioridades para el uso de la red.
El método de paso por testigo está más aplicado en la industria.
Estándar IEEE 802.4 Método de acceso al medio por paso de testigo en bus
Como principales ventajas ,que se tienen frente a la primera norma citada ,están la de
que el protocolo MAC de la IEEE 802.3 tiene un carácter más probabilístico y que en
el peor de los casos una estación podría tener que esperar demasiado tiempo para
transmitir una trama. Por otro lado la IEEE 802.3 no provee de un esquema de
140
prioridades para los distintos tipos de tramas ,este aspecto es muy critico en sistemas
de tiempo real donde las tramas con mayor importancia no pueden retenerse
por
mucho tiempo. Frente a la norma anterior la IEEE
802.5 los únicos aspectos que
las diferencian están relacionadas a la topología de la red.
Esta norma ,la IEEE 802.4 (Dirvin y Miller ,1986 ;IEEE ,1985) se le conoce por lo
general como paso de testigo en bus ,que físicamente es un cable lineal ,o en forma
de
árbol ,al cual se conectan las estaciones. Estas están lógicamente organizadas en un
anillo ,en el que cada estación conoce la dirección de su predecesora y su sucesora.
Cuando el anillo lógico se inicia ,la estación que tiene el número mayor es la que
puede enviar la primera trama. El derecho de acceso al medio viene regulado por una
trama de control denominada testigo (token). La estación que posee el testigo obtiene
el control del medio durante un período de tiempo determinado. Durante este tiempo
puede transmitir cuantas tramas desee ,consultar estaciones y recibir respuestas.
Finalizada la transmisión o el tiempo asignado cede el testigo a la siguiente estación
en el oren lógico ,que ahora tendrá el permiso para transmitir. El método de operación
consiste en fases alternadas de transmisión y transferencia e testigo. En la red
pueden existir estaciones que no hagan uso del testigo pero que, sin embargo, sigan
conectadas para responder a consultas o peticiones de confirmación.
Las direcciones de las estaciones sucesora y predecesora se determinan de forma
dinámica con el objetivo de mantener un único anillo lógico. Este anillo se crea y
mantiene de manera que las estaciones se ordenan lógicamente por orden
descendente de sus direcciones MAC ,a excepción de la última que tiene la dirección
MAC más baja que es seguida por la estación con la direcciona MAC más alta. Como
el testigo sólo lo puede tener una estación no hay problemas de colisiones.
El orden físico en el que se encuentran conectadas las estaciones al cable no es
importante. Al ser el cable de manera inherente a un medio físico de difusión ,cada
estación recibe cada trama descartando las que no van dirigidas a ella.
Cuando una estación pasa el testigo ,envía una trama de testigo específicamente a
su vecino lógico del anillo ,independientemente del lugar físico en que este se
encuentre. Cuando las estaciones se activan por primera vez ,estas no están dentro
del anillo ,así que el protocolo MAC tiene la capacidad para agregar o retirar
estaciones.
Para la capa física ,el paso de testigo en bus utiliza el cable coaxial de banda ancha
de 75 Ω,el sistema de cable de pares trenzados con o sin armadura está también
autorizado. También están autorizados tres tipos de modulación analógica: por
desplazamiento de frecuencia de fase continua ,por desplazamiento de frecuencia de
fase coherente y modulación por desplazamiento de fase modulada con amplitud
multinivel dúo binaria.
141
1.4.6.3.1 Visión general del IEEE 802.4
La esencia del método de acceso por testigo se puede resumir en los siguientes
puntos:
- Un testigo o token controla el acceso ordenado al medio físico ;la estación que
posee el testigo tiene momentáneamente el control sobre el medio.
- El testigo circula por todas las estaciones que residen en el medio. Se requiere la
existencia de un anillo lógico.
- El mantenimiento del anillo se asegura a través de las funciones proporcionadas por
las propias estaciones: iniciación del anillo ,recuperación del testigo ,adición y
eliminación de una estación y manejo general del anillo lógico.
El medio compartido puede utilizarse de dos formas: difusión y secuencial. La norma
IEEE 802.4 trata únicamente de la técnica de difusión ,en la que cada estación puede
recibir todas las señales transmitidas ;el medio se configura mediante un bus físico.
El subnivel de control de acceso al medio provee acceso secuencial al bus
compartido desde una perspectiva lógica ,ya que el control del medio se pasa de
estación a estación en un modo circular. El subnivel MAC (Control de Acceso al
Medio) determina cuándo la estación tiene acceso al medio compartido por
reconocimiento y aceptación del testigo emitido desde la estación predecesora y
determina cuando se debe pasar el testigo emitido a la siguiente estación.
Las funciones generales del subnivel MAC son:
- Temporización para la identificación de perdida del testigo.
- Iniciación de la transmisión.
- Tiempo de posesión del testigo (para múltiples servicios).
- Limitación de datos en el bus.
- Reconocimiento de direcciona de nodos.
- Encapsulado de tramas
- Generación de FCS (checksum) y verificación para detectar errores en la
transmisión.
- Reconocimiento de testigo valido.
- Adición de nuevos miembros al anillo.
- Recuperación de errores en un nodo.
El estándar IEEE 802.4 define el protocolo de control de acceso al medio token bus
para una topología en bus. Incluye tanto el nivel MAC como el nivel físico.
142
Elementos del IEEE 802.4:
- Subnivel MAC
Especificaciones de servicio , protocolo y unidades de datos
- Nivel físico
Especificaciones de servicio y especificaciones del medio físico
Las especificaciones de servicio MAC definen en términos funcionales el servicio
proporcionado por el IEEE 802.4 al LLC (control de enlace lógico) o cualquier otro
usuario de nivel superior. Estas especificaciones de servicio ocultan los niveles MAC y
físico al usuario del nivel MAC ,la utilización de una variedad de medios de
transmisión no debe ser visible al usuario excepto en aspectos de rendimiento.
El protocolo MAC es el núcleo del estándar 802.4. Las especificaciones describen la
estructura de trama y las interacciones que tienen lugar entre las entidades MAC.
Las especificaciones del nivel físico se dividen en dos partes para cada alternativa del
medio; una especificación de la entidad de nivel físico y una especificación del medio.
Cada especificación de la entidad de nivel físico incluye las características funcionales
,eléctricas y mecánicas necesarias para la transmisión y recepción de señales sobre
un determinado medio. La especificación del medio físico define las características del
medio físico ,sus componentes y los cables utilizados para la conexión de la estación
al medio.
1.4.6.3.2 Especificaciones de servicio del subnivel MAC (interfaz LLCMAC)
Los servicio proporcionados por el subnivel MAC permiten a la entidad local LLC
intercambiar unidades de datos LLC con entidades pares LLC. Las primitivas que
define el servicio MAC IEEE 802.4 son:
MA_DATA.request (dirección destino ,unidad de datos de servicio ,calidad de
servicio deseada).
En esta primitiva ,el parámetro calidad de servicio deseada tiene dos componentes.
El primero especifica la prioridad solicitada mientras que el segundo toma uno de los
valores siguientes:
- Request with no response. Se solicita simplemente al nivel MAC la transmisión de
datos en la unidad de servicio. El servicio MAC envía los datos en una MA_DATA
.indication manteniendo el valor del parámetro calidad.
143
- Request with response. Se solicita al usuario MAC remoto contestación a la
transmisión. El servicio MAC envía los datos en una MA_DATA.indication
manteniendo el valor del parámetro calidad.
- Response. Esta acción es respuesta a una anterior MA_DATA.indication que incluía
request with response en su parámetro de calidad de servicio. El servicio MAC envía
los datos en una MA_DATA.indication manteniendo el valor del parámetro calidad
,pasándole además el estado en una primitiva adicional de MA_DATA
.STATUS.indication
MA_DATA.indication (dirección destino ,dirección origen ,unidad de datos de
servicio).
MA_DATA.STATUS.indication (dirección destino ,dirección origen ,calidad de
servicio soportada).
El parámetro calidad proporcionada especifica la calidad de servicio realmente
proporcionada. El parámetro tiene dos componentes: prioridad y estado. El
parámetro
estado indica el estado del servicio proporcionado a una MA_DATA.request previa.
En el caso de un fallo local se pasa una indicación de error. Cuando el parámetro de
calidad de la solicitud especifique "request with response" ,se pasa igualmente una
indicación de error si se ha sobrepasado el número de reintentos permitidos sin
respuesta. Una indicación de éxito se pasa cuando ,en lo que concierne a la entidad
local MAC ,la petición ha sido resuelta de manera satisfactoria. Cuando el parámetro
calidad de la correspondiente petición especifica "request with no response" o
"response" ,la MA_DATA.STATUS.indication se pasa inmediatamente después de la
transmisión de la trama correspondiente. Cuando el parámetro calidad de la solicitud
indica "request with response" entonces se pasa la MA_DATA.STATUS.indication
cuando se recibe la trama solicitada de respuesta.
Estos servicios solo proporcionan conexiones de servicios de transferencia de datos
entre entidades pares LLC. De esta manera ,las entidades del control de enlace
lógico
pueden intercambiar unidades de servicio de datos LLC sin el establecimiento de una
conexión punto a punto. La transferencia de datos puede ser punto a punto o
multipunto.
1.4.6.3.3 Protocolo del subnivel MAC
La especificación describe la estructura de la trama y las interacciones que tienen
144
lugar entre las entidades MAC. La operación del anillo lógico en bus requiere
considerables aspectos de gestión y mantenimiento que deben ser realizados por una
o mas estaciones. En este apartado se analizan la estructura de la trama ,la gestión
del acceso al medio y el esquema de prioridades.
Estructura de la trama MAC
La figura siguiente muestra el formato de la trama del protocolo IEEE 802.4.
A continuación se explican más detalladamente cada uno de ellos.
Preámbulo un patrón de uno o mas octetos utilizado por el receptor para establecer
la sincronización de bit. (1 Byte).
Delimitadores de trama indican el comienzo y final de la trama. Contienen
patrones de señalización distintos a los datos. Su codificación es XX0XX000 donde X
representa
un símbolo carente de información. La forma de este símbolo depende de la
codificación de señal utilizada en el medio. (1 Byte).
según los dos primeros bits de mayor peso se puede distinguir entre
Control
tramas de datos LLC o tramas de control. Las tramas de control se emplean para
gestionar el protocolo de testigo en bus ,por ejemplo ,el propio testigo. En una trama
de control los seis bits de menor peso identifican su identidad. En una trama de datos
LLC los tres bits de menor peso indican la prioridad. Los restantes tres bits indican el
tipo de trama: solicitud sin confirmación ,solicitud con confirmación o trama de
confirmación. (2 Bytes).
Dirección Origen y Destino
igual que en IEEE 802.3 (de 2 a 6 Bytes).
145
contiene la unidad de datos de la LLC o información para control del modo
Data
de operación, cada dato esta formado por 1 Byte.
CRC
secuencia de verificación e trama igual que en IEEE 802.3 (4 Bytes).
1.4.6.3.4 Gestión de acceso al medio
Las funciones básicas de gestión y mantenimiento del acceso al medio deben ser
realizadas por al menos una estación. Estas funciones básicas son las siguientes:
- Adición al anillo ;las estaciones no participantes en el anillo deben tener
periódicamente la oportunidad de incorporarse al mismo.
- Eliminación del anillo ;una estación debe ser capaz por si misma de retirarse del
anillo.
- Iniciación del anillo ;cuando se arranca la red o esta se recupera de un fallo de
funcionamiento, debe suministrarse un mecanismo descentralizado que decida el
orden de iniciación del anillo.
- Recuperación del testigo ;son necesaria funciones de recuperación ante la perdida
del testigo.
En el procedimiento de inserción en el anillo cada una de las estaciones es
responsable de garantizar periódicamente la oportunidad de acceso a las nuevas
estaciones. En función de la situación de la estación en el anillo existen dos variantes
en el proceso:
En primer lugar esta el caso en que la estación es distinta a la ultima estación del
anillo. La estación , cuando tiene el testigo ,emite una trama de "solicitud de sucesor"
invitando a las estaciones que tengan una dirección entre la suya y la siguiente
estación en el anillo lógico a incorporarse al anillo. La estación emisora espera
durante un período de tiempo equivalente a dos veces el retardo de propagación del
medio extremo a extremo (ventana de respuesta). Puede suceder una de estas
situaciones:
a) No existe respuesta. La estación pasa el testigo a su sucesora como en el proceso
habitual.
b) Existe una única respuesta. Una estación ha respondido con una trama de
"establecer sucesor". La estación que tiene el testigo define su sucesor como la
estación que respondió y le envía el testigo.
c) Múltiples estaciones responden ;la respuesta que recibe la estación estará alterada
,debido a la colisión. El conflicto se resuelve mediante un mecanismo de contención
146
basado en las direcciones. La estación transmite una trama de "resolución de
contención" y espera durante cuatro ventanas de respuesta. Cada solicitante puede
responder en una de estas ventanas según los dos primeros bits de su dirección. Si
una estación solicitante escucha algo antes de que llegue su ventana se abstiene en
su respuesta. Si la estación poseedora el testigo recibe una trama valida de
"establecer sucesor" procede como en el paso b). En caso contrario vuelve a
intentarlo basándose en el segundo par de bits de las direcciones ,pudiendo
contestar sólo aquellas estaciones que respondieron la vez anterior. El proceso
continua hasta que se reciba una respuesta valida de "establecer sucesor" ,no se
reciba respuesta o se llegue al final de los bits de dirección. En estos dos últimos
casos ,la estación poseedora del testigo abandona su intento y pasa el testigo el
testigo como en el proceso habitual.
d) Respuesta invalida ;si la estación recibe una trama distinta a la de "establecer
sucesor" asume que otra estación piensa que tiene el testigo y ,por lo tanto ,para
evitar el conflicto ,vuelve a un estado de escucha.
En el segundo caso la estación que tiene el testigo es la ultima del anillo lógico o de
dirección más grande. Esta estación transmite una trama de "solicitud de sucesor 2" y
espera durante un período de tiempo equivalente a dos ventanas de respuesta. Las
estaciones con una dirección inferior a la de la estación emisora pueden responder
con una trama de "establecer sucesor" durante la primera ventana de respuesta.
Las estaciones con una dirección superior deben esperar durante una ventana de
respuesta. Si no escuchan nada pueden responder ;en caso contrario se abstienen
de
responder. El resto del proceso es equivalente al expuesto antes. El procedimiento de
eliminación del anillo es mas sencillo que el de adición. La estación que desea
retirarse del anillo espera a recibir el testigo y envía entonces una trama de
"establecer sucesor" a su predecesor conteniendo la direcciona de su sucesor. La
estación predecesora actualiza su variable de estación sucesora. La estación que
posee el testigo lo transmite a su sucesora. En la siguiente rotación la estación
predecesora a la que acaba de salir envía el testigo a la estación sucesora de esa
misma estación. Cada vez que una estación recibe el testigo actualiza el valor de la
variable de estación antecesora con la direcciona MAC de la estación emisora. El
mecanismo de iniciación del anillo arranca automáticamente cuando una o mas
estaciones detectan ausencia de actividad durante un período de tiempo superior al
valor del temporizador correspondiente. Los motivos habituales para la iniciación del
anillo son el comienzo de actividad de la red o la perdida del testigo.
Este mecanismo comienza con la transmisión de tramas de "petición de testigo" por
parte de las estaciones que han detectado la inactividad. El proceso para seleccionar
la estación que finalmente obtendrá el derecho a tener el testigo por primera vez se
basa en las direcciones de las propias estaciones. Las estaciones que emiten la
trama de "petición de testigo" rellenan el campo de datos para que esta sea un
múltiplo (0,2,4 o 6) de la longitud que se transmitiría en el tiempo de una ventana de
respuesta ,basándose en los dos primeros bits de su dirección. Después de transmitir
quedan a la escucha del medio y si detectan otra transmisión se retiran del proceso
de petición del testigo ,puesto que se deduce que otra estación ha transmitido una
trama de petición más larga.
En caso contrario continúan intentándolo ,ahora
147
basándose en el segundo par de bits de dirección. Cuando se han empleado
ya
todos los bits de dirección, la estación que finaliza en la ultima iteración se considera
como poseedora del testigo. A partir de este momento se reconstruye el anillo
mediante el mecanismo de adición descrito anteriormente.
Por ultimo ,es necesaria una labor de recuperación del testigo durante el propio paso
de testigo. Cuando la estación que tiene el testigo ,lo pasa a la siguiente ,queda a la
escucha durante un período de tiempo equivalente al doble del retardo de
propagación en el medio para asegurarse de que su sucesor se encuentra activo. El
proceso es el siguiente:
1- En el caso que el sucesor este activo ,escuchará una trama valida y lo da por
correcto el paso de testigo.
2- Si no escucha una trama valida reenvía el testigo por segunda vez.
3- Si después de dos intentos no escucha una trama valida ,supone que el sucesor
tiene algún fallo y envía la trama "quien es el siguiente" solicitando así la identidad de
la estación posterior a su sucesora. Si recibe una trama de "establecer sucesor"
procedente de dicha estación posterior actualiza su variable de estación sucesora y
transmite el testigo.
4- Si no recibe respuesta de la posterior estación a su sucesora ,envía una trama de
"establecer sucesor" a la que pueden contestar todas las otras estaciones de la red.
Si este proceso finaliza correctamente se establece el anillo con dos estaciones.
5- Si el paso 4 falla por dos veces la estación que desea pasar el testigo supone que
hay un fallo grave en la red (que todas las otras estaciones han abandonado el anillo
lógico ,el receptor de esta estación no funciona bien o que el medio ha fallado).
Llegado a este punto la estación cesa de transmitir y pasa al modo "escucha" del
bus.
Tramas de control para el paso de testigo en bus
0000 0000
reclamo
testigo
Reclamo del testigo durante el
inicio
0000 0001
solicito
sucesor 1
Permiso para que entren
otras estaciones
0000 0010
solicito
sucesor 2
Permiso para que entren
otras estaciones
0000 0011
quien
sigue
Recuperación del testigo
148
0000 0100
resuelve
contienda
Acceso múltiple al anillo
0000 1000
testigo
Paso de testigo
0000 1100
establece
sucesor
permiso para salir del anillo
1.4.6.3.5 Esquema de prioridades
El esquema de prioridades del paso de testigo en bus se aplica sobre los datos que
se transmiten ,al contrario que el paso de testigo en anillo en que las prioridades
afectan al propio testigo. Se definen cuatro niveles de prioridad o clases de servicio
,que en orden descendente son: 6,4,2,0 ,manteniendo una cola de tramas para cada
una de las prioridades. La utilización de prioridades es opcional ,por defecto la
prioridad asignada es la más alta. Cada estación estará internamente dividida en
cuatro subestaciones ,cada una de ellas teniendo asignada un nivel de prioridad.
Cuando la información de entrada llega a la parte superior de la subcapa MAC ,se
comprueba la prioridad de los datos y se encaminan hacia una de las cuatro
subestaciones. Cada una de las subestaciones mantiene su propia cola de espera
para la transmisión de tramas.
Cuando el testigo llega a una estación a través del cable ,pasa directamente a la
subestación con mayor prioridad ,la cual puede empezar a transmitir sus tramas hasta
que termine su tiempo ,para después pasar internamente el testigo a la siguiente
subestación de menor prioridad hasta llegar a la última. Al acabar esta subestación de
enviar sus tramas o que su temporizador haya expirado ,el testigo se pasa a la
siguiente estación del anillo. Si las subestaciones de mayor prioridad no usan todo su
tiempo asignado este se le añade al de las estaciones de menor prioridad.
Con este mecanismo la carga total del sistema regula la prioridad de las tramas que
pueden ser transmitidas siendo siempre las tramas de mayor prioridad las que salen
más beneficiadas. El objetivo de este esquema es gestionar la totalidad del ancho de
banda de la red en función de las tramas más prioritarias y transmitiendo las tramas
de menor prioridad siempre que exista un ancho de banda suficiente. Por eso se mide
el tiempo que tarda el testigo en dar la vuelta al anillo. Cada nivel de prioridad tiene
predefinido un tiempo de rotación del testigo que representa el tiempo máximo
permitido
para la circulación del testigo ,durante el cual puede realizarse la transmisión de las
tramas de ese nivel. Con la intención de evitar que una única estación monopolice la
149
totalidad de la red ,existe otro temporizador que limita el tiempo máximo durante el
cual una estación puede estar en posesión del testigo.
1.4.6.3.6 Estructura interna del subnivel MAC
El nivel MAC realiza varias funciones que se dividen de la siguiente manera:
Actúa como interfaz y buffer entre los niveles LLC y MAC ,
Maquina de interfaz
y entre la gestión de la estación y el nivel MAC ,interpretando todas las llegadas de
MA_DATA y otras primitivas de servicio ,y generando la apropiada salida de los
servicios básicos. Esta maquina maneja los parámetros de calidad de servicio desde
LLC al MAC. Realiza también el reconocimiento de dirección aceptando las tramas
dirigidas a su estación.
Coopera con las maquinas de control de acceso
Maquina de Control de Acceso
de otras estaciones para manejar el testigo y controlar el acceso al bus compartido.
Responsable de la utilización y mantenimiento del anillo lógico ,incluyendo la admisión
de nuevas estaciones. Ha de detectar y si es posible recuperar los fallos en el testigo.
Acepta entradas de símbolos ,desde el nivel físico
Maquina Receptora
ensamblándolos en estructura que son validas y transferidas a las anteriores
maquinas. Identifica la condición de ruido y silencio en el bus.
Acepta una estructura de datos desde la maquina de
Maquina Transmisora
control de acceso al medio y la transmite como una secuencia de símbolos en el
formato apropiado al nivel físico.
Es opcional, presente en estaciones
Maquina de Repetición Regenerativa
repetidoras. Repite el caudal de símbolos que recibe del nivel físico .
Especificaciones de servicio de la interfaz MAC-GESTIÓN DE
ESTACIÓN
Servicios proporcionados a , y por ,la estación de gestión de funciones para el
150
subnivel MAC de paso de testigo de la norma IEEE 802.4. Se trata de un servicio
local entre el subnivel MAC y su gestor ,que proporciona:
- reiniciación de la entidad MAC
- especificación de los valores de tiempo y contadores apropiados para la red.
- determinación de si la entidad MAC debe ser un miembro de un anillo y si su
dirección aparece como única en la red.
- especificación del conjunto de direcciones de grupo que la entidad MAC reconoce.
Especificaciones de servicio del nivel físico (interfaz PHY-MAC)
Los servicios proporcionados por el nivel físico se definen en términos de la siguientes
primitivas y parámetros:
- PHY_UNITDATA.request(símbolo) soporta la transferencia de datos desde una
entidad MAC a todas las demás entidades MAC de la misma red.
- PHY_UNITDATA.indication(símbolo) a medida que se recibe cada bit se genera
esta.
- PHY_MODE.invoke(modo) se utiliza para que el nivel físico seleccione uno de los
dos modos de operación: en origen o repetición. Esta primitiva es útil si una estación
esta conectada a mas de un segmento de red. En modo repetición esa estación
retransmite lo que "oye" por un segmento al otro. Si además de retransmitir también
funciona como
estación independiente se selecciona el segundo modo.
- PHY_NOTIFY.invoke se emplea para comunicar al nivel físico que deje de transmitir
al haber sido detectado el final de trama.
151
1.4.7 Descripción final de la red a implementar
LAN
Para el presente proyecto se implementará hasta la subcapa LLC de la capa de
enlace para la red local, puesto que las LANs no requieren una capa 3 (Red)
separada ,la capa 2 (Enlace) deberá incorporar las funciones o servicios esenciales
de la capa 3. La topología de dicha red será en bus y por lo tanto el método de
acceso al medio escogido será el IEEE 802.4 de paso de testigo en bus. Como medio
físico se empleará el RS485 con pares trenzados no apantallados (UTP) por
considerar un ambiente menos ruidoso en oficinas.
El programa de aplicación hará uso de los tres tipos de servicio: orientado a conexión
,no orientado a conexión con reconocimiento y no orientado a conexión sin
reconocimiento.
En el segundo caso no se soportará el servicio DL-REPLY, ya que con el servicio DLDATA-ACK se abarcarán todas las necesidades. La red se centrará en el control de la
planta y por lo tanto en la gestión de los diferentes Front-Ends ,por lo que las
funciones de las aplicaciones estarán restringidas exclusivamente al control de esos.
Para la red local LAN se emplearán equipos de PCs estándar.
BUS DE CAMPO
El bus de campo se implementará sobre el estándar RS485 con pares trenzados
apantallados (STP) por estar distribuido en campo ,con los posibles ruidos e
interferencias que pueden existir. La topología de estebus de campo será también en
tipo bus. El protocolo para el bus de campo a utilizar será el MODBUS modo RTU que
emplea la transmisión de octetos en vez de caracteres ASCII para una mayor
eficiencia.
Como equipos procesadores locales se dispondrán microcontroladores Altair
SAB80c537 y ordenadores portátiles convencionales para poder cambiar los
152
programas en caso necesario. El papel de los Front-End (enlace del bus de campo
con la red local) lo llevarán a cabo PCs.
A fin de adaptar las comunicaciones RS232 a RS485 se emplearán conversores
RS232/RS485 alimentados por los
propios equipos que los necesiten: PCs y
Front-Ends.
1.5 Descripción General
1.5.1 Bus de Campo
Esta parte del proyecto se llevará a cabo en las cercanías del proceso ,su misión es la
de poder comunicar los equipos ya presentes (controladores SAB80c537) con los
Front-End que se instalaran en la sala de comunicaciones del edificio de control. La
distancia entre la planta de proceso y el edificio de control es de 1 Km.
Los procesadores locales están instalados en armarios metálicos dentro de unos
2
recintos de 3 x 7 m y una altura libre de 2'8 m, la iluminación de los cuales es
totalmente artificial.
El cable empleado es del tipo para ampliación de distancia ,de baja capacidad para
entornos industriales
con cubierta de PVC. Cable de 4 conductores (de 2 pares
trenzados) cada par esta individualmente apantallado en aluminio además cada uno
con un hilo de drenaje. Distribuido en bobinas.
Capacidad de 39'4 pF/m ± 6'6 pF/m. Distancia máxima de hasta 1200 m.Diámetro del
conductor 7 x 32 AWG. Resistencia 5'3 Ω /100 m máximo. Referencia ERN04A de
Black Box.
Como conectores se empleara el tipo RJ11,los 2 pares se conectaran en paralelo a
los contactos centrales para disponer así de un doble canal ,aprovechando así uno de
los pares sobrantes (RS485 solo necesita un par ,pero lo mínimo por cable son 2
pares). Para más detalle consultar el siguiente esquema de conexión.
153
Los protectores contra sobretensión serán del tipo barra terminal de tecnología
basada en diodos y de 2 hilos (los 2 pares se conectaran al igual que en el caso
anterior) ,permitiendo funcionar a una velocidad de transmisión de 1'5 Mbps con baja
capacidad (para una mínima pérdida de señal). Referencia SP121A-R2 de Black Box
,limitación de voltaje ±6'8 V. Capaces de manejar picos de hasta 5 kV. Serán
instalados a la salida del puerto RS485 del microcontrolador SAB80c537 ,el cable de
interconexión estará enchufado por presión dentro de la regleta de dos polos de la
citada salida y apretado por tornillo ,de la misma manera en los terminales de
conexión del dispositivo protector de tensión.
Los hilos de drenaje irán conectados junto con la toma de tierra del protector a la
barra de compensación de potencial de los armarios donde están situados los
microcontroladores. La distancia entre los protectores barra terminal y la barra de
PAS no será superior a 15 cm. En el otro regletero del mismo protector ,se conectara
el cable derivador enchufándolo dentro y apretándolo con tornillos. En el extremo final
de dicho cable se instalara el conector tipo RJ11 que se conectará por presión a la
caja de derivación correspondiente.
Las cajas de derivación serán del tipo adaptador de 3 vías (referencia RS186-3082)
con "Jack" para conector RJ11 (referencia RS477-337 ,de 6/4 pares útiles ,material de
fabricación: resina de ABS UL90V-O ,de poliéster negro ,cumplen con la FCC68)
,estarán encajadas dentro de "rosetas" en cajas ,referencia RS210-5804. Las
derivaciones estarán colocadas dentro de cajas estancas apantalladas contra RF de
color blanco ,referencia RS501-547, los cables tendrán prensa-estopas de PVC de
diámetro igual al del cable para ajustarlos a dichas cajas y luego irán sellados con
silicona para mayor aislamiento contra la corrosión y la humedad de las galerías.
El cable principal o bus de campo se instalara en racks dentro de las galerías de paso
de cables de electricidad. La manera correcta de instalarlos se puede observar en el
2
apartado de planos. Las cajas de derivación se colocarán en arquetas de 30 x 40 cm
a 20 cm por debajo del nivel del suelo para
su
comprobación
visual
y
mantenimiento sin tener que bajar a las galerías. Seguir los consejos para la puesta
en marcha y funcionamiento así como de los esquemas al final de dicho apartado.
Para conectar el bus principal a los Front-End se procederá como antes ,vigilando la
correcta colocación de los equipos de protección contra tensión mencionados.
154
1.5.2 Red Local
Esta otra parte se realizará dentro del edificio de control y su misión será la de enlazar
los PCs Front-End con los PCs Workstations de cada departamento involucrados.
Todos los Front-Ends estarán situados en la misma sala de comunicaciones de 7 x 10
2
m y una altura libre de 3'2 m ,con una iluminación natural a través de 4 ventanas de
1'5 m x 1'2 m .La distancia de estos a los equipos de los diversos departamentos no
será superior a 500 m.
Los PCs Front-End estarán instalados en armarios metálicos separados entre si por
una chapa metálica. Todas las partes metálicas accesibles estarán con su
correspondiente puesta a tierra. En estos equipos se emplearan protectores de
tensión del tipo conexión rápida. Limitación de voltaje ± 18V. Modelo de dos hilos
,tecnología basada en diodos y de baja capacidad para disminuir la perdida de señal.
Fácil instalación ,conexión por inserción directa en el conector del protector. Conexión
de la toma de tierra al chasis del armario. Referencia SP600A de Black Box. Estos
equipos se instalarán a la salida de las tarjetas conversoras de RS232/RS485 de los
PCs.
En principio exitirán 26 Workstations y 6 Front-End dentro de la red Local.
El cable derivador se enchufará dentro de la regleta dedos polos de la tarjeta
conversora se fijará mediante tornillos. En el extremo final de dicho cable se instalará
el conector tipo RJ11 que se conectará por presión a la caja de derivación
correspondiente. El tipo de caja de derivación es la misma que para el bus de campo.
No se ha hecho ningún estudio sobre el SAI (Sistema de Alimentación Ininterrumpido)
por no conocerse la posible ampliación de la red. En caso de necesitar un equipo
provisional ,consultar cualquier modificación a realizar en este contexto al director de
obra o en su defecto al proyectista.
Tanto el cable derivador para cada nodo de la red ,como el cable de bus o principal
serán del mismo tipo UTP. El cable empleado es del tipo para datos de 2 pares
trenzados sin apantallar. Los conductores serán de cobre estañado ,de 7/0'25 mm
diámetro del conductor 22 AWG, con cubierta de PVC gris. Capacidad 164 pF/m y
atenuación de 3.9 db/100 m a 1 MHz y 8 dB/100 m a 10 MHz. Resistencia menor de
5'3 Ω /100 m.Impedancia característica 85 Ω. Temperatura de funcionamiento de o
o
30 C a +70 C.Referencia ECN04A de Black Box.
Las separaciones entre los cables de datos y de alimentación eléctrica deberán
respetar una distancia
mínima de 10 cm.
155
Los 2 pares se conectaran en paralelo a los contactos centrales para disponer así de
un doble canal,así se aprovecha uno de los pares sobrantes (RS485 solo necesita un
par ,pero lo mínimo por cable son 2 pares),también dará mayor seguridad en caso de
rotura de uno de los pares.
Todos los cables desde la sala de comunicaciones a los distintas "workstations" de
cada departamento irán protegidos dentro de una canaleta de PVC.
Cuando tengan que pasar por el suelo se emplearan cubrecables con los bordes
biseladas para evitar accidentes o daños en los equipos. Serán del tipo goma no
2
tóxica y combustión retardada de 8 x 14 mm fabricado por Misco.
Para la red local no se instalará ningún tipo de alimentación auxiliar o sistema de
alimentación ininterrumpida (SAI) a no ser que no este instalado por defecto ,a tal
efecto se deberá consultar dicha modificación al director de obra.
En principio la instalación dará cobertura a 32 estaciones ,al igual que en el bus de
campo. Para otras ampliaciones se podrá emplear el código de programa del mismo
software ,pero se tendrá que configurar una estación como repetidora.
1.5.3 Adaptación del protocolo de bus de campo MODBUS a los
equipos SAB80c537
1.5.3.1 Descripción general
Comunicaciones serie por el puerto 0 RS485 sin paridad y 1 bit stop por defecto (no
configurable).Trabajo en modo normal, velocidad variable y dirección del dispositivo
esclavo configurable. Dip 8 pines conectado a P8 (P8.0 ... P8.4 dirección esclavo y
baudios)la petición INT0 activa la posibilidad de configuración externa. 1ª petición
para lectura parte alta en BCD de la dirección ,2ª petición para lectura parte baja en
BCD y 3ª petición para lectura valor binario de la tabla de configuración de velocidad
de las comunicaciones.
NID es el número de identificación del tipo de equipo esclavo ,en nuestro caso
(μ80C537).Se calcula haciendo la XOR de la mitad de los caracteres del nombre del
microcontrolador para formar la parte alta del número de identidad y la otra mitad para
la parte baja ,en este caso:
8 xor0 xorC = 4
5 xor3 xor7 = 1
156
Luego la ID del 80C537 es 41 hex.
SOFTV es la versión del software instalado en este caso es la primera versión. TBUS
es el tipo de bus empleado en nuestro caso 39 hexadecimal que equivale a un bus
MODBUS tipo RTU.
El dispositivo Maestro envía siempre una Unidad de datos simple (SDU) tipo:
/xxx/xxxx para direcciones y para datos (x significa un valor '0' o '1' lógico). El
dispositivo Esclavo al inicio o reset del controlador tiene RX8 a '0' por lo que todos
escuchan al Maestro enviar la dirección destinataria ,luego el destinatario pone su
RX8 a '1' para escuchar los datos del maestro, al acabar de recibir el mensaje y enviar
su respuesta al acabar pone de nuevo su RX8 a '1'.
RX8
Estado
0
escucha
1
escucha y atiende
Las entradas analógicas del puerto 7 empleadas ,tendrán una imagen de su valor en
las posiciones RAM interna $80..$87 ,además hasta la $FF se considerarán registros
de entrada referenciados como 3x. Para acceder a ellos se ha de especificar los
registros en el rango 0...127 que equivalen a $80..$FF.Los registros de memoria
extendida son de un byte en vez de dos ,por lo que la parte alta se desprecia y en las
lecturas a dichos registros aparecerá como cero.
1.5.3.2 Descripción de la disposición de la memoria externa de DATOS
9048
9049
904A
904B
capacidad RAM interna (Bytes reales=(nºBytes ,valor en tabla) +1Byte)
capacidad ROM interna (Bytes reales=(nºBytes, valor en tabla) +1Byte)
capacidad RAM externa (Kb reales= (nºKb ,valor en tabla) + 1Kb)
capacidad ROM externa (Kb reales= (nºKb ,valor en tabla) + 1Kb)
MODBUS CONTROL AREA: dirección 93E0
93FF
93FE
93FD
93FC
9053
bits parada
9052
paridad
9051
estado Bus
9050
dirección
904F
baudios
904E
tipo Bus
904D
Versión soft.
904C
ID esclavo
904B
ROM ext.
904A
RAM ext.
9049
ROM int.
9048
RAM int.
9047
num. ports
157
9046
num. AO
9045
num. AI
9044
num. DO
9042
num. comms
9041
num. timers
9040
num. A/D
9043
num DI
MODBUS STATUS AREA: dirección 93D8
9039
9038
nº tramas procesadas
CRC incorrecto
9037
contador Ocupado
9036
contador Difusión
9035
dirección incorrecta
9034
función incorrecta
9033
referencia incorrecta
9032
tramas incorrectas
9031
nº tramas enviadas
9030
nº tramas
recibidas
BUFFER INPUT CONTROL AREA: dirección 9000..903F
9003
Timeout
9002
nº bytes eventos
9001
nº bytes en el
buffer entrada 2
9000
nº bytes en el
buffer entrada 1
Otros:
9004 Timer 0
9005 dirección a establecer
9006 velocidad de transmisión a establecer
9010..901F buffer secundario
9020..90FF control y estatus
BUFFER OUTPUT CONTROL AREA: dirección 9007..9010
91E0
nº bytes en el
buffer salida
158
BUFFER INPUT AREA: dirección 9100 .. 91FF
BUFFER OUTPUT AREA: dirección 9200 .. 92FF
EVENT BUFFER AREA: dirección 9300 .. 93FF
- Disposición de la memoria externa de DATOS 9400..4FF
9500..5FF
9600..6FF
9700..7FF
9800..8FF
9900..9FF
9A00..AFF
9B00..BFF
9C00..CFF
9D00..DFF
9E00..EFF
9F00..FFF
archivo 1 de Registros de Memoria Extendida
archivo 2
archivo 3
archivo 4
archivo 5
archivo 6
archivo 7
archivo 8
archivo 9
archivo 10
archivo 11
archivo 12
Nota* Las zonas de memoria "vacias" se emplearan para
posibles ampliaciones o depuración del programa.
1.5.3.3 Descripción de la disposición de la memoria externa de
PROGRAMA
8000
80FF
Vectores de Interrupción
8100
82FF
Tablas para calculo del CRC
8300
87FF
Programa principal
8800
8BFF
Rutinas MODBUS
8C00
8FFF
Rutinas generales
(*) NOTA: Los espacios reservados entre las direcciones 8000...80FF y 8100..82FF
son fijas para todos los microcontroladores instalados, las demás direcciones son a
titulo de ejemplo de cómo se distribuiría la memoria .
159
1.5.3.4 Descripción de la asignación de los recursos
A continuación se describe como se han adaptado las capacidades del
microcotrolador SAB80c537 al protocolo MODBUS RTU empleado para este
proyecto.
Puerto
Pin
Función
P4
0..7
puerto de salida digital
P5
0..7
puerto de entrada digital
P7
0..7
puerto de entrada analógica
8 canales multiplexados
P8
0..3
DIP 8 configuración (*)
(*) Nota: La dirección viene codificada en BCD ,1º se entra la parte alta de la dirección
y luego la parte baja. La velocidad de transmisión corresponde a los valores binarios
de la siguiente tabla.
Valor
Dip
0000
0001
0010 *
0011 *
0100
Baudios
1200
2400
4800
9600
19200
Entrada de configuración por el DIP 8 (uso del puerto nº8 del microcontrolador
SAB80C537)
0
0
0
0
X
X
X
X
Dirección esclavo 0 (difusión) , 1..31 (individuales) valor en BCD
(ej. dirección 17 = 0000 0001 + 0000 0111)
0
0
0
0
x
x
x
x
Velocidad de transmisión (ver tabla) valores binarios validos de 0000 0000 ... 0000
00100
160
0
0
0
0
0
x
x
x
1.5.3.5 Conformidad con el protocolo MODBUS RTU
Una vez adaptadas las capacidades del SAB80C537 al protocolo MODBUS ,se
observa que no todas las funciones MODBUS RTU pueden ser soportadas por este
equipo. A continuación se detalla una lista de las funciones MODBUS adaptadas a las
posibilidades del microcontrolador (Nota: las direcciones citadas están en
hexadecimal).
Funciones MODBUS
asociadas
Controladores Modicon
Controladores Altair
1,5,F
Salidas discretas
ref. 0x
Salidas discretas
puerto 4
2,
Entradas discretas
ref. 1x
Entradas discretas
puerto 5
3,6,10,
16,17
Registros
ref. 4x
4,
Registros de
entrada ref. 3x
14,15,
Registros
memoria Direcciones RAM ext.
extendida ref. 6x
9400..9FFF
7,
Estado de 8 relés de Dirección RAM interna 2F y
excepciones
interrupciones
externas 4 ,5 y 6
de
retención Bancos 0..3
RAM interna
de
registros
Puerto 7 entradas
analógicas (imagen en $80.
..$87)además hasta la $FF
Funciones MODBUS no soportadas:
- Lectura de la cola FIFO (18) Ya que además de los registros de retención permite
otros.
- Diagnostico Modbus (08) subfunción Devolución registro de diagnostico(02)
Ya que no se realiza diagnostico interno
- Diagnostico Modbus (08) subfunción Cambio de delimitador ASCII(03) Porque
sólo se emplea MODBUS RTU.
161
- Diagnostico Modbus (08) subfunción Devolución de contador NAK enviados
por el eslavo(16) Al no enviarse NAK ,en caso de fallo en comunicación o error en el
mensaje.
- Diagnostico Modbus (08) subfunción Devolución de contador overrun(18) Este
controlador no soporta a la detección de overrun.
- Diagnostico Modbus (08) subfunción (19,20,21)
1.6 Prescripciones Técnicas
Reglamentos y normas seguidos en el presente proyecto:
- Normas DIN ,UNE ,EN y ISO.
- Normas IEC y IEEE 802.4 y 802.2
- Estándares IA/TIA-232E (V.24) y EIA/TIA-485.
- Documento EIA/TIA-574 (DB9).
- Normas CEI.
- Reglamento de Baja Tensión (MIE BT 021 ).
- Norma Tecnológica de la Edificación - IEP.
- Disposiciones generales de aplicación de la Ordenanza General de Seguridad e
Higiene en el Trabajo.
Relación de normas y reglamentos específicos aplicados
- Puesta a tierra según NTE-IEB y DIN VDE 0100 ,puesta a tierra y compensación de
potencial (DI VDE 0160) para toda parte inactiva de sistemas eléctricos que incluso
en el caso de anomalía no tendrán tensión.
- Conexión a masa de pantallas CEI 364.
- Este equipo cumple con la EN55022 clase A o FCC parte 15 ,subparte J ,clase
A.(Esta diseñado para proveer una protección razonable frente a interferencias y así
no causar interferencias perjudiciales a otros equipos ,pero por contra no rechaza
cualquier interferencia recibida ,incluyendo la interferencia que pueda causar una
operación indeseada).
- Compatibilidad electromagnética para equipos de medición y control según DIN VDE
0843 (CEI 108).
- Estándar EN 50082-1:
- Normas IEC 801-3 acerca de la inmunidad a la radiación.
- Normas IEC 801-4 aplicadas a transitorios eléctricos rápidos.
- Normas IEC 801-2 sobre descargas electrostáticas. Consultar los anexos.
- Métodos y precauciones en la medida de la resistividad superficial de materiales
aislantes eléctricos descritos en la norma UNE 21303.
- IEC950 protección de equipos frente a sobre voltajes.
- Autómatas programables y periféricos ,especificaciones de seguridad para aparatos
electrónicos y relacionados alimentados por la red según DIN VDE 0860 (CEI 65A).
- Grados de protección IP según UNE 20324.
162
- Código de resistencias según DIN 41429.
Para el mantenimiento:
- Barra de puesta a tierra colocada según NTE-IEB 59.
- Línea principal de tierra en conducto de fabrica según NTE-IEB 60.
- Arqueta de conexión según NTE-IEP 6.
- Puesta a tierra provisional según NTE-IEP 7.
- Procedimiento de medición de compatibilidad electromagnética según DIN VDE
0847.
- Aparatos de medición para la evaluación de la compatibilidad electromagnética
según DIN VDE 0847.
(los dos apartados siguientes deben haberse cumplido por el constructor del
edificio )
2
2
- Cable de enlace con tierra de cobre mínimo 35 mm y mínimo 95 mm si el cable es
de acero galvanizado ,según RBT.
- Piqueta de acero cubierta de Cobre mínimo 2 m de longitud y 1'4 cm de diámetro,
según RBT.
163
1.7 Puesta en marcha y funcionamiento
Disponer los controladores de campo a una distancia de seguridad de fuentes de
perturbaciones (ej. lámparas fluorescentes o fuentes de potencia), inspeccionar la
correcta separación de los armarios pequeños que contengan una parte de control de
la de potencia por una chapa metálica atornillada al chasis (Ver figura al
final del
capítulo). Si la iluminación de los armarios es fluorescente verificar que estos tengan
colocada una rejilla pantalla y sean alimentados por un cable apantallado ,accionados
por un interruptor blindado y con un filtro de la red incorporado. La alimentación de
c.a. de los ventiladores de los armarios y la de los controladores de campo debe
tomarse de fases distintas.
La alimentación para las fuentes de alimentación del equipo de automatización ha de
tomarse también de una fase distinta a los contactores ,válvulas solenoides
,etc.
Comprobar que la conexión de los terminadores de línea mediante los jumpers (J9
según esquema de la placa del microcontrolador ,ver apartado de planos) sólo se
realice en los equipos de final de línea y que este bien hecha. Los procesadores
80c537 han de tener los puentes J10 y J11 cerrados para permitir la comunicación
RS485 y RS232.
Verificar que los racks estén bien sujetos por los marcos de sujeción a las paredes y
que los conductos respeten las distancias mínimas de seguridad para evitar
interferencias ver esquemas de montaje al final de este capítulo). Se recomienda el
uso de racks y conductos para cables hechos de chapa de acero ,conectados al
sistema de compensación de potencial (ver figura al final del capitulo).
Comprobar el correcto estado del cableado del bus de campo (STP ,pares trenzados
apantallados) desde los armarios de campo hasta la sala de comunicaciones del
edificio de control central ,por si hubiese alguna rotura de los cables. No mezclar los
cables y enrollar los cables sobrantes (ver figura al final de este capítulo). Evitar
colocar en paralelo cables de transmisión de señales de clases diferentes: de
potencia ,de control ,y de medida. Limitar lo mas posible la longitud de los cables.
Separar lo mas posible los cables que conducen señales de clases diferentes: la
distancia mínima entre cables de potencia y cables de señal digital ha de ser de 10
cm
,mientras que entre los cables de alimentación y los de transmisión de datos o
164
analógicos ha de ser de 30 cm(ver figura al final del capitulo). A mayor longitud de los
cables de distintas clases de señales ,mayor separación entre ellos.
Es recomendable que el trenzado de los cables de señal sea de 20 vueltas por metro
y de 5 a 10 vueltas por metro para las líneas de alimentación eléctrica. Los
conductores sueltos o no utilizados de un cable deben estar sistemáticamente
conectados a masa (chasis, canaleta ,armario) en los dos extremos. Montar de forma
que se crucen en ángulo recto los conductores o cables que conduzcan señales de
clases distintas. Los conductos de cables para alimentación c.c y c.a. han de estar
separados ,cuanto más mejor.
Inspeccionar la correcta conexión de la pantalla o blindaje protector del bus en los
extremos de este (comprobar la correcta puesta a tierra de la planta) y en zonas
intermedias a masa. Verificar que se haya
realizado un correcto mallado
sistemático de todas las estructuras metálicas ,bastidores ,chasis ,conductores de
masa ,etc. entre si. Reducir lo mas posible la superficie de los bucles de masa. Es
necesario garantizar la
continuidad del plano de masa entre 2 armarios. Descubrir si hay algún tipo de pintura
o revestimiento
aislante en el plano de masa o barra de masa.
Conexión del equipo de protección contra sobretensión
directamente en los
cables de bus en cada uno de los extremos de cada estación y conexión de estos
equipos de protección a la barra de compensación de potencial (PAS).
Comprobar la correcta conexión del cable de cada nodo (drop cable) a la caja de
derivación (tap) para unirlo al cable del bus (trunk cable).
Hacer pruebas del correcto funcionamiento del software y las comunicaciones a nivel
de bus, empleando un PC portátil para volcar el programa de los procesadores
locales y ver el estado interno de registros y memoria con ayuda del programa
EDITOR51.BAT de IBERCOMP S.A.
Probar todas las funciones MODBUS RTU y evaluar el comportamiento frente a
"roturas simuladas" de la línea o interferencias.
Verificación de los correctos niveles de tensión tanto a la entrada como la salida de
las tarjetas conversoras de RS232/RS485 ,han de cumplir con las especificaciones
eléctricas de dichos estándares. Comprobar el correcto aislamiento en los anteriores
interfaces.
Verificar que la conexión de los terminadores de línea sólo se realice en los equipos
de final de línea y que este bien hecha ,la impedancia en los extremos del bus debe
tener un valor no inferior a 50 Ω . Revisar la conexión desde los conectores de las
tarjetas conversoras a las cajas de conexión.
Comprobar el correcto estado del cableado de la red local (UTP ,pares trenzados no
apantallados) sobretodo evitando ser colocados cerca de superficies que estén a una
165
temperatura elevada y que no estén aprisionados por el mobiliario o fuera de las
canaletas de plástico.
Inspeccionar el estado final de los cubrecables ,para evitar posibles deformaciones
que puedan ser origen de caídas por tropiezos.
Evaluar las comunicaciones en la red primero ,haciendo pruebas simulando roturas
en el cable de transmisión ,incorporando nuevas estaciones o eliminando otras del
anillo lógico. Después de esto ,comprobar el correcto funcionamiento global del
sistema comunicando desde
los PCs centrales con los controladores locales de
campo. Los procesadores locales han de ser configurados con direcciones en orden
ascendente empezando desde 1 hasta 32. Cada nuevo equipo que se instale se ha
de actualizar en el programa del Front-End correspondiente al bus donde se
encuentre este.
1.8 Planificación y control
- Actividades a desarrollar Capítulo 1 Instalación del bus de campo
Capítulo 2 Instalación del programa de bus de campo en los procesadores locales y
en los Front-End.
Capitulo 3 Puesta en marcha y funcionamiento del bus de campo. Capítulo 4
Instalación de los interfaces en los PCs y en los procesadores Front-End.
Capítulo 5 Instalación de la red local.
Capítulo 6 Instalación del programa de red local en las Workstations (en los Front-End
dicha instalación se realiza en el capitulo 2 ,al soportar estos tanto el manejo del bus
de campo como la actuación en la red local).
Capitulo 7 Puesta en marcha y funcionamiento conjunta de la red local y del bus de
campo.
166
Capítulo 1
Instalación del bus de campo
1) Conexión de los terminadores de línea mediante los jumpers (sólo los equipos de
final de línea).
2) Montaje de racks ,conductos para cables y marcos de sujeción necesarios para
instalar los cables de señal.
3) Cableado del bus de campo (STP) desde los armarios de campo hasta la sala de
comunicaciones del edificio de control central .
4) Conexión de la pantalla protectora del bus en los extremos de este y en zonas
intermedias a masa.
5) Conexión del equipo de protección contra sobretensión directamente en los cables
de bus en cada uno de los extremos de cada estación y conexión de estos equipos de
protección a la barra de compensación de potencial (PAS).
6) Conexión el cable de cada nodo (drop cable) a la derivación (tap) para unirlo al
cable
del bus (trunk cable).
Capítulo 2 Instalación del programa de bus de campo en los procesadores
locales y en los Front-End.
1) Copiar los programas en memoria e instalarlos.
Capitulo 3 Puesta en marcha y funcionamiento del bus de campo.
1) Pruebas del correcto funcionamiento del software y las comunicaciones.
167
Capítulo 4 Instalación de los interfaces en las Workstations y de los Front-End.
1) Conexión de las tarjetas conversoras RS232/RS485.
2) Verificar niveles de tensión correctos.
Capítulo 5 Instalación de la red local.
1) Conexión de los terminadores de línea mediante los jumpers (sólo los equipos de
final de línea).
2) Montaje de conductos para pasar los cables de señal.
3) Cableado de la red local (UPT) desde la sala de comunicaciones hasta la sala de
control del edificio central .
4) Instalación de las cajas de conectores del tipo RJ11.
5) Conexión del cable (UTP) de los conectores de cada tarjeta conversora a los
conectores de las cajas de conexión.
6) Montaje de los cubrecables para pasar cables por el suelo.
Capítulo 6 Instalación del programa de red local de los Front-End y de las
Workstations.
1) Copiar programas en memoria e instalar las aplicaciones.
Capitulo 7 Puesta en marcha y funcionamiento conjunta de la red local y del
bus de campo.
1) Pruebas del correcto funcionamiento del software y las comunicaciones.
168
1.8.1 Planificación
Capítulo
Tiempo
mínimo
días
Tiempo
recomendado
días
1
7
9
2
1
1
3
1
2
4
1
1
5
5
6
6
1
1
7
1
2
1.8.2 Diagrama de tiempos
Capítulo
/ Días
1
1
X
2
X
3
X
4
X
5
X
6
X
2
3
4
5
X
X
169
6
7
7
X
X
8
X
X
9
X
X
10
X
X
11
X
12
X
X
X
13
X
14
X
1.9 Resumen del presupuesto
Del total de la suma de los 3 capítulos ,una vez contemplados los gastos generales y
los beneficios ,y de haber aplicado el I.V.A. ,nos queda un TOTAL FINAL de: NUEVE
MILLONES OCHENTA Y CINCO MIL SETENTA Pesetas.
TOTAL PRESUPUESTO :
9.085.070 Ptas
54.603 Euros
170
Fecha: 13-3-2000
Firmado:
1.10 Glosario
ACR (relación atenuación a diafonía) Es la diferencia entre la atenuación y el NEXT.
ANCHO DE BANDA Relación de velocidad para la transmisión de datos medidos en
Kbps (kilobytes por segundo) y que representa la capacidad del canal de
comunicación para transportar los datos.
ATENUACIÓN la disminución de la fuerza de una señal cuando viaja a través de un
cable, se expresa en términos de dB/304'8 m. A menor gama de dB, el cable es
mejor.
BACKBONE NETWORK Red de infraestructura. Red que actúa como conductor
primario del trafico de datos de la red.
BROADCAST Transmisión abierta, los mensajes se envían sin destino especifico.
CCITT Comité Consultivo Internacional de Telegrafía y Telefonía. Encargado de los
estándares internacionales de comunicación.
CROSSTALK (Diafonía) es causado por las interferencias de los pares adyacentes en
los cables que están mal apantallados. Es el traspaso no deseado de una señal de un
circuito a otro.
FULL DUPLEX Característica de un canal de comunicación en el que los dos
terminales pueden mandar y recibir información a la vez.
IEEE Agrupación de ingenieros que, entre otras funciones documenta todos los
desarrollos tecnológicos.
INTERFACES Conectan los dispositivos a la red y hacen posible la comunicación con
otros dispositivos.
171
ISO Organización Internacional de Normas. Organización que específica estándares
de calidad internacionales.
LAN Red de área local
MARISA (Ver OSI)
MASTER/SLAVE Esquema que permite a dos dispositivos conectarse y comunicarse
al bus de manera sincronizada. El master decide si es él o el otro dispositivo el que
interactua.
MEDIO DE TRANSMISIÓN Proporciona el enlace físico que lleva la información de
un punto a otro de la red.
MIT Cable de par trenzado sin blindaje.
NEXT (Near-End Crosstalk) Definición de la EIA/TIA 568 que especifica la capacidad
de un cable para rechazar las interferencias (diafonías) desde los pares en extremo
más cercano o en el emplazamiento "local". Se expresa en dB. El NEXT par a par
mide la diafonía entre cualquiera de los dos pares del cable.
NODO Estación de trabajo con identificación propia que puede ser fuente y destino en
la red.
OVERHEAD Tiempo de proceso necesario para que se ejecuten los comandos antes
de que un dispositivo este listo para dar acceso.
PROTOCOLO Son las reglas y convenciones que controlan el intercambio de
información.
PS NEXT (Power Sum NEXT) Es una medida más rigurosa del Crosstalk o Diafonía,
mide toda la Diafonía posible entre un par y los pares adyacentes en la misma funda
del cable. El PS NEXT es el método requerido por la TIA para medir el NEXT en
múltiples pares (más de cuatro pares) del cable backbone.
RELACIÓN DEL RETARDO Es la diferencia en nanosegundos entre el tiempo
cuando el primer y último bit de un sólo byte paralelo de datos se reciben en el cable.
REDIRECTOR Conjunto de servicios de software de nivel aplicación que permiten
interactuar con la red.
RJ11 Conector para MIT 2 pares.
RJ45 Conector para MIT 4 pares.
TAP Terminador de línea (suele ser una resistencia con una
adecuada para que la señal transmitida por el bus no rebote).
172
impedancia
TERMINADOR Componente del cableado que iguala la impedancia característica el
cable para regular las señales eléctricas en la red.
TOPOLOGIA Es la forma física de interconexión entre los dispositivos de la red.
TRANSCEPTORES Unidades de interfaz de red que proporcionan la inteligencia
necesaria para leer direcciones de los mensajes y realizar otras funciones de
comunicación orientadas a la red.
TRANSDUCTOR Dispositivo que convierte una energía de un tipo a otro tipo.
TRUNK Derivador del bus, permite conectar cada nodo al cable principal de una red.
OSI
(Interconexión de Sistemas Abiertos) Estructura lógica de siete niveles, para
facilitar la comunicación entre diversos sistemas de computación.
1.11 Anexos
- Apéndice MODBUS RTU
- Instrucciones de los microcontroladores MCS-51 y sinópticos de la CPU Altair 537
- Manual del SAB80c537
- Generadores de descargas electrostáticas según IEC 801-2
- Normas Din 41429
- Grados de protección IP
- Características de los integrados para comunicaciones RS232 (MAX232) ,para
comunicaciones RS485 (SN75176), reguladores de tensión de 7..25 a 5 V (serie
μA7800) y optoacopladores (6N136) .
- Características principales a considerar al elegir un cable, selección de cables
trenzados.
- Protectores de tensión barra terminal y contra descargas de tensión atmosféricas.
-Simbología empleada en transmisión digital.
(*NOTA -1 se incluye además un disquette con los manuales MODBUS y MODBUS
PLUS encontrados en su página de Internet).
173
(*NOTA -2 en la versión PDF no se incluyen los Anexos ,para su consulta acuda a la
copia en papel existente).
174
2 MEMORIA DE CÁLCULO
2.1 - Tarjeta conversora para PC
2.2 - Programación bus de campo
2.2.1 Programa de los SAB80C537
2.2.2 Diagramas de flujo
2.2.3 Código Ensamblador
2.2.3.1 Librería de definiciones
2.3 - Programación red local
2.3.1 Workstation
2.3.1.1 Código en Turbo C
2.3.1.2 Diagramas de flujo
2.3.2 Front-End
2.3.2.1 Código en Turbo C
2.3.2.2 Diagramas de flujo
2.4 - Manuales de los programas
2.4.1 SRM versión Workstation
2.4.2 SRM versión Front-End
2.5 - Programas de ayuda y apoyo
2.5.1 Código de programación en Turbo C y
lenguaje ensamblador
172
2.1 Tarjeta conversora para acoplar a los ordenadores
personales
Esta interface convierte los datos del estándar RS232 al estándar RS485. Adapta
los niveles de señal de uno al otro. Se compone principalmente de 2 circuitos
integrados el MAX232 y el SN75176. El primero se encarga de transformar los
niveles de las señales de RS232 a TTL/CMOS ,el otro adapta estos niveles
TTL/CMOS a los correspondientes del estándar RS485.
La alimentación de la tarjeta proviene de uno de los conectores hembra de 4
bornes de la fuente de alimentación del PC. Dicha alimentación se obtiene a
través de un conector macho del mismo numero de bornes. Se ha de tomar de
los cables de color amarillo (borne positiva) y de uno de los de color negro (borne
negativa) ,la tensión suministrada es de 12 V y por ello se emplea un regulador
de tensión μA7805 ,para obtener los 5 V necesarios para los integrados. Aunque
para las pruebas al final se ha adaptado una regleta de 2 entradas ,para poder
alimentar la tarjeta desde una fuente externa sin tener que acceder al interior de
los PCs .
La patilla 3 (del SN75176) de control del receptor RS485 (si viene habilitada por
hardware ,conectándola directamente a masa, se necesitaría un control software
del eco que se produciría) así como la patilla 2 (del mismo CI) de control del
emisor RS485 tienen que ser des/activadas por software ,la señal de control
procede de la patilla 7 (RTS) del puerto serie del PC ,esta operación se puede
realizar al ser opuestos los niveles de activación de cada uno de ellos.
Las señales de transmisión y la de habilitación ,así como la masa se aplican a
esta tarjeta a través de un conector macho de 10 patillas .Para conectarlo al
puerto serie del PC se necesita un cable plano con dos conectores hembra de en
sus extremos del mismo numero de patillas. Para la simulación realizada en las
pruebas se ha adaptado el citado conector y cable a un conector
D-sub9 para no tener que abrir los PCs. La salida RS485 se encuentra en la
regleta de dos polos.
173
2.1.1 Cálculo de la Resistencia de carga
El cable empleado en la red Local tiene una impedancia característica de 27'5 Ω
(5'3Ω /100 m) por lo que la resistencia terminadora de bus empleada será de
dicho valor (el valor comercial más próximo es de 28 Ω).
2.1.2 Cálculo de la alimentación eléctrica
Como se ha comentado anteriormente la tarjeta conversora requiere una
alimentación eléctrica que vendrá suministrada a través de uno de los conectores
de salida de la fuente de alimentación del PC y que será estabilizada y regulada
mediante el integrado μA7805 ,para proporcionar los 5V necesarios para
alimentar los integrados de la tarjeta.
2.1.3 Cálculo del consumo de la tarjeta conversora para PC
Según los datos proporcionados por el fabricante:
Nombre
consumo
típico en mA
Regulador μA7805
4'2
Diodo 1N4001
SN75176
26..42
MAX232
5
TOTAL:
35'2..51'2 mA
174
2.2 PROGRAMACIÓN DEL BUS DE CAMPO
2.2.1 PROGRAMA DE LOS PROCESADORES LOCALES SAB80C537
A continuación en las paginas siguientes se explican las principales funciones de atención a las
interrupciones y de atención a solicitudes MODBUS ,están basadas en el protocolo MODBUS
RTU en modo esclavo y además se detallan
más tarde los diagramas de flujo de estas y el código de programación en lenguaje
ensamblador ,empleado en el entorno de desarrollo integrado de Altair para estos
microcontroladores.
Índice de Rutinas:
- CONFIG configuración de las comunicaciones: velocidad de transmisión y dirección de la
estación.
- WATCHDOG aviso de fin de trama por exhaurirse el tiempo de espera entre caracteres y
aviso de fin de retardo al llegar este temporizador a cero.
- SERIAL1 recepción de tramas byte a byte y almacenaje en caso de estar dirigidas a la
estación, además del tratamiento de trama entrante cuando la anterior está siendo atendida.
- SERIAL0 envía la configuración de la estación y el estado de entradas y salidas digitales y de
los relés definibles por el usuario.
- PROGRAMA PRINCIPAL Se divide en dos partes: la de usuario y la del programa de
comunicaciones Modbus. En la segunda parte se realiza un tratamiento de las solicitudes
recibidas comprobando el correcto uso del protocolo y enviando las respuestas adecuadas a
las situaciones que surjan y además encuesta el estado de los relés definibles por el usuario
(por defecto ya van asignados a los eventos de modo manual/automático , bypass y alarma).
- ATENFRM Realiza el tratamiento de solicitudes recibidas comprobando que se adaptan al
protocolo Modbus y generando las respuestas correspondientes.
- LEEPORT Usada para lectura/escritura de puertos digitales.
- ERR_FRM Se encarga de preparar la trama de salida en respuesta a una excepción
producida por un fallo de protocolo o de petición en la trama recibida.
- READRETEN Empleada para lectura de registros de retención.
- WRITERETEN Empleada para escritura en registros de retención.
- V_AI Vuelca la porción de RAM interna seleccionada a la tabla de salida.
- EVENTOS Actualiza y almacena los bytes de eventos a medida que se reciben nuevas
tramas.
- V_AE Vuelca una porción de RAM externa seleccionada a la tabla de salida.
- L_AE Carga una parte de la memoria RAM externa seleccionada con los datos recibidos.
- TX_FRM Transmite la tabla de salida por el puerto serie 0 ,comunicaciones según el estándar
RS485.
- TX_MASTER Se encarga de enviar byte a byte la tabla de salida por el puerto serie 0.
- RSTCFG Reinicializa el estado de configuración de la estación para posteriores
cambios de velocidad de transmisión y de dirección de la estación.
175
- TX_PANEL Envía a petición del panel de visualización la configuración establecida para la
estación además del estado de las entradas/salidas digitales y de los relés definidos.
- INC rutina empleada para incrementar contadores controlando su límite superior.
- DELAY Realiza un retardo programado por el usuario.
- CRCFUNC Comprueba el crc de la trama recibida o bien pone el crc de la trama de salida en
la correspondiente tabla (para más información sobre el crc ver la documentación de la parte
de la memoria descriptiva).
Explicación de las principales funciones de atención a las
interrupciones y atención a las solicitudes MODBUS
Función CONFIG
Esta función se encarga de actualizar los valores de velocidad de transmisión de los puertos
serie y de la dirección de la estación. Permite al usuario configurar externamente estos
parámetros de la estación. Por defecto todas las estaciones están configuradas a 9600 Baudios
y con la dirección 32. Para más información consultar la tabla del apartado 1.5.3.4 de la
Memoria Descriptiva (Sección 1.5.3 Adaptación del protocolo Modbus a los equipos
SAB80C537)sobre los posibles valores de configuración.
La función trabaja de la siguiente manera: primero actualiza la parte alta de la dirección de la
estación ,segundo actualiza la parte baja de esta y por último actualiza la velocidad de
transmisión. Estos valores se leen de la parte baja del puerto 8. Los valores leídos se
interpretan en decimal. Esta rutina viene activada por la interrupción externa 0 pin 2 del puerto
3.
Función SERIAL1
Esta función almacena los bytes recibidos en posiciones consecutivas de memoria reservada
para la tabla primaria. Si llega una nueva trama mientras se atendía la anterior se guarda en la
tabla secundaria. Cada vez que recibe un nuevo dato limpia el contador watch-dog y a la vez
activa el temporizador watch-dog de las comunicaciones (que avisa al programa principal de la
recepción de la trama completa). Si cualquiera de las dos tablas de entrada se llena lo avisa al
programa principal y no almacena más bytes. El flag Wait avisa de la posible interrupción al
programa de usuario.
Función SERIAL0
Esta función se encarga de enviar mensajes al panel de visualización de cada procesador local
,en caso de fallo en la configuración o si recibe un byte reenvía los parámetros principales de la
estación (velocidad de transmisión, dirección de la estación, estado de las entradas/salidas
digitales y de los relés configurados.
Función WATCHDOG
Esta función se encarga de activar ,si el contador de comunicaciones llega a cero el aviso
EOFRM para avisar al programa que se ha recibido una nueva trama. En realidad avisa de fin
de recepción de datos por el puerto serie.
176
Rutina dedicada en la parte de INICIO del PROGRAMA PRINCIPAL
Esta rutina se ejecuta dentro de la parte de inicio del programa principal ,después de las
inicializaciones , a continuación de la parte dedicada al programa de usuario .Sus principales
tareas son:
- lectura y almacenaje de los valores de los reles definidos.
- establecimiento definitivo de la configuración de la
función CONFIG.
estación,preestablecida antes por la
- atención a las peticiones MODBUS llegadas por el puerto serie 0 con el consecuente
incremento de contadores respectivos , comprobación de errores de la trama recibida ,atención
a solicitudes entrantes cuando existen todavía anteriores peticiones atendiéndose
comprobación de errores de la trama recibida y atención a solicitudes normales sin ninguna
excepción detectada.
(* NOTA la función de atención a la petición externa y generación de la respuesta idónea se
llama ATENFRM).
177
2.2.2 DIAGRAMAS DE FLUJO DEL PROGRAMA
Diagrama de flujo de la rutina de servicio a la interrupción externa 0.
178
Diagrama de flujo de la rutina de atención a la interrupción del puerto serie 1
179
180
Diagrama de flujo de la rutina de servicio a la interrupción del timer 0
181
Diagrama de flujo de la rutina de servicio a la interrupción serie 0
182
183
184
2.2.3 CÓDIGO DE PROGRAMACIÓN DE LOS PROCESADORES LOCALES
;librerías de definiciones
.include c:\altair\fuentes\reg517.def
.include c:\altair\fuentes\config.def
.text_org $8000
;configuración de los vectores de interrrupción
adr0:
ljmp RUTRESET
.ds.b adr0+$03-!
INT0:
ljmp CONFIG
.ds.b adr0+$0B-!
TIME0:
ljmp WATCHDOG
.ds.b adr0+$23-!
COM0:
ljmp SERIAL0
.ds.b adr0+$83-!
COM1:
ljmp SERIAL1
;tablas para aplicar el CRC16
.ds.b adr0+$100-!
crchi:
.dc.b $00, $C1, $81, $40, $01, $C0, $80, $41,$01, $C0, $80, $41, $00, $C1, $81, $40 .dc.b
$01, $C0, $80, $41, $00, $C1, $81, $40,$00, $C1, $81, $40, $01, $C0, $80, $41 .dc.b $01, $C0,
$80, $41, $00, $C1, $81, $40,$00, $C1, $81, $40, $01, $C0, $80, $41 .dc.b $00, $C1, $81, $40,
$01, $C0, $80, $41,$01, $C0, $80, $41, $00, $C1, $81, $40 .dc.b $01, $C0, $80, $41, $00, $C1,
$81, $40,$00, $C1, $81, $40, $01, $C0, $80, $41 .dc.b $00, $C1, $81, $40, $01, $C0, $80,
$41,$01, $C0, $80, $41, $00, $C1, $81, $40 .dc.b $00, $C1, $81, $40, $01, $C0, $80, $41,$01,
$C0, $80, $41, $00, $C1, $81, $40 .dc.b $01, $C0, $80, $41, $00, $C1, $81, $40,$00, $C1, $81,
$40, $01, $C0, $80, $41 .dc.b $01, $C0, $80, $41, $00, $C1, $81, $40,$00, $C1, $81, $40, $01,
$C0, $80, $41 .dc.b $00, $C1, $81, $40, $01, $C0, $80, $41,$01, $C0, $80, $41, $00, $C1, $81,
$40 .dc.b $00, $C1, $81, $40, $01, $C0, $80, $41,$01, $C0, $80, $41, $00, $C1, $81, $40 .dc.b
$01, $C0, $80, $41, $00, $C1, $81, $40,$00, $C1, $81, $40, $01, $C0, $80, $41 .dc.b $00, $C1,
$81, $40, $01, $C0, $80, $41,$01, $C0, $80, $41, $00, $C1, $81, $40 .dc.b $01, $C0, $80, $41,
$00, $C1, $81, $40,$00, $C1, $81, $40, $01, $C0, $80, $41 .dc.b $01, $C0, $80, $41, $00, $C1,
$81, $40,$00, $C1, $81, $40, $01, $C0, $80, $41 .dc.b $00, $C1, $81, $40, $01, $C0, $80,
$41,$01, $C0, $80, $41, $00, $C1, $81, $40
crclo:
.dc.b $00, $C0, $C1, $01, $C3, $03, $02, $C2, $C6, $06, $07, $C7, $05, $C5, $C4, $04 .dc.b
$CC, $0C, $0D, $CD, $0F, $CF, $CE, $0E, $0A, $CA, $CB, $0B, $C9, $09, $08, $C8 .dc.b
$D8, $18, $19, $D9, $1B, $DB, $DA, $1A, $1E, $DE, $DF, $1F, $DD, $1D, $1C, $DC .dc.b $14,
$D4, $D5, $15, $D7, $17, $16, $D6, $D2, $12, $13, $D3, $11, $D1, $D0, $10 .dc.b $F0, $30,
$31, $F1, $33, $F3, $F2, $32, $36, $F6, $F7, $37, $F5, $35, $34, $F4 .dc.b $3C, $FC, $FD,
$3D, $FF, $3F, $3E, $FE, $FA, $3A, $3B, $FB, $39, $F9, $F8, $38 .dc.b $28, $E8, $E9, $29,
$EB, $2B, $2A, $EA, $EE, $2E, $2F, $EF, $2D, $ED, $EC, $2C .dc.b $E4, $24, $25, $E5, $27,
$E7, $E6, $26, $22, $E2, $E3, $23, $E1, $21, $20, $E0 .dc.b $A0, $60, $61, $A1, $63, $A3,
$A2, $62, $66, $A6, $A7, $67, $A5, $65, $64, $A4 .dc.b $6C, $AC, $AD, $6D, $AF, $6F, $6E,
$AE, $AA, $6A, $6B, $AB, $69, $A9, $A8, $68 .dc.b $78, $B8, $B9, $79, $BB, $7B, $7A, $BA,
$BE, $7E, $7F, $BF, $7D, $BD, $BC, $7C .dc.b $B4, $74, $75, $B5, $77, $B7, $B6, $76, $72,
$B2, $B3, $73, $B1, $71, $70, $B0 .dc.b $50, $90, $91, $51, $93, $53, $52, $92, $96, $56, $57,
$97, $55, $95, $94, $54 .dc.b $9C, $5C, $5D, $9D, $5F, $9F, $9E, $5E, $5A, $9A, $9B, $5B,
$99, $59, $58, $98 .dc.b $88, $48, $49, $89, $4B, $8B, $8A, $4A, $4E, $8E, $8F, $4F, $8D,
185
$4D, $4C, $8C .dc.b $44, $84, $85, $45, $87, $47, $46, $86, $82, $42, $43, $83, $41, $81, $80,
$40
;PROGRAMA PRINCIPAL
.ds.b adr0+$200-!
RUTRESET:
;desactiva interrupciones y quita el control al programa monitor
clr ien0.7
setb PSW.5
clr Led
;configuración de los puertos serie
;modo UART 8 bits ,velocidad de transmisión variable
clr adcon.7
anl pcon,#%011111111
mov s0con,#%01010000
mov s1con,#%10010000
anl En,#%11100111
setb adcon.7
orl pcon,#%10000000
;definición de la interrupción externa por flanco
orl tcon,#$01
;definición del timer0 como temporizador de 16 bits
;recarga por programación
mov TMOD,#$1
mov TH0,#$3C
mov TL0,#$AF
setb TCON.4
;pila del programa $30..$7F
mov SP,#$30
;borrado de los avisos de los puertos serie
anl s0con,#$FC
anl s1con,#$FC
;inicializa contador/puntero de la tabla primaria de entrada
clr a
mov DPTR,#$9000
movx @DPTR,a
;inicializa contador/puntero de la tabla secundaria de entrada
inc DPTR
mov a,#$10
movx @DPTR,a
;inicializa contador/puntero de la tabla de eventos
inc DPTR
clr a
movx @DPTR,a
;inicializa "fuera de tiempo" del timer0
inc DPTR
movx @DPTR,a
;inicializa "tiempo de espera" del timer0 (definible por el usuario para crear retrasos)
inc DPTR
movx @DPTR,a
mov a,#32
;dirección de la estación por defecto 32
inc DPTR
movx @DPTR,a
mov a,#3
;velocidad de transmisión por defecto 9600 baudios (ver tabla en la memoria descriptiva)
inc DPTR
movx @DPTR,a
186
;inicializa contador/puntero de la tabla de salida
inc DPTR
clr a
movx @DPTR,a
;inicializa contadores de las comunicaciones
mov DPTR,#$9030
clr a
mov r7,#10
clrctrl:
movx @DPTR,a
inc DPTR
djnz r7,clrctrl
;inicializa area de control de la estación
inc a
mov DPTR,#$9040
;número de convertidores A/D
movx @DPTR,a
inc DPTR
;número de temporizadores
mov a,#3
movx @DPTR,a
inc DPTR
;número de puertos serie
dec a
movx @DPTR,a
inc DPTR
;número de entradas digitales
mov a,#8
movx @DPTR,a
inc DPTR
;número de salidas digitales
movx @DPTR,a
inc DPTR
;número de entradas analógicas
movx @DPTR,a
inc DPTR
;número de salidas analógicas
clr a
movx @DPTR,a
inc DPTR
;números de puertos generales
mov a,#8
movx @DPTR,a
inc DPTR
;capacidad RAM interna
mov a,#255
movx @DPTR,a
inc DPTR
;capacidad ROM interna (Bytes reales=nºBytes tabla +1Byte)
clr a
movx @DPTR,a
inc DPTR
;capacidad RAM externa
mov a,#63
movx @DPTR,a
inc DPTR
;capacidad ROM externa (Kb reales=nºKb + 1Kb)
movx @DPTR,a
inc DPTR
187
;Identidad de la estación
mov a,#$41
movx @DPTR,a
inc DPTR
;versión del programa
mov a,#1
movx @DPTR,a
inc DPTR
;tipo de bus (modbus)
mov a,#$39
movx @DPTR,a
inc DPTR
;velocidad de transmisión configurada
mov a,#3
movx @DPTR,a
inc DPTR
;dirección de la estación configurada
mov a,#32
movx @DPTR,a
inc DPTR
;estado del bus (inactivo)
clr a
movx @DPTR,a
inc DPTR
;paridad de las comunicaciones (sin paridad)
movx @DPTR,a
inc DPTR
;número de bits de parada
inc a
movx @DPTR,a
;borrado de los avisos de las comunicaciones y del programa
clr MAN
clr BYPASS
clr ALARM
setb CFG
clr CONFADR
clr CONFBD
clr CRONO
clr EOFRM
clr T0_ON
clr TIMEOUT
clr NOTFORME
clr EmptyB1
clr EmptyB2
clr RX8
clr ATENTO
clr Dif
clr WAIT
clr BUSY
clr Modo
clr CRCIO
clr ECO
clr FORZ
clr MUDO
clr EMR
clr COMBO
;inicialización de las interrupciones
anl ien2,#$FE
;interrupciones del puerto serie 1 (MODBUS) inhabilitadas
;hasta ser configurada la velocidad de transmisión y la
188
;dirección de la estación
orl ien0,#$93
;inicializa banco 0 de registros
clr PSW.3
clr PSW.4
;retraso inicial de aviso de programa inicializado
setb led
mov r7,#30
lcall DELAY
clr led
USER_PRG:
setb WAIT
;poner
clr WAIT
aquí el programa dedicado de la estación
;lectura de los relés definidos
RELAYS:
clr a
mov a,RELAY
anl a,#$7
mov $2F,a
;establece la configuración de la estación
jnb CFG,iniserie
inicfg:
clr ien0.7
;restaura las interrupciones del puerto serie 1
orl ien2,#$01
;ES1 activado
mov DPTR,#$9005
;dirección
movx a,@DPTR
mov DPTR,#$9050
movx @DPTR,a
mov DPTR,#$9006
;velocidad transmision
movx a,@DPTR
mov DPTR,#$904f
movx @DPTR,a
clr CFG
orl pcon,#%10000000
cjne a,#$2,fincfg
anl pcon,#%01111111
fincfg:
setb ien0.7
;atención a las peticiones MODBUS llegadas por el puerto serie 1
iniserie:
jnb CRONO,USER_PRG
jnb EOFRM,USER_PRG
;borrado de flags de temporización y avisos de las
;comunicaciones
setb ATENTO
clr CRONO
clr EOFRM
clr RX8
;incremento mensajes recibidos
mov r7,#0
lcall INC
;si llego petición mientras se atendia anterior aviso de
;esa situación a la estación solicitante
189
jnb BUSY,atenb1
clr BUSY
jb EmptyB2,errorf2
;comprueba que la tabla de entrada secundaria no esté vacía
mov DPTR,#$9001
movx a,@DPTR
clr c
subb a,#10
jz atenb1
mov DPTR,#$9010
movx a,@DPTR
mov DPTR,#$9200
;carga dirección destino
movx @DPTR,a
mov DPTR,#$9011
movx a,@DPTR
mov DPTR,#$9201
;carga código de función
movx @DPTR,a
;llamada a la rutina de envios de excepciones
mov r7,#6
lcall ERR_FRM
;envia la trama llamando a la rutina de envios de datos desde la
;tabla de salida
lcall TX_FRM
;incremento de contadores de errores
mov r7,#7
lcall INC
mov r7,#1
lcall INC
;inicializa contador/puntero de la tabla secundaria de entrada
errorf2:
mov a,#$10
mov DPTR,#$9001
movx @DPTR,a
clr EmptyB2
;si no se dio el caso de "ocupado mientras recibe" atiende la
;peticón de la tabla primaria de entrada y actualiza el byte de
;evento
atenb1:
mov r2,#%10000000
jnb Dif,NevDif
mov r2,#%11000000
NevDif:
jnb Modo,NevModo
mov a,r2
orl a,#%00100000
mov r2,a
;si la trama es demasiado extensa ,la tabla primaria esta vacía o
;no va dirigida a esta estación no da respuesta
NevModo:
jnb EmptyB1,testADR
ljmp errorf1
testADR:
jnb NOTFORME,lleno
ljmp vacio
lleno:
mov DPTR,#$9000
movx a,@DPTR
jnz confirm
190
ljmp vacio
;comprobación de que la trama no se haya alterado
confirm:
lcall CRCFUNC
jnb ERR_C,crcisok
SETB LED
mov r7,#10
lcall DELAY
ljmp errorf1
crcisok:
mov DPTR,#$9100
movx a,@DPTR
mov DPTR,#$9200
;carga dirección en la tabla de salida
movx @DPTR,a
mov DPTR,#$9101
movx a,@DPTR
mov DPTR,#$9201
;carga función
movx @DPTR,a
;borrado de avisos empleados por las funciones MODBUS
clr ECO
clr EMR
clr COMBO
clr ERRFRM
;guarda el contexto
push DPSEL
mov DPSEL,#8
push DPH
push DPL
mov DPSEL,#6
push DPH
push DPL
mov DPSEL,#7
push DPH
push DPL
;llamada a la rutina de atención a la petición externa
lcall ATENFRM
;incremento de contador de mensajes atendidos
mov r7,#9
lcall INC
;si hay un aviso de eco de la solicitud ,no enviar respuesta
;o de modo "solo escucha" no envia la respuesta normal
jb Modo,calla
jb MUDO,calla
jb ECO,concrc
sincrc:
mov DPSEL,#7
setb CRCIO
;incluye el CRC en la trama de salida
lcall CRCFUNC
concrc:
mov DPSEL,#7
;transmisión de la trama
lcall TX_FRM
mov r7,#1
lcall INC
;restaura el contexto
calla:
mov DPSEL,#7
191
pop DPL
pop DPH
mov DPSEL,#6
pop DPL
pop DPH
mov DPSEL,#8
pop DPL
pop DPH
pop DPSEL
;actualiza el byte de eventos
mov a,r2
push acc
mov r2,#%01000000
jnb Modo,sinmodo
mov a,r2
orl a,#%00100000
mov r2,a
;si hubo una excepción se modifica el byte de eventos
sinmodo:
mov DPTR,#$9201
movx a,@DPTR
anl a,#$80
jz noexcep
mov a,r2
orl a,#%00000001
mov r2,a
noexcep:
jnb MUDO,noabort
jnb MAN,esbypass
ljmp aborta
esbypass:
jnb BYPASS,noabort
aborta:
mov a,r2
orl a,#%00000010
mov r2,a
;almacena byte eventos
noabort:
lcall EVENTOS
pop acc
mov r2,a
clr MUDO
clr Dif
ljmp clear
;actualiza el byte de eventos en caso de fallo
;y inicializa el contador/puntero de la tabla de entrada
;primaria y los avisos generales
errorf1:
mov r7,#8
lcall INC
mov a,r2
orl a,#%00000010
mov r2,a
clear:
clr a
mov DPTR,#$9000
movx @DPTR,a
clr EmptyB1
vacio:
clr NOTFORME
192
clr ATENTO
clr led
lcall EVENTOS
finserie:
ljmp USER_PRG
reti
;FUNCIONES GENERALES
;actualiza tabla de eventos
EVENTOS:
mov DPTR,#$9002
movx a,@DPTR
mov DPH,#$93
mov DPL,a
mov a,r2
movx @DPTR,a
inc DPL
mov a,DPL
cjne a,#$ff,noFev
clr a
noFev:
mov DPTR,#$9002
movx @DPTR,a
ret
;incremento de contadores de errores en las comunicaciones
ERR_FRM:
mov a,r7
push acc
cjne a,#2,nobadref1
mov r7,#3
lcall INC
nobadref1:
cjne a,#3,nobadref2
mov r7,#3
lcall INC
nobadref2:
cjne a,#1,nobadfunc
mov r7,#4
lcall INC
nobadfunc:
mov r7,#2
lcall INC
pop acc
mov DPTR,#$9201
;altera código de función
movx a,@DPTR
orl a,#$80
movx @DPTR,a
inc DPTR
;codigo de error
mov a,r7
movx @DPTR,a
mov a,#5
;nº bytes trama
mov DPTR,#$9007
movx @DPTR,a
setb ERRFRM
ret
193
;rutina de atención a la solicitud recibida
ATENFRM:
mov DPTR,#$9100
movx a,@DPTR
inc DPTR
movx a,@DPTR
;según el código de función recibido atiende a la petición solicitada
;función 1 lectura salidas digitales
F1:
cjne a,#1,F2
jnb Dif,C1
mov r7,#7
;código de error por función no realizable en modo "difusión"
lcall ERR_FRM
ret
C1:
mov a,DO
mov r7,a
lcall LEEPORT
ret
;función 2 lectura entradas digitales
F2:
cjne a,#2,F3
jnb Dif,C2
mov r7,#7
lcall ERR_FRM
ret
;si el relé BYPASS está activo no responde a la petición
C2:
jnb BYPASS,C21
setb MUDO
ret
C21:
mov a,DI
mov r7,a
lcall LEEPORT
ret
;función 3 lectura registros de retención
F3:
cjne a,#3,F4
jnb Dif,C3
mov r7,#7
lcall ERR_FRM
ret
C3:
clr COMBO
lcall readRETEN
ret
;función 4 lectura de registros y entradas analógicas $80..$FF ($80..$87 = AI0..AI7)
iniF5:
ljmp F5
F4:
cjne a,#4,iniF5
jnb Dif,C4
mov r7,#7
lcall ERR_FRM
ret
C4:
194
inc DPTR
movx a,@DPTR
jz C41
mov r7,#2
;código de error por dirección incorrecta
lcall ERR_FRM
ret
C41:
inc DPTR
movx a,@DPTR
mov r0,a
clr c
add a,#128
jnc C42
mov r7,#2
lcall ERR_FRM
ret
C42:
inc DPTR
movx a,@DPTR
;leer 1..128 registros
jz C43
mov r7,#3
;código de error por valor incorrecto
lcall ERR_FRM
ret
C43:
inc DPTR
movx a,@DPTR
jnz C44
mov r7,#3
lcall ERR_FRM
ret
C44:
mov r7,a
clr c
add a,r0
jnc C45
mov r7,#3
lcall ERR_FRM
ret
C45:
mov a,r0
anl a,#$F8
jz C46
ljmp C47
;si registros a leer de $80..$87 actualiza estos leyendo las entradas analógicas
C46:
push ADCON0
push ADCON1
push DAPR
push IEN1
anl IEN1,#$FE
anl ADCON1,#$F0
;AD arranque por programa ,selección canal 0
anl ADCON0,#$D0
mov a,r7
;guarda nº registros a enviar y carga valor entrada
;analógico inicial
push acc
195
mov r7,#7
;empieza lectura desde canal analogico 7
mov r1,#135
;valor en tabla correspondiente ($87)
act_AD:
mov a,r7
anl a,#7
;selección del canal a leer
orl ADCON0,a
orl ADCON1,a
mov DAPR,#0
;rango de conversión 0..5V
jb ADCON0.4,!
;aviso AD terminó la conversión
clr ADCON0.4
mov a,ADDAT
;valor recogido del AD
mov @r1,a
dec r1
cjne r7,#0,next_AD
ljmp fin_AD
next_AD:
dec r7
ljmp act_AD
fin_AD:
pop acc
mov r7,a
pop IEN1
pop DAPR
pop ADCON1
pop ADCON0
;carga los datos de los registros solicitados a la tabla de salida
C47:
mov a,r0
add a,#128
mov r0,a
lcall V_AI
ret
;función 5 escritura una sola salida digital ,si el relé MAN está activado no se devuelve
;respuesta
iniF6:
ljmp F6
F5:
cjne a,#5,iniF6
jnb Dif,C51
mov r7,#7
lcall ERR_FRM
ret
C51:
jnb MAN,C52
setb MUDO
ret
C52:
inc DPTR
movx a,@DPTR
jz C53
mov r7,#2
lcall ERR_FRM
ret
C53:
196
;reles 0..7
inc DPTR
movx a,@DPTR
mov r7,a
clr c
add a,#$F8
jnc C54
mov r7,#2
lcall ERR_FRM
ret
C54:
inc DPTR
movx a,@DPTR
clr FORZ
jz C56
cjne a,#$FF,C55
setb FORZ
ljmp C56
C55:
mov r7,#3
lcall ERR_FRM
ret
C56:
inc DPTR
movx a,@DPTR
jz C57
mov r7,#3
lcall ERR_FRM
ret
C57:
mov a,#$1
;si esta habilitado el forzado de salidas digitales ,se responde con la misma solicitud
jb FORZ,C59
C58:
cjne r7,#0,rotal0
cpl a
anl P4,a
setb ECO
ret
rotal0:
rl a
djnz r7,rotal0
cpl a
anl P4,a
setb ECO
ret
C59:
cjne r7,#0,rotal1
orl P4,a
setb ECO
ret
rotal1:
rl a
djnz r7,rotal1
orl P4,a
setb ECO
ret
;función 6 escritura de un solo registro de retención
iniF7:
ljmp F7
197
F6:
;0..32 registros
cjne a,#6,iniF7
jnb Dif,C61
mov r7,#7
lcall ERR_FRM
ret
C61:
inc DPTR
movx a,@DPTR
jz C62
mov r7,#2
lcall ERR_FRM
ret
C62:
inc DPTR
movx a,@DPTR
mov r0,a
clr c
add a,#223
jnc C63
mov r7,#2
lcall ERR_FRM
ret
C63:
inc DPTR
movx a,@DPTR
jz C64
mov r7,#3
lcall ERR_FRM
ret
;responde con la misma petición
C64:
inc DPTR
movx a,@DPTR
mov @r0,a
setb ECO
ret
;función 7 lectura estado reles definidos
iniF8:
ljmp F8
F7:
cjne a,#7,iniF8
jnb Dif,C71
mov r7,#7
lcall ERR_FRM
ret
C71:
mov r0,#$2F
mov a,@r0
anl a,#%00000111
mov r7,a
mov a,#5
;nº bytes trama salida
mov DPTR,#$9007
movx @DPTR,a
mov DPTR,#$9202
;byte de estado de reles
mov a,r7
movx @DPTR,a
198
ret
;función 8 diagnostico
iniFB:
ljmp FB
F8:
cjne a,#8,iniFB
jnb Dif,C81
mov r7,#7
lcall ERR_FRM
ret
C81:
inc DPTR
movx a,@DPTR
jz C82
mov r7,#1
;código de error funcion ilegal
lcall ERR_FRM
ret
C82:
inc DPTR
movx a,@DPTR
jnz SF1
;subfunción 0 hacer eco de la pregunta
SF0:
setb ECO
ret
;subfunción 1 salir del modo "escucha"
SF1:
cjne a,#1,SF4
inc DPTR
movx a,@DPTR
clr FORZ
jz SFC12
cjne a,#$FF,SFC11
setb FORZ
ljmp SFC12
SFC11:
mov r7,#3
lcall ERR_FRM
ret
SFC12:
inc DPTR
movx a,@DPTR
jz SFC13
mov r7,#3
lcall ERR_FRM
ret
;si la solicitud envia 0xff solicita limpiar tabla eventos ,también limpia los contadores
;de las comunicaciones
SFC13:
jnb FORZ,SFC14
mov DPTR,#$9002
movx a,@DPTR
mov r7,a
clr a
movx @DPTR,a
;borra contador eventos y limpia tabla de eventos
mov DPTR,#$9300
rstevent:
clr a
199
movx @DPTR,a
djnz r7,rstevent
SFC14:
mov DPTR,#$9030
;inicializa contadores comunicaciones a 0
clr a
mov r7,#10
clrcntr:
movx @DPTR,a
inc DPTR
djnz r7,clrcntr
;si estaba en modo "escucha" no responde
jnb Modo,respon
mov r2,#0
lcall EVENTOS
clr Modo
setb MUDO
ret
respon:
setb ECO
ret
;subfunción 4 entrar en modo "escucha"
SF4: cjne a,#4,SF8
setb Modo
mov r2,#$04
lcall EVENTOS
setb MUDO
ret
;subfunción 8 enviar avisos de comunicaciones
iniSF9:
ljmp SF9
SF8:
cjne a,#8,iniSF9
mov a,#12
;carga nº bytes de la trama de salida
mov DPTR,#$9007
movx @DPTR,a
mov DPTR,#$9202
clr a
movx @DPTR,a
inc DPTR
mov a,#8
;carga código subfunción
movx @DPTR,a
inc DPTR
mov a,#5
mov r7,a
;nº registros a enviar
movx @DPTR,a
inc DPTR
mov r0,#$2B
;dirección inicio avisos
volcat:
mov a,@r0
inc r0
movx @DPTR,a
inc DPTR
djnz r7,volcat
ret
;subfunción 9 enviar contadores de las comunicaciones
200
iniSF10:
ljmp SF10
SF9:
cjne a,#9,iniSF10
mov a,#17
;nº bytes trama de salida
mov DPTR,#$9007
movx @DPTR,a
mov DPSEL,#6
mov DPTR,#$9030
;dirección inicio area de control modbus
mov DPSEL,#7
mov DPTR,#$9202
clr a
movx @DPTR,a
inc DPTR
mov a,#9
;código de subfunción
movx @DPTR,a
inc DPTR
mov a,#10
mov r7,a
;nº registros a enviar
movx @DPTR,a
inc DPTR
lcall V_AE
ret
;subfunción 10 borrado de contadores comunicaciones
iniSF11:
ljmp SF11
SF10:
cjne a,#10,iniSF11
mov DPTR,#$9030
clr a
mov r7,#10
;responde con la misma pregunta
clrarea:
movx @DPTR,a
inc DPTR
djnz r7,clrarea
setb ECO
ret
;si el código de subfunción no existe devuelve respuesta a excepción
SF11:
mov r7,#1
;error func
lcall ERR_FRM
ret
;función 11 enviar contador de eventos en las comunicaciones
iniFC:
ljmp FC
FB:
cjne a,#11,iniFC
jnb Dif,CB1
mov r7,#7
lcall ERR_FRM
ret
CB1:
mov a,#8
201
;nº bytes trama de salida
mov DPTR,#$9007
movx @DPTR,a
mov DPTR,#$9202
;palabra de estado 0xFF si estaba ocupado 0x00 sino lo estaba
jb WAIT,ocupao
mov a,#$FF
movx @DPTR,a
inc DPTR
movx @DPTR,a
ljmp ponconta
ocupao:
clr a
movx @DPTR,a
inc DPTR
movx @DPTR,a
ponconta:
inc DPTR
clr a
movx @DPTR,a
mov DPTR,#$9002
movx a,@DPTR
mov DPTR,#$9205
movx @DPTR,a
ret
;función 12 obtener el archivo de eventos de comunicaciones
iniFF:
ljmp FF
FC:
cjne a,#12,iniFF
jnb Dif,CC1
mov r7,#7
lcall ERR_FRM
ret
CC1:
mov DPTR,#$9002
movx a,@DPTR
mov r7,a
add a,#6
mov r6,a
add a,#5
;nº bytes trama salida
mov DPTR,#$9007
movx @DPTR,a
mov DPTR,#$9202
;nº bytes datos
mov a,r6
movx @DPTR,a
inc DPTR
;palabra de estado
jb WAIT,user_busy
mov a,#$FF
movx @DPTR,a
inc DPTR
movx @DPTR,a
ljmp ponndata
user_busy:
clr a
movx @DPTR,a
inc DPTR
202
movx @DPTR,a
ponndata:
inc DPTR
clr a
movx @DPTR,a
mov DPTR,#$9002
;nº bytes eventos
movx a,@DPTR
mov DPTR,#$9206
movx @DPTR,a
inc DPTR
clr a
movx @DPTR,a
inc DPTR
push DPH
push DPL
mov DPTR,#$9039
;contador mensajes procesados
movx a,@DPTR
pop DPL
pop DPH
movx @DPTR,a
cjne r7,#0,ev_lleno
ljmp ev_vacio
;si la tabla de eventos no esta vacia la carga a la tabla de salida
ev_lleno:
mov DPSEL,#6
mov DPTR,#$9300
mov DPSEL,#7
mov DPTR,#$9209
lcall V_AE
ev_vacio:
ret
;función 15 forzado múltiples salidas digitales ,el relé MAN activado hace que
;no se envie respuesta
iniF10:
ljmp F10
FF:
cjne a,#15,iniF10
jnb MAN,CF1
setb MUDO
ret
CF1:
inc DPTR
movx a,@DPTR
jz CF2
mov r7,#2
lcall ERR_FRM
ret
CF2:
inc DPTR
movx a,@DPTR
mov r6,a
inc DPTR
movx a,@DPTR
jz CF3
mov r7,#3
lcall ERR_FRM
ret
CF3:
203
inc DPTR
movx a,@DPTR
jnz CF4
mov r7,#3
lcall ERR_FRM
ret
CF4:
add a,r6
clr c
add a,#$F7
jnc CF5
mov r7,#3
lcall ERR_FRM
ret
CF5:
inc DPTR
movx a,@DPTR
mov r7,a
mov P4,a
jnb Dif,dialgo
setb MUDO
ret
dialgo:
mov a,#6
;nº bytes trama salida
mov DPTR,#$9007
movx @DPTR,a
mov DPTR,#$9202
;nº datos
mov a,#1
movx @DPTR,a
inc DPTR
mov a,r7
movx @DPTR,a
;datos
ret
;función 16 prefijar múltiples registros de retención
iniF11:
ljmp F11
F10:
cjne a,#16,iniF11
clr COMBO
lcall writeRETEN
ret
;función 17 informar del tipo de esclavo
iniF14:
ljmp F14
F11:
cjne a,#17,iniF14
jnb Dif,CF111
mov r7,#7
lcall ERR_FRM
ret
CF111:
mov a,#25
;nº bytes trama
mov DPTR,#$9007
movx @DPTR,a
mov DPSEL,#6
mov DPTR,#$9040
204
;dirección inicio area de control modbus
mov DPSEL,#7
mov a,#20
mov r7,a
;nº registros a enviar
mov DPTR,#$9202
movx @DPTR,a
inc DPTR
lcall V_AE
ret
;función 20 lectura registros de memoria extendida
iniF15:
ljmp F15
F14:
cjne a,#20,iniF15
jnb Dif,CF141
mov r7,#7
lcall ERR_FRM
ret
CF141:
setb EMR
;acceso a E.M.R.
inc DPTR
movx a,@DPTR
;nº bytes trama recibida
jnz CF142
mov r7,#3
lcall ERR_FRM
ret
CF142:
mov b,#7
;paquetes de solicitud de 7 bytes por cada referencia
div ab
jnz CF143
mov r7,#3
lcall ERR_FRM
ret
CF143:
mov r0,a
;r0 número de grupos max 35 (35x7 = 245bytes ,trama modbus 256 bytes)
mov a,b
jz CF144
mov r7,#3
lcall ERR_FRM
ret
CF144:
mov a,r0
clr c
add a,#220
jnc CF145
mov r7,#3
lcall ERR_FRM
ret
err_ref:
mov r7,#8
;código de error en referencia
lcall ERR_FRM
ret
CF145:
205
push DPH
push DPL
;guarda puntero tabla entrada primaria
mov a,#5
;nº bytes trama salida sólo protocolo
mov DPTR,#$9007
movx @DPTR,a
clr a
mov DPTR,#$9202
;nº bytes datos
movx @DPTR,a
mov DPSEL,#8
mov DPTR,#$9202
;puntero a la tabla de salida
loading:
mov DPSEL,#7
pop DPL
;restaura puntero a tabla de entrada primaria
pop DPH
inc DPTR
movx a,@DPTR
;referencia 06
cjne a,#6,err_ref
inc DPTR
movx a,@DPTR
jz CF146
mov r7,#2
lcall ERR_FRM
ret
CF146:
inc DPTR
movx a,@DPTR
jnz CF147
mov r7,#3
lcall ERR_FRM
ret
CF147:
mov r6,a
;archivo de memoria extendida seleccionado 1..12
clr c
add a,#243
jnc CF148
mov r7,#3
lcall ERR_FRM
ret
CF148:
inc DPTR
movx a,@DPTR
jz CF149
mov r7,#2
lcall ERR_FRM
ret
CF149:
inc DPTR
movx a,@DPTR
mov r1,a
;r1 dirección inicio seleccionada
inc DPTR
movx a,@DPTR
jz CF14A
206
mov r7,#3
lcall ERR_FRM
ret
CF14A:
inc DPTR
movx a,@DPTR
mov r7,a
;r7 nº registros a leer
dec a
;nº registros-1 para no provocar desbordamiento
clr c
add a,r1
;inicio 0..FF nº registros 1..100
jnc CF14B
mov r7,#3
lcall ERR_FRM
ret
CF14B:
push DPH
;guarda puntero a la tabla primaria de entrada
push DPL
mov DPTR,#$9007
;nº bytes trama salida
movx a,@DPTR
add a,r7
;5bytes(protocolo)+ nºregistrosx(2bytes cada uno) + 2(protocolo referencias)
add a,#2
add a,r7
movx @DPTR,a
clr c
subb a,#5
mov DPTR,#$9202
;nº bytes datos
movx @DPTR,a
mov DPSEL,#8
push DPH
push DPL
mov DPSEL,#7
pop DPL
;puntero tabla de salida
pop DPH
carga:
mov DPSEL,#6
mov DPL,r1
mov a,#$93
;leer memoria datos externa 9400..9F00
add a,r6
mov DPH,a
mov DPSEL,#7
inc DPTR
mov a,r7
mov b,#2
mul ab
inc a
movx @DPTR,a
inc DPTR
mov a,#6
movx @DPTR,a
inc DPTR
mov a,r7
207
;volcado de datos desde posición E.M.R a la tabla de salida
lcall V_AE
mov DPSEL,#7
dec DPL
push DPH
;puntero tabla salida
push DPL
mov DPSEL,#8
pop DPL
pop DPH
mov a,r0
jz finF14
djnz r0,recarga
finF14:
mov DPSEL,#7
pop DPL
;restaura puntero tabla entrada primaria
pop DPH
ret
recarga:
ljmp loading
;función 21 escritura de registros de memoria extendida E.M.R.
iniF16:
ljmp F16
F15:
cjne a,#21,iniF16
jnb Dif,CF151
mov r7,#7
lcall ERR_FRM
ret
CF151:
inc DPTR
movx a,@DPTR
jnz CF152
mov r7,#3
lcall ERR_FRM
ret
er_refer:
mov r7,#8
;código error en referencia
lcall ERR_FRM
ret
CF152:
mov r0,a
;r0 nºbytes
setb COMBO
volcado:
inc DPTR
movx a,@DPTR
;referencia
cjne a,#6,er_refer
inc DPTR
movx a,@DPTR
jz CF153
mov r7,#2
lcall ERR_FRM
ret
CF153:
inc DPTR
movx a,@DPTR
208
jnz CF154
mov r7,#3
lcall ERR_FRM
ret
CF154:
;archivo 1..12 EMR seleccionado
mov r6,a
clr c
add a,#243
jnc CF155
mov r7,#3
lcall ERR_FRM
ret
CF155:
inc DPTR
movx a,@DPTR
jz CF156
mov r7,#2
lcall ERR_FRM
ret
CF156:
inc DPTR
movx a,@DPTR
mov r1,a
;r1 dirección inicio seleccionada
inc DPTR
movx a,@DPTR
jz CF157
mov r7,#3
lcall ERR_FRM
ret
CF157:
inc DPTR
movx a,@DPTR
mov r7,a
;r7 nº registros a escribir
dec a
clr c
add a,r1
;inicio 0..FF nº registros 1..100
jnc CF158
mov r7,#3
lcall ERR_FRM
ret
CF158:
inc DPTR
descarga:
mov DPSEL,#6
mov a,#$93
;lectura desde posiciones ram externa 9400..9F00
add a,r6
mov DPH,a
mov DPL,r1
mov a,r7
mov b,#2
mul ab
add a,#7
push acc
lcall L_AE
209
;escritura en EMR
pop acc
mov r7,a
mov a,r0
clr c
subb a,r7
jz finF15
ljmp volcado
;como respuesta envia la solicitud recibida
finF15:
setb ECO
ret
;función 22 escribir en el registro de máscaras ,ecuación R = (C& máscaraAND)| (máscara
OR& *máscara AND)
;ver documentación memoria descriptiva
iniF17:
ljmp F17
F16:
cjne a,#22,iniF17
jnb Dif,CF161
mov r7,#7
lcall ERR_FRM
ret
CF161:
inc DPTR
movx a,@DPTR
jz CF162
;máscara AND parte alta
mov r7,#2
lcall ERR_FRM
ret
CF162:
inc DPTR
movx a,@DPTR
;máscara AND parte baja
mov r0,a
mov r1,a
mov a,@r0
mov r0,a
inc DPTR
movx a,@DPTR
;máscara OR parte alta
jz CF163
mov r7,#3
lcall ERR_FRM
ret
CF163:
inc DPTR
movx a,@DPTR
;máscara OR parte baja
mov r7,a
anl a,r0
mov r0,a
inc DPTR
movx a,@DPTR
jz CF164
mov r7,#3
lcall ERR_FRM
ret
CF164:
210
inc DPTR
movx a,@DPTR
mov r6,a
mov a,r7
cpl a
anl a,r6
orl a,r0
mov @r1,a
setb ECO
ret
;función 23 lectura/escritura de registros de retención
iniF18:
ljmp F18
F17:
cjne a,#23,iniF18
jnb Dif,CF171
mov r7,#7
;error func no realizable
lcall ERR_FRM
ret
;activa el aviso de comnbinación de funciones modbus
CF171:
setb COMBO
lcall readRETEN
jnb ERRFRM,CF172
ret
CF172:
mov DPTR,#$9105
mov a,r0
push acc
mov a,r7
push acc
lcall writeRETEN
pop acc
mov r7,a
pop acc
mov r0,a
jnb ERRFRM,CF173
ret
;carga los datos solicitados de lectura desde la ram interna a la tabla de salida
CF173:
lcall V_AI
ret
;si el código de función no existe responde a dicha excepción
F18:
mov r7,#1
;error función inexistente
lcall ERR_FRM
ret
;función escritura registros retención
writeRETEN:
inc DPTR
movx a,@DPTR
jz CF101
mov r7,#2
lcall ERR_FRM
ret
CF101:
inc DPTR
211
movx a,@DPTR
mov r0,a
mov r1,a
inc DPTR
movx a,@DPTR
jz CF102
mov r7,#3
lcall ERR_FRM
ret
CF102:
inc DPTR
movx a,@DPTR
jnz CF103
mov r7,#3
lcall ERR_FRM
ret
CF103:
mov r7,a
mov r6,a
add a,r1
clr c
add a,#223
jnc CF104
mov r7,#2
lcall ERR_FRM
ret
CF104:
jnb COMBO,CF105
inc DPTR
CF105:
inc DPTR
prefija:
inc DPTR
movx a,@DPTR
inc DPTR
mov @r1,a
inc r1
djnz r7,prefija
jnb COMBO,sigue
ret
sigue:
mov a,#8
;nº bytes trama salida
mov DPTR,#$9007
movx @DPTR,a
clr a
mov DPTR,#$9202
movx @DPTR,a
inc DPTR
mov a,r0
;dirección
movx @DPTR,a
inc DPTR
clr a
movx @DPTR,a
inc DPTR
mov a,r6
movx @DPTR,a
;nº reg
ret
212
;función lectura registros retención
readRETEN:
inc DPTR
;reg. inicio 0..31
movx a,@DPTR
jz C31
mov r7,#2
lcall ERR_FRM
ret
C31:
inc DPTR
movx a,@DPTR
mov r0,a
inc DPTR
;leer 1..32 reg.
movx a,@DPTR
jz C32
mov r7,#3
lcall ERR_FRM
ret
C32:
inc DPTR
movx a,@DPTR
jnz C33
mov r7,#3
lcall ERR_FRM
ret
C33:
mov r7,a
add a,r0
clr c
add a,#$DF
jnc C34
mov r7,#3
lcall ERR_FRM
ret
C34:
jnb COMBO,volca
ret
;volcado datos de ram interna a tabla de salida
volca:
lcall V_AI
ret
;función incremento de contadores
INC:
push acc
push DPH
push DPL
mov a,#$30
orl a,r7
mov DPH,#$90
mov DPL,a
movx a,@DPTR
;control de límites de contadores
cjne a,#$FF,masaun
clr a
movx @DPTR,a
ret
masaun:
213
inc a
movx @DPTR,a
pop DPL
pop DPH
pop acc
ret
;función volcado desde la RAM externa a la tabla de salida
V_AE:
v_event:
jnb EMR,sincero
mov DPSEL,#7
clr a
movx @DPTR,a
;destino tabla de salida
inc DPTR
sincero:
mov DPSEL,#6
;origen ram
movx a,@DPTR
inc DPTR
mov DPSEL,#7
;destino tabla salida
movx @DPTR,a
inc DPTR
djnz r7,v_event
ret
;función carga desde la tabla de entrada primaria a la RAM externa
L_AE:
load_ev:
mov DPSEL,#7
;origen tabla entrada
jnb COMBO,onebyte
inc DPTR
onebyte:
movx a,@DPTR
inc DPTR
mov DPSEL,#6
;destino ram
movx @DPTR,a
inc DPTR
djnz r7,load_ev
ret
;función tratamiento entradas/salidas digitales
LEEPORT:
inc DPTR
movx a,@DPTR
jz dir_lo
mov r7,#2
lcall ERR_FRM
ret
dir_lo:
inc DPTR
movx a,@DPTR
;nº DO/DI inicio 0..7
mov r6,a
214
inc DPTR
movx a,@DPTR
jz num_lo
mov r7,#2
lcall ERR_FRM
ret
num_lo:
inc DPTR
movx a,@DPTR
;nº DO/DI a leer 1..8
jnz lo_ok
mov r7,#3
lcall ERR_FRM
ret
lo_ok:
add a,r6
clr c
add a,#$F7
jnc cargaBy
mov r7,#3
lcall ERR_FRM
ret
cargaBy:
mov a,#6
;nº bytes trama salida
mov DPTR,#$9007
movx @DPTR,a
mov DPTR,#$9202
;nº datos
mov a,#1
movx @DPTR,a
inc DPTR
mov a,r7
movx @DPTR,a
;dato
ret
;función volcado ram interna a tabla de salida
V_AI:
mov DPSEL,#7
mov a,r7
add a,#5
;nº bytes frame = datos + protocolo(5)
mov DPTR,#$9007
movx @DPTR,a
mov DPTR,#$9202
;nº datos
mov a,r7
movx @DPTR,a
inc DPTR
AINT:
;datos
mov a,@r0
inc r0
movx @DPTR,a
inc DPTR
djnz r7,AINT
ret
;función retraso de r7 segundos
215
DELAY:
push acc
push DPH
push DPL
clr ien0.7
clr tcon.4
;carga contador
mov a,r7
mov DPTR,#$9004
movx @DPTR,a
;activa contador espera y borra el aviso
clr TIMEOUT
setb T0_ON
setb tcon.4
setb ien0.7
;espera a que el contador sea 0 y el aviso se ponga a '1'
jnb TIMEOUT,!
clr T0_ON
pop DPL
pop DPH
pop acc
ret
;función envio de tabla de salida
TX_FRM:
;si es eco descarga desde la tabla de entrada primaria, sino desde la tabla de salida
jnb ECO,noeco1
mov DPTR,#$9000
ljmp ponn
noeco1:
mov DPTR,#$9007
ponn:
movx a,@DPTR
mov r7,a
;nº bytes
jnb ECO,noeco2
mov DPTR,#$9100
ljmp TXAI
noeco2:
mov DPTR,#$9200
;datos
TXAI:
movx a,@DPTR
lcall TX_MASTER
inc DPTR
djnz r7,TXAI
ret
;función comprobación/carga de CRC16
CRCFUNC:
clr ERR_C
;guarda contexto
push DPSEL
push acc
mov a,r5
push acc
mov a,r6
push acc
mov a,r7
push acc
216
mov DPSEL,#6
push DPH
push DPL
mov DPSEL,#7
push DPH
push DPL
;comprueba si ha de poner crc o sólo comprobarlo
jb CRCIO,crcout
mov DPTR,#$9000
movx a,@DPTR
mov R5,a
push acc
lcall TX_PANEL
mov a,#255
lcall TX_PANEL
pop acc
mov DPTR,#$9100
ljmp crcadr
crcout:
mov DPTR,#$9007
movx a,@DPTR
clr c
subb a,#2
mov R5,a
mov DPTR,#$9200
crcadr:
mov R7 ,#$FF
mov R6 ,#$FF
;ejecuta CRC16
bucle:
mov DPSEL,#7
movx A,@DPTR
push acc
lcall TX_PANEL
pop acc
inc DPTR
xrl A,R7
push Acc
mov DPSEL,#6
mov DPTR,#crchi
movc a,@a+DPTR
xrl A,R6
mov R7,A
pop Acc
mov DPTR,#crclo
movc a,@a+DPTR
mov R6,A
djnz R5,bucle
jb CRCIO,cargacrc
mov a,R7
orl a,R6
jz crcOK
setb ERR_C
ljmp crcOK
cargacrc:
mov DPTR,#$9007
;nº bytes trama salida
movx a,@DPTR
clr c
subb a,#2
217
mov DPL,a
mov DPH,#$92
;carga crc
mov a,R7
movx @DPTR,a
inc DPTR
mov a,R6
movx @DPTR,a
clr CRCIO
;restaura el contexto
crcOK:
mov DPSEL,#7
pop DPL
pop DPH
mov DPSEL,#6
pop DPL
pop DPH
pop acc
mov r7,a
pop acc
mov r6,a
pop acc
mov r5,a
pop acc
pop DPSEL
ret
;rutina de servicio a la interrupción externa 0 función configuración de dirección y velocidad de
transmisión ;de la estación ,lectura puerto 8 ;primero lee dirección alta ,luego dirección baja y
por último valor de la tabla ;de equivalencias de velocidad de transmisión
exit_cfg:
;restaura contexto
pop DPL
pop DPH
pop b
pop acc
mov r7,a
pop acc
reti
CONFIG:
jnb CFG,nofinconf
reti
nofinconf:
;interrupción serie 1 deshabilitada
clr ien0.7
anl ien2,#$FE
;ES1 off
;guarda contexto y ejecuta actualización dirección y velocidad de transmisión vigilando los
límites (1..32 y ;2..3 correspondientemente) en caso de fallo envia código de error al panel
visualizador conectado al puerto ;serie 0
setb ien0.7
push acc
mov a,r7
push acc
push b
push DPH
push DPL
mov Dip,#0
nop
mov a,Dip
218
anl a,#$0F
mov r7,a
mov a,$2E
anl a,#$03
jnz conf2
CONF1:
setb CONFADR
clr CONFBD
mov a,r7
mov b,#10
mul ab
mov DPTR,#$9005
movx @DPTR,a
ljmp exit_cfg
CONF2:
cjne a,#$1,conf3
clr CONFADR
setb CONFBD
mov DPTR,#$9005
movx a,@DPTR
add a,r7
jz outrang
clr c
add a,#$DF
jc outrang
clr c
subb a,#$DF
movx @DPTR,a
ljmp exit_cfg
CONF3: cjne a,#$2,err_in
setb CONFADR
setb CONFBD
mov a,r7
vel2: cjne a,#$2,vel3
ljmp vel
vel3: cjne a,#$3,err_vel
vel:
mov DPTR,#$9006
movx @DPTR,a
setb CFG
clr CONFADR
clr CONFBD
ljmp exit_cfg
err_in:
mov a,#103
lcall TX_PANEL
ljmp sinconf
err_vel:
mov a,#102
lcall TX_PANEL
ljmp sinconf
outrang:
mov a,#101
lcall TX_PANEL
sinconf:
lcall rstcfg
ljmp exit_cfg
;inicialización de la configuración
rstcfg:
219
clr CONFADR
clr CONFBD
clr a
mov DPTR,#$9005
movx @DPTR,a
mov DPTR,#$9006
movx @DPTR,a
clr CFG
ret
;rutina de servicio a la interrupción del timer0
WATCHDOG:
push acc
push DPH
push DPL
clr TCON.4
mov TH0,#$3C
mov TL0,#$AF
;si existe aviso de contaje de retraso actua ,sino se recarga y sale
timer0:
jnb T0_ON,timeout0
mov DPTR,#$9004
movx a,@DPTR
jnz dectimer
setb TIMEOUT
ljmp timeout0
dectimer:
dec a
movx @DPTR,a
;si existe aviso de contaje de espera de fin de trama actua
timeout0:
jnb CRONO,rest
mov DPTR,#$9003
movx a,@DPTR
jnz dectimeout
setb EOFRM
ljmp rest
dectimeout:
dec a
movx @DPTR,a
rest:
setb TCON.4
pop DPL
pop DPH
pop acc
reti
;rutina de servicio a la interrupción del puerto serie 1 recepción de solicitudes de la estación
principal del
;bus de campo
SERIAL1:
push acc
mov a,s1con
jb acc.0,RX1
pop acc
reti
RX1:
anl s1con,#$fe
mov a,r7
push acc
220
mov a,r6
push acc
push DPH
push DPL
;recarga TIMEOUT SERIAL
clr ien0.7
clr tcon.4
mov a,#$5
mov DPTR,#$9003
movx @DPTR,a
clr EOFRM
setb CRONO
setb tcon.4
setb ien0.7
;carga byte recibido
mov a,s1buf
;comprueba estados
jb BUSY,buf2
jb ATENTO,activaB
jb EmptyB1,salida
jb NOTFORME,salida
mov r7,a
jb RX8,datain
setb RX8
mov a,r7
jnz nodifus
setb Dif
ljmp datain
nodifus:
mov DPTR,#$9005
movx a,@DPTR
xrl a,r7
jnz activaF
;si los datos son para la estación o es un mensaje de difusión global acepta los datos y los
guarda en la ;tabla de entrada primaria ,si detecta que está atendiendo a anterior mensaje
recibido los almacena en la ;tabla secundaria de entrada. Si las tablas se "desbordan" deja de
cargar los datos y avisa de ello
datain:
mov DPTR,#$9000
movx a,@DPTR
mov DPH,#$91
mov DPL,a
mov a,r7
movx @DPTR,a
inc DPL
mov a,DPL
cjne a,#$ff,sigueme
setb EmptyB1
sigueme:
mov DPTR,#$9000
movx @DPTR,a
ljmp salida
buf2:
jb EmptyB2,salida
mov DPTR,#$9001
movx a,@DPTR
mov DPH,#$90
mov DPL,a
mov a,r7
movx @DPTR,a
221
inc DPL
mov a,DPL
cjne a,#$1F,sigue2
setb EmptyB2
sigue2:
mov DPTR,#$9001
movx @DPTR,a
ljmp salida
activaB:
setb BUSY
mov r7,#6
lcall INC
ljmp salida
activaF:
setb led
setb NOTFORME
salida:
pop DPL
pop DPH
pop acc
mov r6,a
pop acc
mov r7,a
pop acc
reti
;rutina de envio de bytes por el puerto serie 0 al panel visualizador
TX_PANEL:
;habilita transmisión
orl En,#%00001000
clr s0con.1
mov s0buf,a
;espera a envio de byte finalizado
jnb s0con.1,!
clr s0con.1
;pasa a modo recepción
anl En,#%11110111
ret
;rutina de servicio a la interrupción del puerto serie 0 a cada recepción responde con los datos
principales ;de la estación
SERIAL0:
jbc s0con.0,RX0
reti
;guarda contexto
RX0:
push DPH
push DPL
push acc
mov a,s0buf
mov DPTR,#$9005 ;dirección
movx a,@DPTR
lcall TX_PANEL
mov DPTR,#$9006 ;velocidad de transmisión
movx a,@DPTR
lcall TX_PANEL
mov a,Relay
lcall TX_PANEL
mov a,Dip
lcall TX_PANEL
222
mov a,DO
lcall TX_PANEL
mov a,DI
lcall TX_PANEL
pop acc
pop DPL
pop DPH
reti
;rutina envios al dispositivo maestro del bus de campo (puerto serie 1)
TX_MASTER:
orl En,#%00010000
anl s1con,#$FC
mov s1buf,a
push acc
espera:
mov a,s1con
jnb acc.1,espera
anl s1con,#$FC
anl En,#%11101111
pop acc
ret
.end
223
2.2.3.1 LIBRERÍA DE DEFINICIONES DEL PROGRAMA MODBUS
;Constantes del
En
= P6
DO
= P4
DI
= P5
Led
= P3.5
Relay = P1
Dip
= P8
programa
;P6.3 habilita '1' o no '0' el transmisor RS485
;"Digital inputs" ,entradas digitales
;"Digital outputs" ,salidas digitales
;led de la placa base
;puerto de reles de emergencia ,definibles por el usuario
;P8.0...P8.3 valor BCD direccion y valor binario tabla
;baudios INT0 permite config. baudios 1º y direccion 2 º
;Avisos del
T0_ON
=
TIMEOUT =
RX8
=
CFG
=
COMBO
=
ERRFRM
=
programa
$2B.0
$2B.1
$2B.2
$2B.3
$2B.4
$2B.5
;aviso de uso general para el usuario habilita TIMEOUT
;aviso de uso general para el usuario se da cada R7 ms
;aviso de captacion direccion=0/datos=1
;aviso configuracion establecida es correcta
;aviso de rutinas empleadas combinadas
;aviso trama incorrecta
Modo
Dif
ATENTO
BUSY
CRONO
EOFRM
WAIT
NOTFORME
$2C.0
$2C.1
$2C.2
$2C.3
$2C.4
$2C.5
$2C.6
$2C.7
;aviso de Modo solo escucha
;aviso de mensaje de difusion=1 ,individual =0
;aviso de mensaje siendo atendido
;aviso de llegada peticion cuando se estaba atendiendo anterior
;aviso de inicio de contaje para detectar EOFRM
;aviso deteccion de fin de trama en com0
;aviso "atencion al usuario ha sido interrumpida"
;aviso de trama no validada para dicha estacion
=
=
=
=
=
=
=
=
EmptyB1 = $2D.0
entrada primaria
EmptyB2 = $2D.1
secundaria
ERR_C
= $2D.2
;si esta a '0' ,desconexion por falta de espacio en la tabla de
;si es '0' ,desconexion por falta de espacio en la tabla de entrada
;error CRC
CONFADR
CONFBD
CRCIO
Output
RESET
FORZ
ECO
MUDO
EMR
extendida
= $2E.0
= $2E.1
= $2E.2
;estados de la configuracion: 00 sin configurar ,10 ADRH
;01 ADRL y 11 BAUD (CONFADR =MSB , CONFBD = LSB)
;aviso para aplicar CRC a buffer entrada o salida '1' = Input '0' =
=
=
=
=
=
;aviso reset tabla de eventos
;forzar salida
;hacer eco de la peticion
;no responder a peticion
;acceso a "Extended Memory Registers" ,registros de memoria
MAN
BYPASS
ALARM
= $2F.0
= $2F.1
= $2F.2
$2E.3
$2E.4
$2E.5
$2E.6
$2E.7
;ESTADO DE RELES DE ESTADOS definibles por el usuario
;2F.3 a 2F.7 reservados para ampliacion
224
2.3 -Programación de la Red Local
2.3.1 -Programación Workstation
El programa de las Workstations (estaciones de trabajo) se dedica por entero a las
comunicaciones entre estas y los Front-End (estaciones de enlace con los buses de campo).
Las principales tareas que realiza son :
-Envio de comandos a los Front-End y recepción de las respuestas.
-Envio y recepción de documentos de texto.
-Desconexión remota tanto de Workstations como de Front-Ends.
-Creación de documentos de texto propios para enviarlos a las otras estaciones.
-Visualización del estado de la red.
-Visualización del estado de la propia estación.
-Visualización de la información recogida de los Front-Ends así como de los procesadores
locales accedidos.
-Creación de fichero de históricos a partir de la información recogida de las entradas analógicas
de los procesadores locales a los que se accede.
El código del programa se muestra a continuación y más tarde se puede acceder a los
diagramas de flujo de este (la mayoría de diagramas de flujo son aplicables a la versión de los
Front-End.Para una información más detallada sobre su funcionamiento véase el manual del
programa en el apartado 2.4.
2.3.1.1 -Código del programa en lenguaje de programación
turbo C
/*librerias turboC empleadas por el programa*/
#include <alloc.h>
#include <conio.h>
#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
#include <graphics.h>
#include <string.h>
/*definición de constantes*/
#define TIMEOUT_recibo
1
#define TIMEOUT_envio
1
#define TIMEOUT_response 270
#define TIMEOUT_initoken
36
#define TIMEOUT_posesion
180
#define TIMEOUT_ack0
9
#define TIMEOUT_ack1
81
#define UNITDATA
0x00
#define DATA
0x01
#define DATA_ACK
0x02
#define ACS
0x03
#define CMS
0x02
#define UCS
0x01
#define UI
0x01
#define XID
0x02
#define TEST
0x03
#define UNNUMBERED
0x01
#define SUPERVISORY
0x02
#define INFORMATION
0x03
#define SABME
0x01
#define DISC
0x02
#define UASABME
0x03
225
#define UADISC
#define UARST
#define DMSABME
#define DMDISC
#define DMRST
#define FRMR
#define RST
#define RR
#define RNR
#define REJ
#define TOKEN_ASK
#define SUCESS1
#define SUCESS2
#define WHO_NEXT
#define BATTLE
#define TOKEN_PASS
#define STABLISH
#define OFF
#define NOTOKEN
#define TOKENACTV
#define WAIT
#define CONFLICTO
#define RECLAMO
#define PASO
#define SUCESOR1
#define SUCESOR2
#define CONTIENDA
#define QUIENSIGUE
#define ESCAPE
#define reclamo
#define paso
#define sucesor1
#define sucesor2
#define contienda
#define quiensigue
#define escape
#define EXIT
#define REPOSO
#define INIUCS
#define UCSTEST
#define UCSXID
#define UCSUI
#define INIACS
#define ACSTEST
#define ACSXID
#define ACSAC
#define INICMS
#define CMSTEST
#define CMSUA_SABME
#define CMSABME
#define CMSXID
#define CMSACK
#define CMSI
#define CMSREJ
#define CMSUA_DISC
#define CMSDISC
#define CMSWAIT
#define CMSUA_RST
#define CMSRST
#define L7OFF
0x13
0x23
0x04
0x14
0x24
0x05
0x06
0x01
0x02
0x03
0x00
0x01
0x02
0x03
0x04
0x08
0x0C
0
1
2
3
4
5
6
7
8
9
10
11
0x01
0x02
0x03
0x04
0x05
0x06
0x07
0x0
0x1
0x22
0x23
0x24
0x25
0x46
0x47
0x48
0x49
0x8A
0x8B
0x8C
0x8D
0x8E
0x8F
0x90
0x91
0x92
0x93
0x94
0x95
0x96
0x00
226
#define L7TEST
0x11
#define L7XID
0x12
#define L7UI
0x13
#define L7AC
0x31
/*definición de rutinas de servicio a interrupción*/
void interrupt (*o_com_vecWS)(void);
void interrupt (*o_com_vecFE)(void);
void interrupt (*o_time_vec)(void);
/*definición de tipos generales*/
typedef unsigned int uint;
typedef unsigned char uchar;
typedef struct basic_byte
{
uchar byte;
struct basic_byte *next;
}one_byte;
/*estructuras empleadas para las primitivas LLC y MAC*/
struct UCS_PRMTR_I
{
one_byte *datos, *org;
uchar activa,status;
uint dir_org, dir_dest;
};
struct UCS_PRMTR_R
{
one_byte *datos,*org;
uchar activa,status;
uint dir_dest;
};
struct UCS_PRMTV
{
struct UCS_PRMTR_I indication;
struct UCS_PRMTR_R request;
};
struct CMS_PRMTR_CNXN_IC
{
uchar activa;
uint dir_org, dir_dest;
};
struct CMS_PRMTR_CNXN_R
{
uchar activa;
uint dir_dest;
};
struct CMS_PRMTR_DATOS_I
{
one_byte *datos, *org;
uchar activa,status;
uint dir_org, dir_dest;
};
struct CMS_PRMTR_DATOS_R
{
one_byte *datos,*org;
uchar activa,status;
uint dir_dest;
};
struct CMS_PRMTR_RST_R
{
uint dir_dest;
uchar activa;
227
};
struct CMS_PRMTR_RST_C
{
uint dir_org, dir_dest;
uchar activa;
};
struct CMS_PRMTR_DSCNXN_IyRST
{
uchar motivo,activa;
uint dir_org, dir_dest;
};
struct CMS_PRMTR_DSCNXN_C
{
uchar motivo, activa;
uint dir_org, dir_dest;
};
struct CMS_PRMTR_DSCNXN_R
{
uchar motivo, activa;
uint dir_dest;
};
struct CMS_PRMTR_CNTRLFLJ_R
{
uint numdatos, dir_dest;
uchar activa;
};
struct CMS_PRMTR_CNTRLFLJ_I
{
uint numdatos, dir_org, dir_dest;
uchar activa;
};
struct CMS_PRMTV_CNXN
{
struct CMS_PRMTR_CNXN_IC indication,confirm;
struct CMS_PRMTR_CNXN_R request;
};
struct CMS_PRMTV_DATOS
{
struct CMS_PRMTR_DATOS_I indication;
struct CMS_PRMTR_DATOS_R request;
};
struct CMS_PRMTV_DSCNXN
{
struct CMS_PRMTR_DSCNXN_R request;
struct CMS_PRMTR_DSCNXN_C confirm;
struct CMS_PRMTR_DSCNXN_IyRST indication;
};
struct CMS_PRMTV_RST
{
struct CMS_PRMTR_RST_R request;
struct CMS_PRMTR_RST_C confirm;
struct CMS_PRMTR_DSCNXN_IyRST indication;
};
struct CMS_PRMTV_CNTRLFLJ
{
struct CMS_PRMTR_CNTRLFLJ_R request;
struct CMS_PRMTR_CNTRLFLJ_I indication;
};
struct ACS_PRMTR_RCNCMNTyRSPST_I
228
{
one_byte *datos, *org;
uchar activa,status;
uint dir_org, dir_dest;
};
struct ACS_PRMTR_RCNCMNTyRSPST_R
{
one_byte *datos, *org;
uchar activa,status;
uint dir_dest;
};
struct ACS_PRMTR_STDRCNCMNT
{
uchar activa, estado;
uint dir_org, dir_dest;
};
struct ACS_PRMTV_RCNCMNTyRSPST
{
struct ACS_PRMTR_RCNCMNTyRSPST_I indication;
struct ACS_PRMTR_RCNCMNTyRSPST_R request;
};
struct ACS_PRMTV_STDRCNCMNT
{
struct ACS_PRMTR_STDRCNCMNT indication;
};
struct LLC_OBJ
{
struct UCS_PRMTV unitdata;
struct CMS_PRMTV_CNXN connect;
struct CMS_PRMTV_DATOS data;
struct CMS_PRMTV_DSCNXN disconnect;
struct CMS_PRMTV_RST reset;
struct CMS_PRMTV_CNTRLFLJ connection_flowcontrol;
struct ACS_PRMTV_RCNCMNTyRSPST data_ack;
struct ACS_PRMTV_STDRCNCMNT data_ack_status;
char servicio;
}dl;
struct PTCN_SBPRMTR_DT
{
uchar tipo;
};
struct PTCN_SBPRMTR_STD_DT
{
uchar tipo,estado;
};
struct PTCN_PRMTR_DT
{
char activa,status;
uint dir_dest;
one_byte *org, *sdu;
struct PTCN_SBPRMTR_DT calidad;
};
struct NDCCN_PRMTR_DT
{
char activa,status;
uint dir_dest, dir_org, dir_post_org, dir_pre_org;
one_byte *org, *sdu;
};
struct NDCCN_PRMTR_STD_DT
{
char activa;
uint dir_dest, dir_org;
229
struct PTCN_SBPRMTR_STD_DT calidad;
};
struct PRMTV_DT
{
struct PTCN_PRMTR_DT request;
struct NDCCN_PRMTR_DT indication;
};
struct PRMTV_STD_DT
{
struct NDCCN_PRMTR_STD_DT indication;
};
struct MAC_OBJ
{
struct PRMTV_DT data;
struct PRMTV_STD_DT data_status;
}ma;
struct PRMTV_NTF
{
uchar invoke;
};
struct PRMTV_UDATA
{
uchar indication, request;
};
struct PRMTR_PORT
{
char FE,WS;
};
struct PRMTV_CNFG
{
struct PRMTR_PORT port;
long baudrateWS, baudrateFE;
};
struct PHY_OBJ
{
struct PRMTV_NTF notify;
struct PRMTV_CNFG config;
struct PRMTV_UDATA unitdata;
}phy;
/*tablas para aplicar CRC16*/
uchar HiCRCtab[] = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,
0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40} ;
230
uchar LoCRCtab[] = {
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7, 0x05, 0xC5, 0xC4,
0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9,
0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF,
0x1F, 0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12,
0x13, 0xD3, 0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32, 0x36,
0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE,
0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,
0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24,
0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26, 0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0,
0x60, 0x61, 0xA1, 0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F,
0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB,
0x7B, 0x7A, 0xBA, 0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75,
0xB5, 0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0, 0x50, 0x90,
0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 0x9C,
0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98,
0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C,
0x8C, 0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83, 0x41, 0x81,
0x80, 0x40} ;
/*definición de variables*/
char nomfich[20]="vacio",nombre[20]="vacio",filename[20]="vacio", set_adrs=0,openFILE=0,
L7_ctrl=L7OFF,token_ctrl=OFF, rotation=0, pl_invoke=0,
tokennom[12][15]={"OFF","NOTOKEN",
"TOKENACTV","WAIT","CONFLICTO","RECLAMO","PASO", "SUCESOR1","SUCESOR2",
"CONTIENDA","QUIENSIGUE","ESCAPE"},L7nom[24][15]={"EXIT" ,"REPOSO","INIUCS",
"UCSTEST","UCSXID","UCSUI","INIACS","ACSTEST","ACSXID","ACSAC" ,"INICMS",
"CMSTEST","CMSUA_SABME","CMSABME","CMSXID","CMSACK","CMSI","CMSREJ",
"CMSUA_DISC" ,"CMSDISC","CMSWAIT","CMSUA_RST","CMSRST"};
uint reenvio=0, RXB_INDEX=0, RXS_INDEX=0 ,FE_INDEX=0, old_mask, Local_Address =
0x0001,
winXID, seqsend=0, seqrec=0, winseq=0, oldseq=0,Global_Address = 0xFFFF, Next_Address
= 0xFFFF, Previous_Address = 0x0000;
uchar RX_BUF[1000],FE_BUF[256], TABLA[65];
int com_vecWS=0xC,com_vecFE=0xB, mx=220,my=220 ,timer_recibo=-1,timer_envio=1,timer_ack0=-1, timer_ack1 = -1,timeout_plc=-1,timer_token=-1, RX_BUF_SIZE=
640,MAC_BUF_SIZE= 640,MAXDATA= 600, WINDOW=16, CPU=-1,pag=0, COM_WS = 0x3F8
,COM_FE=0x2F8, token_stat=NOTOKEN, L7_stat=REPOSO;
void *raton;
FILE *cfg;
char
long endfile=0L;
fpos_t filepos=0L;
/*función de inicialización del modo gráfico,para que el programa funcione
correctamente los archivos EGAVGA.BGI ,LITT.CHR y TRIP.CHR han de estar en el
mismo directorio que el ejecutable (si aparece el mensaje de aviso es por que no se
encontró dichos archivos )*/
void inigraf()
{
int gdriver = DETECT, gmode, errorcode;
initgraph(&gdriver, &gmode, "");
errorcode = graphresult();
if (errorcode != grOk)
{
printf("Graphics error: #%s\n", grapherrormsg(errorcode));
getch();
exit(1);
}
}
231
/*realiza la operación contraria al anterior devuelve la pantalla al modo texto ,los retardos
introducidos son para mejor efecto visual*/
void closegraf()
{
cleardevice();
delay(250);
closegraph();
delay(250);
}
/*en caso de quedarse sin memoria dinámica el programa antes de finalizar restaura los
vectores de interrupción ,deshabilita las comunicaciones RS485 y pasa la pantalla a
modo texto*/
void descarga()
{
disable();
outportb(COM_WS+4,0x0B);
setvect(com_vecWS,o_com_vecWS);
setvect(0x1C,o_time_vec);
outportb(0x21,old_mask);
enable();
closegraf();
exit(-1);
}
/*rutina de atención a la recepción de caracteres por el puerto serie 1 (habitualmente con
conector de 9 pines y dirección 0x3F8),si el usuario lo permite almacena los bytes
recibidos en una tabla de entrada de datos ,las tramas enviadas tienen la cabecera
definida por el valor 0x7E (hexadecimal)*/
void interrupt serial1()
{
uchar inputbyte;
timer_recibo=TIMEOUT_recibo;
if(inportb(COM_WS+5) & (0x1E))
inportb(COM_WS);
else
{
inputbyte=inportb(COM_WS);
if(phy.notify.invoke)
goto endirq1;
if(!phy.unitdata.indication&&(inputbyte==0x7E))
phy.unitdata.indication=1;
RX_BUF[RXB_INDEX]=inputbyte;
RXB_INDEX++;
if(RXB_INDEX==RX_BUF_SIZE)
RXB_INDEX=0;
}
endirq1:
outportb(0x20,0x20);
}
/*rutina de atención al timer 0 del sistema,intervalo de interrupción definido en 1/18
seg,empleado para decremetar contadores de las comunicaciones*/
void interrupt timer0(void)
{
if(timer_recibo>=0)
timer_recibo--;
if(timeout_plc>=0)
timeout_plc--;
if(timer_envio>=0)
timer_envio--;
if(timer_token>=0)
timer_token--;
232
if(timer_ack0>=0)
timer_ack0--;
if(timer_ack1>=0)
timer_ack1--;
o_time_vec();
outportb(0x20,0x20);
}
/*función para cargar en memoria el puntero (en forma de rectangulo con una cruz
interior)a emplear por el ratón del PC y asignarlo a un apuntador a esa porción de
memoria*/
void rata()
{
unsigned int size;
setcolor(15);
rectangle(0,0,10,10);
line(0,0,10,10);
line(10,0,0,10);
size = imagesize(0,0,10,10);
raton = malloc(size);
if(raton==NULL)
descarga();
getimage(0,0,10,10,raton);
}
/*creación de una macro para dibujar fondos opacos con margen de colores,se le ha de
pasar la posición del vértice superior izquierdo y del inferior derecho así como los
colores para el fondo y el margen*/
void fondo(int x1,int y1,int x2,int y2,int c1,int c2)
{
setfillstyle(SOLID_FILL,c1);
bar(x1,y1,x2,y2);
setcolor(c2);
rectangle(x1,y1,x2,y2);
}
/*rutina de dibujo de la pantalla principal donde aparece un esquema de la red local y el
bus de campo si el parámetro pasado por valor así lo indica*/
void pantalla(int part)
{
int i;
setpalette(3,32);
fondo(0,0,639,479,3,3);
for(i=0;i<=1;i++)
{
setcolor(3+i*3);
rectangle(610+i,455+i,620+i,465+i);
setcolor(6-i*3);
setfillstyle(SOLID_FILL,6-i*3);
bar(30+i,7+i,610+i,9+i);
bar(580+i,10+i,580+i,56+i);
bar(30+i,57+i,610+i,59+i);
settextstyle(DEFAULT_FONT,HORIZ_DIR,1);
if(!part)
{
outtextxy(550+i,450+i,"Station");
outtextxy(550+i,460+i,"Access");
}
else
{
outtextxy(550+i,450+i,"Listen");
outtextxy(550+i,460+i,"Mode");
bar(30+i,317+i,610+i,319+i);
233
bar(580+i,320+i,580+i,366+i);
bar(30+i,367+i,610+i,369+i);
}
rectangle(200-i,420-i,430-i,476-i);
settextstyle(TRIPLEX_FONT,HORIZ_DIR,1);
outtextxy(600+i,20+i,"LAN");
if(part)
outtextxy(600+i,330+i,"BUS");
settextstyle(DEFAULT_FONT,HORIZ_DIR,1);
outtextxy(205-i,430-i,"Token Status");
outtextxy(205-i,445-i,"Level7 Status");
outtextxy(205-i,460-i,"Control Message");
outtextxy(210-i,410-i,"Control / Status Window");
fondo(330+i,425+i,425+i,472+i,0,7+i);
}
}
/*rutina de dibujo de mensajes de aviso para el usuario ,devuelve un valor cierto o falso
según la respuesta dada por el usuario al mensaje,se le ha de pasar el mensaje y el
permiso a esperar una respuesta*/
char message(char string[],int espera)
{
int i;
fondo(80,150,300,250,7,7);
settextstyle(TRIPLEX_FONT,HORIZ_DIR,2);
setcolor(4);
rectangle(85,155,295,245);
outtextxy(125-(strlen(string)*2),180,string);
settextstyle(TRIPLEX_FONT,HORIZ_DIR,5);
outtextxy(255,170,"!");
for(i=0;i<=4;i++)
{
line(257,168,277+i,210+i);
line(257,168,237-i,210+i);
line(237-i,210+i,277+i,210+i);
}
if(espera)
{
switch(getch())
{
case 'y':
case 13:
case 'Y':return(1);
case 'n':
case 'N':
case 27:
default: return(0);
}
}
settextstyle(SMALL_FONT,HORIZ_DIR,4);
return(0);
}
/*rutina de dibujo de la pantalla de visualización de una entrada analógica*/
void grafica()
{
int i,j;
char string[25];
fondo(0,0,639,479,7,8);
fondo(20,10,629,439,0,15);
setcolor(14);
line(20,420,629,420);
234
settextstyle(TRIPLEX_FONT,HORIZ_DIR,1);
for(i=0;i<=1;i++)
{
setcolor(15-i*7);
for(j=0;j<=10;j++)
line(20,420-j*40+i,15,420-j*40+i);
for(j=0;j<=5;j++)
{
itoa(5-j,string,10);
outtextxy(2+i,10+i+j*80,string);
}
outtextxy(10+i,449+i,"PLC :");
outtextxy(150+i,449+i,"AI :");
setcolor(15-i*7);
rectangle(550-i*2,450,600+i*4,470+i*5);
setfillstyle(SOLID_FILL,15-i*15);
setcolor(15-15*i);
bar(558+i,455+i,567+i,465+i);
line(570+i,465+i,580+i,455+i);
setfillstyle(SOLID_FILL,15-i*11);
setcolor(15-i*11);
bar(585+i,455+i,587+i,465+i);
bar(590+i,455+i,592+i,465+i);
}
}
/*rutina para visualzar un documento en una ventana predefinida de la pantalla,se le pasa
el nombre del fichero de texto a abrir y el tipo de ventana deseado*/
void doc(char nom[],int op)
{
char str[2];
int ncar=0,nlin=0,px=0,py=0;
FILE *f;
f=fopen(nom,"r");
if(f!=NULL)
{
if(op!=2)
{
setfillstyle(SOLID_FILL,7);
bar(406,211,634,359);
px=406;
py=211;
setcolor(8);
settextstyle(SMALL_FONT,HORIZ_DIR,4);
}
else
{
setfillstyle(SOLID_FILL,3);
bar(30,110,300,315);
px=30;
py=110;
setcolor(6);
settextstyle(DEFAULT_FONT,HORIZ_DIR,1);
}
ncar=0;
nlin=0;
while(!feof(f))
{
str[0]=getc(f);
str[1]='\0';
if((op!=2)&&(ncar>=230))
235
{
nlin=nlin+8;
ncar=0;
if(nlin==168)
goto fin2;
outtextxy(px+ncar,py+nlin,str);
}
if((op==2)&&(str[0]=='\n'))
{
nlin=nlin+10;
ncar=0;
}
if(!feof(f)&&(str[0]!='\n'))
{
outtextxy(px+ncar,py+nlin,str);
ncar=ncar+8;
}
}
}
fin2:
fclose(f);
}
/*rutina de dibujo de la pantalla principal de visualización ,de la información recogida del
microcontrolador accedido*/
void microlocal()
{
int i,j,k=0;
int cpu[14];
int zocal[14];
char pattern[8] = {0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55};
fondo(0,0,639,479,7,7);
settextstyle(SMALL_FONT,HORIZ_DIR,4);
for(i=0;i<2;i++)
{
setcolor(8-i);
rectangle(5+i,5+i,15+i,15+i);
outtextxy(20+i,7+i,"Set NOW");
}
setpalette(5,24);
setfillpattern(pattern,5); /*placa base*/
bar(50,30,394,478);
setfillstyle(SOLID_FILL,9);
/*DB-9 RS232C*/
bar(50,230,62,234);
bar(50,250,62,254);
bar(50,270,62,274);
bar(50,366,62,370);
bar(50,386,62,390);
bar(50,406,62,410);
bar(25,220,50,280);
bar(25,356,50,420);
for(j=0;j<=90*2;j=j+90)
/*puertos 1,3,7*/
{
setcolor(0);
setfillstyle(SOLID_FILL,8); /*conector 10pines*/
bar(112+j,32,200+j,72);
bar(392,74+j,352,162+j);
setfillstyle(SOLID_FILL,7);
bar(116+j,36,196+j,68);
bar(388,78+j,356,158+j);
setcolor(8);
236
setfillstyle(SOLID_FILL,8);
for(i=0;i<=4*12;i=i+12)
{
circle(136+i+j,46,4); /*pines*/
floodfill(136+i+j,46,8);
circle(136+i+j,58,4);
floodfill(136+i+j,58,8);
circle(365,98+i+j,4);
floodfill(365,98+i+j,8);
circle(378,98+i+j,4);
floodfill(378,98+i+j,8);
}
k++;
}
setfillstyle(SOLID_FILL,8); /*conector 10pines*/
bar(392,74+j,352,162+j);
setfillstyle(SOLID_FILL,7);
bar(388,78+j,356,158+j);
setcolor(8);
/*pines del 10*/
setfillstyle(SOLID_FILL,8);
for(i=0;i<=4*12;i=i+12)
{
circle(378,98+j+i,4);
floodfill(378,98+j+i,8);
circle(364,98+i+j,4);
floodfill(364,98+i+j,8);
}
bar(168,438,348,478); /*conector 26 pines */
setfillstyle(SOLID_FILL,7);
bar(172,442,344,474);
bar(84,450,164,470); /*conector 14 pines*/
setfillstyle(SOLID_FILL,8);
for(i=0;i<=12*12;i=i+12) /*pines del 26*/
{
circle(192+i,450,4);
floodfill(192+i,450,8);
circle(192+i,466,4);
floodfill(192+i,466,8);
}
for(i=0;i<=6*12;i=i+12) /*pines del 14*/
{
circle(88+i,466,4);
floodfill(88+i,466,8);
circle(88+i,454,4);
floodfill(88+i,454,8);
}
setcolor(0);
zocal[0]=206;
/*zocalo cpu 80c537 */
zocal[1]=78;
zocal[2]=206;
zocal[3]=210;
zocal[4]=214;
zocal[5]=218;
zocal[6]=350;
zocal[7]=218;
zocal[8]=350;
zocal[9]=86;
zocal[10]=342;
zocal[11]=78;
zocal[12]=zocal[0];
237
zocal[13]=zocal[1];
setfillstyle(SOLID_FILL,8);
fillpoly(7, zocal);
for(i=0;i<=6*28;i=i+28)
{
setcolor(11);
setfillstyle(SOLID_FILL,11); /* Condensadores electroliticos*/
circle(150,98+i,13);
floodfill(150,98+i,11);
setcolor(7);
setfillstyle(SOLID_FILL,7); /* Condensadores electroliticos*/
circle(150,98+i,11);
floodfill(150,98+i,7);
}
setfillstyle(SOLID_FILL,8);
bar(390,474,354,434); /* conector Vcc*/
setcolor(7);
setfillstyle(SOLID_FILL,7);
circle(372,444,6);
floodfill(372,444,7);
circle(372,464,6);
floodfill(372,464,7);
setcolor(0);
line(366,464,378,464);
line(366,444,378,444);
cpu[0]=226;
/*cpu 80c537 */
cpu[1]=98;
cpu[2]=226;
cpu[3]=190;
cpu[4]=234;
cpu[5]=198;
cpu[6]=330;
cpu[7]=198;
cpu[8]=330;
cpu[9]=106;
cpu[10]=322;
cpu[11]=98;
cpu[12]=cpu[0];
cpu[13]=cpu[1];
setfillstyle(SOLID_FILL,0);
fillpoly(7, cpu);
setcolor(4);
setfillstyle(SOLID_FILL,4); /*led */
circle(96,50,10);
floodfill(96,50,4);
setcolor(12);
setfillstyle(SOLID_FILL,12);
circle(96,50,8);
floodfill(96,50,12);
setfillstyle(SOLID_FILL,14); /*reset clk*/
bar(105,81,127,104);
setfillstyle(SOLID_FILL,15); /*reset*/
bar(58,82,80,104);
setcolor(15);
setfillstyle(SOLID_FILL,8);
settextstyle(SMALL_FONT,VERT_DIR,4);
outtextxy(270,118,"CPU SIEMENS");
outtextxy(280,118,"SAB 80C537");
outtextxy(35,225,"RS232C/1");
outtextxy(35,365,"RS232C/0");
238
settextstyle(SMALL_FONT,HORIZ_DIR,4);
bar(294,262,198,238); /*DEMULTIPLEXOR 74HCT573*/
bar(294,262,298,254);
bar(294,238,298,246);
outtextxy(215,245,"74HCT573");
bar(298,342,162,286); /*SRAM 65256*/
bar(158,286,162,302);
bar(158,342,162,322);
outtextxy(195,310,"SRAM 65256");
bar(298,422,162,366); /*EPROM 27C256*/
bar(158,366,162,386);
bar(158,422,162,402);
outtextxy(195,394,"EPROM 27C256");
settextstyle(SMALL_FONT,VERT_DIR,4);
bar(110,266,118,262);
/*SELECCION MEMORIA 74HCT00*/
bar(122,266,130,262);
bar(110,266,130,326);
outtextxy(115,274,"74HCT00");
bar(110,166,118,170);
/*MAX232*/
bar(122,166,130,170);
bar(110,246,130,170);
outtextxy(115,188,"MAX 232");
bar(110,154,118,150);
/*LT485*/
bar(122,154,130,150);
bar(110,122,130,150);
outtextxy(115,125,"485");
bar(110,358,118,362);
/*PHANTOM WATCH*/
bar(122,358,130,362);
bar(110,438,130,362);
outtextxy(115,370,"PHANTOM");
bar(54,138,90,182);
/*conector RS-485*/
setcolor(7);
setfillstyle(SOLID_FILL,7);
circle(72,149,6);
floodfill(72,149,7);
circle(72,171,6);
floodfill(72,171,7);
setcolor(0);
line(66,149,78,149);
line(66,171,78,171);
setcolor(0);
setfillstyle(SOLID_FILL,15);
bar(174,154,190,194); /* conector Cristal cuarzo*/
outtextxy(177,156,"12 MHz");
setcolor(0);
outtextxy(408,116,">");
outtextxy(433,116,">");
outtextxy(458,116,">");
outtextxy(483,116,">");
outtextxy(508,116,">");
outtextxy(533,116,">");
outtextxy(558,116,">");
outtextxy(583,116,">");
setcolor(0);
rectangle(615,25,625,35);
setcolor(8);
rectangle(615-1,25,625+3,35+2);
for(j=0;j<2;j++)
{
setcolor(8-j);
239
settextstyle(SMALL_FONT,HORIZ_DIR,4);
outtextxy(415+j,25-j,"ID :");
outtextxy(465+j,25-j,"ADR :");
outtextxy(535+j,25-j,"Listen Mode :");
outtextxy(415+j,155-j,"_Status Relays_");
outtextxy(415+j,165+j,"Man/Auto");
outtextxy(415+j,175-j,"Bypass");
outtextxy(415+j,185-j,"Alarm");
outtextxy(415+j,55-j,"Bit");
outtextxy(415+j,70-j,"DI");
outtextxy(415+j,85-j,"DO");
line(438+j,55+j,438+j,95+j);
line(448+j,50+j,448+j,95+j);
line(458+j,50+j,458+j,95+j);
line(468+j,50+j,468+j,95+j);
line(478+j,50+j,478+j,95+j);
line(488+j,50+j,488+j,95+j);
line(498+j,50+j,498+j,95+j);
line(508+j,50+j,508+j,95+j);
outtextxy(440+j,55+j,"1");
outtextxy(450+j,55+j,"2");
outtextxy(460+j,55+j,"3");
outtextxy(470+j,55+j,"4");
outtextxy(480+j,55+j,"5");
outtextxy(490+j,55+j,"6");
outtextxy(500+j,55+j,"7");
outtextxy(510+j,55+j,"8");
outtextxy(615+j,128-j,"AI");
outtextxy(421+j,115+j,"1");
outtextxy(446+j,115+j,"2");
outtextxy(471+j,115+j,"3");
outtextxy(494+j,115+j,"4");
outtextxy(521+j,115+j,"5");
outtextxy(546+j,115+j,"6");
outtextxy(571+j,115+j,"7");
outtextxy(596+j,115+j,"8");
for(i=0;i<=200;i=i+25)
line(408+i+j,125+j,408+i+j,140+j);
for(i=0;i<=30;i=i+15)
line(415+j,65+i+j,520+j,65+i+j);
line(408+j,125+j,608+j,125+j);
line(408+j,140+j,608+j,140+j);
outtextxy(445+j,200-j,"Extended Memory Registers");
rectangle(405+j,200+j,635+j,380+j);
line(415+j,200+j,415+j,210+j);
line(625+j,200+j,625+j,210+j);
line(405+j,210+j,635+j,210+j);
line(405+j,360+j,635+j,360+j);
outtextxy(410+j,365-j,"E.M.R. number: #");
outtextxy(630+j,200+j,">");
outtextxy(415+j,385-j,"ROM
Kb");
outtextxy(415+j,395-j,"RAM
Kb");
outtextxy(415+j,405-j,"Software Version .0");
outtextxy(415+j,415-j,"Bus Type");
outtextxy(415+j,425-j,"Baudrate");
outtextxy(415+j,435-j,"Frames received");
outtextxy(415+j,445-j,"Frames transmited");
outtextxy(415+j,455-j,"Frames accepted");
}
}
240
/*rutina de colocación y visualización de los datos recogidos del microcontrolador
accedido,para acceder a los datos se leen del archivo PLCFILE.DAT que previamente se
solicitó a la estación Front-End , los datos de los registros de memoria extendida (zona
de EMR) se alamcenan en el fichero temporal RAM.IMG para poder ser visualizado
posteriormente empleando la rutina DOC( )*/
uchar valores()
{
int i,c_aux2,c_aux1;
char string[15];
FILE *TMP,*cfg;
TMP=fopen("plcfile.dat","r");
i=0;
c_aux2=0;
if(TMP!=NULL)
{
settextstyle(SMALL_FONT,HORIZ_DIR,4);
setcolor(8);
while(!feof(TMP))
{
c_aux1=getc(TMP);
if(c_aux1!='\n')
string[i++]=c_aux1;
else
{
string[i++]='\0';
if(i>4)
goto fallo;
if(c_aux2==13)
{
i=(atoi(string)-1)*4800;
itoa(i,string,10);
}
i=0;
switch(c_aux2)
{
case 0: outtextxy(495,25,string);break;
case 1: outtextxy(619,25,string);break;
case 2: outtextxy(500,165,string);break;
case 3: outtextxy(500,175,string);break;
case 4: outtextxy(500,185,string);break;
case 5: outtextxy(520,435,string);break;
case 6: outtextxy(520,445,string);break;
case 7: outtextxy(520,455,string);break;
case 8: outtextxy(520,395,string);break;
case 9: outtextxy(520,385,string);break;
case 10: outtextxy(440,25,string);break;
case 11: outtextxy(520,405,string);break;
case 12: outtextxy(520,415,string);break;
case 13: outtextxy(520,425,string);break;
case 14: outtextxy(413,128,string);break;
case 15: outtextxy(437,128,string);break;
case 16: outtextxy(462,128,string);break;
case 17: outtextxy(487,128,string);break;
case 18: outtextxy(512,128,string);break;
case 19: outtextxy(537,128,string);break;
case 20: outtextxy(563,128,string);break;
case 21: outtextxy(587,128,string);break;
case 22: outtextxy(440,68,string);break;
case 23: outtextxy(450,68,string);break;
case 24: outtextxy(460,68,string);break;
241
case 25: outtextxy(470,68,string);break;
case 26: outtextxy(480,68,string);break;
case 27: outtextxy(490,68,string);break;
case 28: outtextxy(500,68,string);break;
case 29: outtextxy(510,68,string);break;
case 30: outtextxy(440,83,string);break;
case 31: outtextxy(450,83,string);break;
case 32: outtextxy(460,83,string);break;
case 33: outtextxy(470,83,string);break;
case 34: outtextxy(480,83,string);break;
case 35: outtextxy(490,83,string);break;
case 36: outtextxy(500,83,string);break;
case 37: outtextxy(510,83,string);break;
}
c_aux2++;
if(c_aux2==38)
goto acaba;
}
}
}
goto fallo;
acaba:
cfg=fopen("ram.img","w");
if(cfg!=NULL)
{
c_aux1=0;
while(!feof(cfg)&&!feof(TMP))
{
c_aux1=getc(TMP);
if(!feof(TMP))
putc(c_aux1,cfg);
}
}
fclose(cfg);
fclose(TMP);
doc("ram.img",1);
return(0);
fallo:
fclose(TMP);
cfg=fopen("ram.img","w");
fclose(cfg);
return(1);
}
/*rutina para la creación de una tabla dinámica empleada por el nivel LLC de
solicitud(REQUEST),se le ha de pasar la etapa (creación 0x00 o continuación 0x01) ,el
tipo de LLC (sin reconocimiento ni conexión UNITDATA ,con conexión y reconocimiento
DATA o sin conexión pero con reconocimiento DATA_ACK) y por último el dato a incluir
en la tabla*/
void PDU_dinamica(uchar etapa,uchar tipo,uchar dato)
{
if(etapa==0x00)
{
switch(tipo)
{
case UNITDATA:
{
if( (dl.unitdata.request.datos= malloc(sizeof(one_byte)))==NULL)
descarga();
dl.unitdata.request.status=1;
dl.unitdata.request.org=dl.unitdata.request.datos;
242
dl.unitdata.request.datos->byte=dato;
dl.unitdata.request.datos->next=NULL;
}break;
case DATA:
{
if((dl.data.request.datos= malloc(sizeof(one_byte)))==NULL)
descarga();
dl.data.request.status=1;
dl.data.request.org=dl.data.request.datos;
dl.data.request.datos->byte=dato;
dl.data.request.datos->next=NULL;
}break;
case DATA_ACK:
{
if((dl.data_ack.request.datos= malloc(sizeof(one_byte)))==NULL)
descarga();
dl.data_ack.request.status=1;
dl.data_ack.request.org=dl.data_ack.request.datos;
dl.data_ack.request.datos->byte=dato;
dl.data_ack.request.datos->next=NULL;
}break;
}
}
else
{
switch(tipo)
{
case UNITDATA:
{
if((dl.unitdata.request.datos->next= malloc(sizeof(one_byte)))==NULL)
descarga();
dl.unitdata.request.datos=dl.unitdata.request.datos->next;
dl.unitdata.request.datos->byte=dato;
dl.unitdata.request.datos->next=NULL;
}break;
case DATA:
{
if((dl.data.request.datos->next= malloc(sizeof(one_byte)))==NULL)
descarga();
dl.data.request.datos=dl.data.request.datos->next;
dl.data.request.datos->byte=dato;
dl.data.request.datos->next=NULL;
}break;
case DATA_ACK:
{
if((dl.data_ack.request.datos->next= malloc(sizeof(one_byte)))==NULL)
descarga();
dl.data_ack.request.datos=dl.data_ack.request.datos->next;
dl.data_ack.request.datos->byte=dato;
dl.data_ack.request.datos->next=NULL;
}break;
}
}
}
/*rutina similar a la anterior pero que sólo se emplea para crear una tabla dinámica a
emplear por el nivel MAC de solicitud (REQUEST) ,hay que pasarle la etapa (creación
0x00 o continuación 0x01) y el valor del dato a incluir)*/
void LLC_dinamica(uchar etapa,uchar dato)
{
if(etapa==0x00)
243
{
if((ma.data.request.sdu= malloc(sizeof(one_byte)))==NULL)
descarga();
ma.data.request.status=1;
ma.data.request.org=ma.data.request.sdu;
ma.data.request.sdu->byte=dato;
ma.data.request.sdu->next=NULL;
}
else
{
if((ma.data.request.sdu->next= malloc(sizeof(one_byte)))==NULL)
descarga();
ma.data.request.sdu=ma.data.request.sdu->next;
ma.data.request.sdu->byte=dato;
ma.data.request.sdu->next=NULL;
}
}
/*rutina empleada para descargar la información de un fichero de texto y la creación de
una trama LLC de solicitud (REQUEST) ,se le ha de pasar el tipo de LLC a crear
(UNITDATA,DATA o DATA_ACK) según el servicio a prestar, si se abre por primera vez
FILEPOS=0 entonces se incluye a la trama LLC el nombre del fichero y la extensión en
bytes de este*,los flags 0xFF sirven para su posterior reconocimiento de cada cual. En
caso de que el archivo sobrepase los límites establecidos para los servicios UNITDATA y
DATA_ACK devuelve un valor '1' y da una solicitud de desconexión
local (libera la trama creada con anterioridad),en el servicio DATA guarda la posición en
la que se quede al llegar a dicho límite preestablecido. Si el fichero está vacio devuelve
el mismo código de error '1'*/
uchar download_fichero(uchar tipo)
{
uchar car_tmp=0;
long l=0L;
one_byte *p;
char string[25];
int i,nbytes=0;
FILE *txt;
txt=fopen(filename,"r");
if(txt!=NULL)
{
fseek(txt, 0L, SEEK_END);
endfile = ftell(txt);
fseek(txt, 0L, SEEK_SET);
if(tipo==DATA)
{
if(filepos==0L)
{
seqsend=0;
winseq=0;
for(i=0;filename[i]!='\0';i++)
{
if(!i)
PDU_dinamica(0x00,tipo,filename[i]);
else
PDU_dinamica(0x01,tipo,filename[i]);
}
PDU_dinamica(0x01,tipo,0xFF);
ltoa(endfile,string,10);
for(i=0;string[i]!='\0';i++)
{
car_tmp=(uchar)(string[i]);
PDU_dinamica(0x01,tipo,car_tmp);
244
}
PDU_dinamica(0x01,tipo,0xFF);
}
else
{
if (fsetpos(txt, &filepos)!=0)
descarga();
}
}
nbytes=0;
while(!feof(txt))
{
car_tmp=(uchar)(getc(txt));
if(!feof(txt))
{
if(!nbytes)
{
if(tipo==DATA)
{
if(filepos==0L)
PDU_dinamica(0x01,tipo,car_tmp);
else
PDU_dinamica(0x00,tipo,car_tmp);
}
else
PDU_dinamica(0x00,tipo,car_tmp);
}
else
PDU_dinamica(0x01,tipo,car_tmp);
nbytes++;
if((nbytes>64)&&(tipo!=DATA))
goto end_file;
if((nbytes>=MAXDATA)&&(tipo==DATA))
{
fgetpos(txt,&filepos);
seqsend++;
fclose(txt);
if(filepos==endfile)
PDU_dinamica(0x01,tipo,0xFF);
return(0);
}
}
}
if(tipo==DATA)
{
seqsend++;
fgetpos(txt, &filepos);
PDU_dinamica(0x01,tipo,0xFF);
}
fclose(txt);
return(0);
}
else
{
fclose(txt);
L7_stat=REPOSO;
dl.disconnect.indication.dir_org=Local_Address;
dl.disconnect.indication.motivo=0x01;
dl.disconnect.indication.activa=1;
if(pag<2)
245
{
setfillstyle(SOLID_FILL,0);
bar(332,456,425,472);
outtextxy(335,460,"Empty File");
}
return(1);
}
end_file:
fclose(txt);
L7_stat=REPOSO;
dl.disconnect.indication.dir_org=Local_Address;
dl.disconnect.indication.motivo=0x05;
dl.disconnect.indication.activa=1;
if(pag<2)
{
setfillstyle(SOLID_FILL,0);
bar(332,456,425,472);
outtextxy(335,460,"File Disc");
}
switch(tipo)
{
case UNITDATA:{
if(dl.unitdata.request.org!=NULL)
{
dl.unitdata.request.datos=dl.unitdata.request.org;
for(l=0;dl.unitdata.request.datos!=NULL;l++)
{ p=dl.unitdata.request.datos->next;
free(dl.unitdata.request.datos);
dl.unitdata.request.datos=p;
}
dl.unitdata.request.status=0;
dl.unitdata.request.org=NULL;
}
}break;
case DATA:{
if(dl.data.request.org!=NULL)
{
dl.data.request.datos=dl.data.request.org;
for(l=0;dl.data.request.datos!=NULL;l++)
{ p=dl.data.request.datos->next;
free(dl.data.request.datos);
dl.data.request.datos=p;
}
dl.data.request.status=0;
dl.data.request.org=NULL;
}
}break;
case DATA_ACK:{ if(dl.data_ack.request.org!=NULL)
{
dl.data_ack.request.datos=dl.data_ack.request.org;
for(l=0;dl.data_ack.request.datos!=NULL;l++)
{ p=dl.data_ack.request.datos->next;
free(dl.data_ack.request.datos);
dl.data_ack.request.datos=p;
}
dl.data_ack.request.status=0;
dl.data_ack.request.org=NULL;
}
}break;
}
246
p=NULL;
free(p);
return(1);
}
/*rutina de creación de una trama LLC de indicación (INDICATION) ,tratamiento similar a
la rutina PDU_dinamica ,le pasamos la etapa (creación o continuación),el tipo de LLC
(UNITDATA,DATA o DATA_ACK) y el dato a incluir en dicha trama*/
void dinamic_LLC(uchar etapa,uchar tipo,uchar dato)
{
if(etapa==0x00)
{
switch(tipo)
{
case UNITDATA:
{
if ( (dl.unitdata.indication.datos= (malloc(sizeof(one_byte))) )==NULL)
descarga();
dl.unitdata.indication.status=1;
dl.unitdata.indication.org=dl.unitdata.indication.datos;
dl.unitdata.indication.datos->byte=dato;
dl.unitdata.indication.datos->next=NULL;
}break;
case DATA:
{
if ( (dl.data.indication.datos= (malloc(sizeof(one_byte))) )==NULL)
descarga();
dl.data.indication.status=1;
dl.data.indication.org=dl.data.indication.datos;
dl.data.indication.datos->byte=dato;
dl.data.indication.datos->next=NULL;
}break;
case DATA_ACK:
{
if ( (dl.data_ack.indication.datos= (malloc(sizeof(one_byte))) )==NULL)
descarga();
dl.data_ack.indication.status=1;
dl.data_ack.indication.org=dl.data_ack.indication.datos;
dl.data_ack.indication.datos->byte=dato;
dl.data_ack.indication.datos->next=NULL;
}break;
}
}
else
{
switch(tipo)
{
case UNITDATA:
{
if((dl.unitdata.indication.datos->next= (malloc(sizeof(one_byte))) )==NULL)
descarga();
dl.unitdata.indication.datos=dl.unitdata.indication.datos->next;
dl.unitdata.indication.datos->byte=dato;
dl.unitdata.indication.datos->next=NULL;
}break;
case DATA:
{
if((dl.data.indication.datos->next= (malloc(sizeof(one_byte))) )==NULL)
descarga();
dl.data.indication.datos=dl.data.indication.datos->next;
dl.data.indication.datos->byte=dato;
247
dl.data.indication.datos->next=NULL;
}break;
case DATA_ACK:
{
if((dl.data_ack.indication.datos->next= malloc(sizeof(one_byte)))==NULL)
descarga();
dl.data_ack.indication.datos=dl.data_ack.indication.datos->next;
dl.data_ack.indication.datos->byte=dato;
dl.data_ack.indication.datos->next=NULL;
}break;
}
}
}
/*rutina de creación de la cola de la trama MAC de salida ,(incluye el CRC y el patrón final
de la trama)*/
void cola()
{
uchar HiCRC = 0xFF,LoCRC = 0xFF;
uint IndexCRC;
long l;
ma.data.request.sdu=ma.data.request.org;
ma.data.request.sdu=ma.data.request.sdu->next;
ma.data.request.sdu=ma.data.request.sdu->next;
while (ma.data.request.sdu!=NULL)
{
IndexCRC = HiCRC ^ (ma.data.request.sdu->byte);
ma.data.request.sdu=ma.data.request.sdu->next;
HiCRC = LoCRC ^ HiCRCtab[IndexCRC];
LoCRC = LoCRCtab[IndexCRC];
}
ma.data.request.sdu=ma.data.request.org;
for (l=0;ma.data.request.sdu->next!=NULL;l++)
ma.data.request.sdu=ma.data.request.sdu->next;
LLC_dinamica(0x01,HiCRC);
LLC_dinamica(0x01,LoCRC);
LLC_dinamica(0x01,0xD8);
ma.data.request.sdu=ma.data.request.org;
}
/*rutina de creación de tramas de testigo de solicitud (REQUEST) para el nivel MAC , se
le ha de pasar el código del tipo de trama de testigo a crear */
uchar MAC_token_interface(uchar func)
{
uint index;
int i;
uchar dir_tmp;
if(phy.unitdata.request)
{
if(pag<2)
outtextxy(335,460,"MAC oV");
return(1);
}
switch(func)
{
case TOKEN_PASS:
ma.data.request.dir_dest=Next_Address;
break;
case STABLISH:{
if(token_stat==ESCAPE)
ma.data.request.dir_dest=Previous_Address;
else
248
ma.data.request.dir_dest=Global_Address;
}break;
default:
ma.data.request.dir_dest=Global_Address;
break;
}
LLC_dinamica(0x00,0x7E);
LLC_dinamica(0x01,0xD8);
LLC_dinamica(0x01,func);
dir_tmp = (uchar)((ma.data.request.dir_dest)>>8);
LLC_dinamica(0x01,dir_tmp);
dir_tmp= (uchar)( (ma.data.request.dir_dest)&0xFF);
LLC_dinamica(0x01,dir_tmp);
dir_tmp = (uchar)((Local_Address)>>8);
LLC_dinamica(0x01,dir_tmp);
dir_tmp =(uchar)( (Local_Address)&0xFF);
LLC_dinamica(0x01,dir_tmp);
if(func==TOKEN_PASS)
{
LLC_dinamica(0x01,(uchar)(Previous_Address>>8));
LLC_dinamica(0x01,(uchar)(Previous_Address&0xFF));
}
else
{
LLC_dinamica(0x01,(uchar)(Next_Address>>8));
LLC_dinamica(0x01,(uchar)(Next_Address&0xFF));
}
if((func==TOKEN_ASK)||(func==STABLISH))
{
for(index=0;index<=63;index++)
LLC_dinamica(0x01,0x7e);
}
else
if(func==TOKEN_PASS)
{
for (i=0;i<=63;i++)
LLC_dinamica(0x01,TABLA[i]);
}
cola();
phy.unitdata.request=1;
return(0);
}
/*rutina de creación de tramas LLC de solicitud (REQUEST) según la petición,se le ha de
especificar el tipo de servicio LLC a proporcionar ,el tipo de trama dentro de dicho
servicio ,la posible opción dentro de dicho tipo y si la trama será de petición de
información(resp=1) o de respuesta a petición (resp=0) en caso de error en la petición
devuelve un código de error '1'*/
uchar LLC_interface_envios (char service,char tipo,char opcion,char resp)
{
uchar field_ctrl1=0x00,field_ctrl2=0x00;
one_byte *p;
char emptyfile=1;
long index=0;
uchar dir_tmp;
if(ma.data.request.activa)
{
if(pag<2)
outtextxy(335,460,"LLC oV");
return(1);
}
ma.data.request.activa=0;
249
if(!strcmp(filename,"vacio"))
goto sigueme;
switch(service)
{
case UCS:
{
if(download_fichero(UNITDATA))
return(1);
}break;
case CMS:
{
if(download_fichero(DATA))
return(1);
}break;
case ACS:
{
if(download_fichero(DATA_ACK))
return(1);
}break;
}
emptyfile=0;
sigueme:
switch(service)
{
case UCS:
{
dl.servicio=0x01;
switch(tipo)
{
case UI:
{
if(emptyfile)
return(1);
field_ctrl1 = 0xC9;
ma.data.request.calidad.tipo =0x01;
}break;
case XID:
{
if(emptyfile)
return(1);
field_ctrl1 = 0xCB;
ma.data.request.calidad.tipo =0x02;
}break;
case TEST:
{
if(emptyfile)
return(1);
field_ctrl1 = 0xCA;
ma.data.request.calidad.tipo =0x02;
}break;
}
if(!resp)
{
field_ctrl1=field_ctrl1&0xF7;
ma.data.request.calidad.tipo = 0x04;
}
ma.data.request.dir_dest=dl.unitdata.request.dir_dest;
}break;
case CMS:
{
250
dl.servicio=0x02;
ma.data.request.calidad.tipo =0x01;
switch(tipo)
{
case UNNUMBERED:
{
switch(opcion)
{
case SABME:{
field_ctrl1 = 0xD9;
ma.data.request.dir_dest=dl.connect.request.dir_dest;
}break;
case DISC:{
field_ctrl1 = 0xDA;
ma.data.request.dir_dest=dl.disconnect.request.dir_dest;
}break;
case UASABME:{
field_ctrl1 = 0xDB;
ma.data.request.dir_dest=dl.connect.confirm.dir_dest;
}break;
case UADISC:{
field_ctrl1 = 0xDB;
ma.data.request.dir_dest=dl.disconnect.confirm.dir_dest;
}break;
case UARST:{
field_ctrl1 = 0xDB;
ma.data.request.dir_dest=dl.reset.confirm.dir_dest;
}break;
case DMSABME:{
field_ctrl1 = 0xD1;
ma.data.request.dir_dest=dl.connect.confirm.dir_dest;
}break;
case DMDISC:{
field_ctrl1 = 0xD1;
ma.data.request.dir_dest=dl.disconnect.confirm.dir_dest;
}break;
case DMRST:{
field_ctrl1 = 0xD1;
ma.data.request.dir_dest=dl.reset.confirm.dir_dest;
}break;
case FRMR:{
field_ctrl1 = 0xD2;
ma.data.request.dir_dest=dl.unitdata.request.dir_dest;
}break;
case RST:{
field_ctrl1 = 0xD3;
ma.data.request.dir_dest=dl.reset.request.dir_dest;
}break;
}
}break;
case SUPERVISORY:
{
switch(opcion)
{
case RR: {field_ctrl1 = 0x80;}break;
case RNR:{field_ctrl1 = 0x90;}break;
case REJ:{field_ctrl1 = 0xA0;}break;
}
field_ctrl2=0x80|seqrec;
251
if(!resp)
field_ctrl2=field_ctrl2&0x7F;
ma.data.request.dir_dest=dl.connection_flowcontrol.request.dir_dest;
}break;
case INFORMATION:
{
if(emptyfile)
return(1);
field_ctrl1=seqsend;
field_ctrl2=0x80|seqrec;
if(!resp)
field_ctrl2=field_ctrl2&0x7F;
ma.data.request.dir_dest=dl.data.request.dir_dest;
}break;
}
}break;
case ACS:
{
if(emptyfile)
return(1);
dl.servicio=0x03;
field_ctrl1 = 0xE9;
ma.data.request.calidad.tipo =0x02;
if(!resp)
{
field_ctrl1=field_ctrl1&0xF7;
ma.data.request.calidad.tipo = 0x04;
}
ma.data.request.dir_dest=dl.data_ack.request.dir_dest;
}break;
}
LLC_dinamica(0x00,0x7E);
LLC_dinamica(0x01,0xD8);
LLC_dinamica(0x01,(ma.data.request.calidad.tipo<<3) | 0x40);
dir_tmp = (uchar)((ma.data.request.dir_dest)>>8);
LLC_dinamica(0x01,dir_tmp);
dir_tmp= (uchar)( (ma.data.request.dir_dest)&0x00FF);
LLC_dinamica(0x01,dir_tmp);
dir_tmp = (uchar)((Local_Address)>>8);
LLC_dinamica(0x01,dir_tmp);
dir_tmp =(uchar)( (Local_Address)&0x00FF);
LLC_dinamica(0x01,dir_tmp);
LLC_dinamica(0x01,field_ctrl1);
if((dl.servicio==CMS)&&(field_ctrl1<0xC0))
LLC_dinamica(0x01,field_ctrl2);
if(emptyfile)
goto nolibre;
switch(dl.servicio)
{
case UCS:
{
if(dl.unitdata.request.org!=NULL)
{
dl.unitdata.request.datos=dl.unitdata.request.org;
for(index=0;dl.unitdata.request.datos!=NULL;index++)
{ p=dl.unitdata.request.datos->next;
LLC_dinamica(0x01,dl.unitdata.request.datos->byte);
free(dl.unitdata.request.datos);
dl.unitdata.request.datos=p;
}
252
dl.unitdata.request.status=0;
dl.unitdata.request.org=NULL;
}
}break;
case CMS:
{
if(tipo==INFORMATION)
{
if(dl.data.request.org!=NULL)
{
dl.data.request.datos=dl.data.request.org;
for(index=0;dl.data.request.datos!=NULL;index++)
{
p=dl.data.request.datos->next;
LLC_dinamica(0x01,dl.data.request.datos->byte);
free(dl.data.request.datos);
dl.data.request.datos=p;
}
dl.data.request.status=0;
dl.data.request.org=NULL;
}
}
}break;
case ACS:
{
if(dl.data_ack.request.org!=NULL)
{
dl.data_ack.request.datos=dl.data_ack.request.org;
for(index=0;dl.data_ack.request.datos!=NULL;index++)
{
p=dl.data_ack.request.datos->next;
LLC_dinamica(0x01,dl.data_ack.request.datos->byte);
free(dl.data_ack.request.datos);
dl.data_ack.request.datos=p;
}
dl.data_ack.request.status=0;
dl.data_ack.request.org=NULL;
}
}break;
}
p=NULL;
free(p);
nolibre:
ma.data.request.activa=1;
return(0);
}
/*rutina de tratamiento de las tramas recibida por el nivel MAC (Nivel de Acceso al
Medio) vuelca la tabla de entrada empleada por la rutina de servicio a la interrupción
serie 1 en una tabla dinamica MAC de indicación (INDICATION) ,los datos recibidos se
almacenan en el fichero de texto INPUT.DEP . Esta rutina trata los posibles errores
sufridos por la trama por alteración de algunos bits en patrones y cabecera, comprueba
su extensión máxima definida y su integridad mediante el algoritmo CRC16. En caso de
error devuelve el código '1'. Se encarga además de verificar si el mensaje recibido es
para dicha estación, si se trata de una trama de testigo o de datos y si es respuesta a
una petición pendiente para limpiar la trama de salida. Una vez realizadas las anteriores
comprobaciones actualiza el control del testigo ,y las direcciones de las estaciones
activas que contiene el testigo ,incluyendo la propia si no lo está(para tramas de testigo)
limpiando posteriormente la trama creada o devuelve la PDU LLC útil para el nivel LLC
(tramas de datos) o sea quita la cabecera y la cola de la trama creada*/
uchar MAC_in_level(void)
253
{
long l=0L,index;
one_byte *p;
uint NPATRON,dir_tmp,func_tmp,aux,estat;
uchar RX_BYTE_IN=-1;
uint IndexCRC;
uchar HiCRC = 0xFF,
LoCRC = 0xFF;
FILE *in;
if(phy.unitdata.indication)
{
ma.data.indication.activa=0;
timer_recibo=TIMEOUT_recibo;
l=0L;
do{
disable();
estat=RXB_INDEX-RXS_INDEX;
enable();
}while((timer_recibo>=0)&&!estat);
if (estat)
{
RX_BYTE_IN = RX_BUF[RXS_INDEX];
RXS_INDEX++;
if(RXS_INDEX ==RX_BUF_SIZE)
RXS_INDEX=0;
l++;
}
else
{
phy.notify.invoke=0;
phy.unitdata.indication=0;
return(1);
}
NPATRON=0;
if( (ma.data.indication.sdu= malloc(sizeof(one_byte)))==NULL)
descarga();
ma.data.indication.status=1;
ma.data.indication.org=ma.data.indication.sdu;
ma.data.indication.sdu->byte=RX_BYTE_IN;
ma.data.indication.sdu->next=NULL;
in=fopen("input.dep","a");
if(in!=NULL)
fprintf(in,"\n%x.",RX_BYTE_IN);
if(RX_BYTE_IN==0xD8)
NPATRON++;
while(!phy.notify.invoke)
{
timer_recibo=TIMEOUT_recibo;
do{
disable();
estat=RXB_INDEX-RXS_INDEX;
enable();
}while((timer_recibo>=0)&&!estat);
if (estat)
{
RX_BYTE_IN = RX_BUF[RXS_INDEX];
RXS_INDEX++;
if(RXS_INDEX ==RX_BUF_SIZE)
RXS_INDEX=0;
l++;
254
if((RX_BYTE_IN!=0xD8)&&(NPATRON==2))
NPATRON=1;
if(RX_BYTE_IN==0xD8)
NPATRON++;
if(NPATRON>=2)
NPATRON=2;
if(l >= MAC_BUF_SIZE )
goto termina;
else
{
if((ma.data.indication.sdu->next= malloc(sizeof(one_byte)))==NULL)
descarga();
ma.data.indication.sdu=ma.data.indication.sdu->next;
ma.data.indication.sdu->byte=RX_BYTE_IN;
ma.data.indication.sdu->next=NULL;
if( ((RX_BYTE_IN>64)&&(RX_BYTE_IN<91))||((RX_BYTE_IN>96)&&(RX_BYTE_IN<123)))
{
if(in!=NULL)
fprintf(in,"%c.",RX_BYTE_IN);
}
else
{
if(in!=NULL)
fprintf(in,"%x.",RX_BYTE_IN);
}
}
}
else
{
termina:
phy.notify.invoke=1;
fclose(in);
if((NPATRON!=2)||(l >= MAC_BUF_SIZE))
{
phy.notify.invoke=0;
goto finito;
}
}
}
phy.notify.invoke=0;
ma.data.indication.sdu=ma.data.indication.org;
while((ma.data.indication.sdu->byte==0x7E))
{
p=ma.data.indication.sdu->next;
free(ma.data.indication.sdu);
ma.data.indication.sdu=p;
}
ma.data.indication.org=ma.data.indication.sdu;
if(ma.data.indication.sdu->byte==0xD8)
{
p=ma.data.indication.sdu->next;
free(ma.data.indication.sdu);
ma.data.indication.sdu=p;
ma.data.indication.org=ma.data.indication.sdu;
l=0L;
while(ma.data.indication.sdu->next!=NULL)
{
l++;
ma.data.indication.sdu=ma.data.indication.sdu->next;
}
255
if(ma.data.indication.sdu->byte!=0xD8)
goto finito;
ma.data.indication.sdu=ma.data.indication.org;
l=l-1L;
for(index=0;index<l;index++)
ma.data.indication.sdu=ma.data.indication.sdu->next;
p=ma.data.indication.sdu->next;
ma.data.indication.sdu->next=NULL;
ma.data.indication.sdu=p;
free(ma.data.indication.sdu);
ma.data.indication.sdu=ma.data.indication.org;
while (ma.data.indication.sdu!=NULL)
{
IndexCRC = HiCRC ^ (ma.data.indication.sdu->byte);
ma.data.indication.sdu=ma.data.indication.sdu->next;
HiCRC = LoCRC ^ HiCRCtab[IndexCRC];
LoCRC = LoCRCtab[IndexCRC] ;
}
ma.data.indication.sdu=ma.data.indication.org;
if(HiCRC||LoCRC)
goto finito;
l=l-2L;
for(index=0;index<l;index++)
ma.data.indication.sdu=ma.data.indication.sdu->next;
p=ma.data.indication.sdu->next;
ma.data.indication.sdu->next=NULL;
ma.data.indication.sdu=p;
p=ma.data.indication.sdu->next;
free(ma.data.indication.sdu);
ma.data.indication.sdu=p;
free(ma.data.indication.sdu);
ma.data.indication.sdu=ma.data.indication.org;
if(ma.data.indication.sdu->byte&0x40)
{
if(ma.data.indication.sdu->byte&0x08)
ma.data_status.indication.calidad.tipo=0x08;
else
if(ma.data.indication.sdu->byte&0x10)
ma.data_status.indication.calidad.tipo=0x10;
else
if(ma.data.indication.sdu->byte&0x20)
ma.data_status.indication.calidad.tipo=0x20;
else
goto finito;
ma.data.indication.sdu=ma.data.indication.org;
p=ma.data.indication.sdu->next;
free(ma.data.indication.sdu);
ma.data.indication.sdu=p;
ma.data.indication.dir_dest=((uint)(ma.data.indication.sdu->byte))<<8;
p=ma.data.indication.sdu->next;
free(ma.data.indication.sdu);
ma.data.indication.sdu=p;
ma.data.indication.org=ma.data.indication.sdu;
ma.data.indication.dir_dest= ma.data.indication.dir_dest | (ma.data.indication.sdu->byte);
if(
(ma.data.indication.dir_dest==Local_Address)||(ma.data.indication.dir_dest==Global_Address))
{
p=ma.data.indication.sdu->next;
free(ma.data.indication.sdu);
ma.data.indication.sdu=p;
256
ma.data.indication.dir_org=((uint)(ma.data.indication.sdu->byte))<<8;
p=ma.data.indication.sdu->next;
free(ma.data.indication.sdu);
ma.data.indication.sdu=p;
ma.data.indication.org=ma.data.indication.sdu;
ma.data.indication.dir_org= ma.data.indication.dir_org | (ma.data.indication.sdu->byte);
if((ma.data.indication.dir_org==Local_Address)||(ma.data.indication.dir_org==Global_Address))
goto finito;
p=ma.data.indication.sdu->next;
free(ma.data.indication.sdu);
ma.data.indication.sdu=p;
ma.data.indication.org=ma.data.indication.sdu;
}
else
goto finito;
if (ma.data_status.indication.calidad.estado==0x01)
{
if(ma.data_status.indication.calidad.tipo==0x20)
{
ma.data_status.indication.dir_dest=ma.data.indication.dir_dest;
ma.data_status.indication.dir_org=ma.data.indication.dir_org;
ma.data_status.indication.calidad.estado=0x00;
if(ma.data.request.org!=NULL)
{
ma.data.request.sdu=ma.data.request.org;
for(l=0;ma.data.request.sdu!=NULL;l++)
{
p=ma.data.request.sdu->next;
free(ma.data.request.sdu);
ma.data.request.sdu=p;
}
ma.data.request.status=0;
ma.data.request.org=NULL;
}
ma.data_status.indication.activa=1;
timer_ack0=-1;
reenvio=0;
}
else
{
ma.data_status.indication.dir_dest=ma.data.indication.dir_dest;
ma.data_status.indication.dir_org=ma.data.indication.dir_org;
ma.data_status.indication.calidad.estado=0x01;
ma.data_status.indication.activa=1;
}
}
ma.data.indication.activa=1;
}
else
{
timer_token=TIMEOUT_response;
func_tmp=(ma.data.indication.sdu->byte);
if( func_tmp > 0x0C)
goto finito;
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
ma.data.indication.dir_dest=((uint)(ma.data.indication.sdu->byte))<<8;
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
ma.data.indication.dir_dest= ma.data.indication.dir_dest | (ma.data.indication.sdu->byte);
if(
(ma.data.indication.dir_dest==Local_Address)||(ma.data.indication.dir_dest==Global_Address) )
257
{
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
ma.data.indication.dir_org=((uint)(ma.data.indication.sdu->byte))<<8;
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
ma.data.indication.dir_org= ma.data.indication.dir_org | (ma.data.indication.sdu->byte);
if( (ma.data.indication.dir_org==Local_Address)||(ma.data.indication.dir_org==Global_Address)
)
goto finito;
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
dir_tmp=((uint)(ma.data.indication.sdu->byte))<<8;
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
dir_tmp= dir_tmp | (ma.data.indication.sdu->byte);
if(func_tmp!=TOKEN_PASS)
ma.data.indication.dir_post_org = dir_tmp;
else
{
ma.data.indication.dir_pre_org = dir_tmp;
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
for (aux=0;ma.data.indication.sdu->next!=NULL;aux++)
{
if(aux<=63)
TABLA[aux]=ma.data.indication.sdu->byte;
else
goto finito;
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
}
for (aux=0;aux<=63;aux=aux+2)
{
dir_tmp=(TABLA[aux]<<8)|(TABLA[aux+1]);
if(!set_adrs&&(!TABLA[aux])&&(!TABLA[aux+1]))
{
TABLA[aux]=(uchar)((Local_Address&0xFF00)>>8);
TABLA[aux+1]=(uchar)(Local_Address&0xFF);
set_adrs=1;
}
}
}
if(ma.data.indication.org!=NULL)
{
ma.data.indication.sdu=ma.data.indication.org;
for(l=0;ma.data.indication.sdu!=NULL;l++)
{
p=ma.data.indication.sdu->next;
free(ma.data.indication.sdu);
ma.data.indication.sdu=p;
}
ma.data.indication.status=0;
ma.data.indication.org=NULL;
}
switch(func_tmp)
{
case TOKEN_ASK:token_stat=WAIT;break;
case SUCESS1:token_ctrl=sucesor1;break;
case SUCESS2:token_ctrl=sucesor2;break;
case WHO_NEXT:token_ctrl=quiensigue;break;
case BATTLE:token_ctrl=contienda;break;
case TOKEN_PASS:token_ctrl=paso;break;
case STABLISH:token_ctrl=escape;break;
}
}
else
258
goto finito;
ma.data.indication.activa=0;
}
}
else
{
finito:
if(ma.data.indication.org!=NULL)
{
ma.data.indication.sdu=ma.data.indication.org;
for(l=0;ma.data.indication.sdu!=NULL;l++)
{
p=ma.data.indication.sdu->next;
free(ma.data.indication.sdu);
ma.data.indication.sdu=p;
}
ma.data.indication.status=0;
ma.data.indication.org=NULL;
}
phy.unitdata.indication=0;
p=NULL;
free(p);
return(1);
}
phy.unitdata.indication=0;
p=NULL;
free(p);
}
return(0);
}
/*rutina de gestión de peticiones LLC recibidas ,recibe una PDU_LLC de indicacion
(INDICATION) proviniente del nivel MAC, comprueba que la petición solicitada cumpla
con el protocolo establecido para cada servicio ,creando posteriormente la respuesta a
solicitudes con confirmación (ej. TEST) ,actualizando variables de las
comunicaciones(ej. ventana de transmisión ,WINXID) , creando las tramas LLC de
indicacion (INDICATION) (ej. DL.CONNECT.INDICATION) correspondientes o tomando las
medidas opotunas (ej. reposicionar puntero a fichero descarga en servicio CMS al recibir
un REJ por trama errónea o actualizar el número de secuencia recibida). En caso de
encontrar algún fallo devuelve el código de error '1'*/
char LLC_in_level(void)
{
char p_r=0,c,fallo=0;
int cpu_tmp=0,win_tmp;
long l;
float f,f_aux;
one_byte *p;
if(ma.data.indication.activa)
{
ma.data.indication.activa=0;
if(ma.data.indication.org!=NULL)
{
ma.data.indication.sdu=ma.data.indication.org;
if(((ma.data.indication.sdu->byte)&0xC0)==0xC0)
{
if(ma.data.indication.sdu->byte&0x08)
p_r=1;
if(! ((ma.data.indication.sdu->byte)&0x30) ) /*UCS*/
{
if( ((ma.data.indication.sdu->byte)&0x07)==0x01) /*UI*/
{
259
dl.unitdata.indication.dir_org=ma.data.indication.dir_org;
dl.unitdata.indication.dir_dest=ma.data.indication.dir_dest;
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
dinamic_LLC(0x00,UNITDATA,ma.data.indication.sdu->byte);
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
for (l=0;ma.data.indication.sdu!=NULL;l++)
{
dinamic_LLC(0x01,UNITDATA,ma.data.indication.sdu->byte);
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
}
dl.unitdata.indication.datos=dl.unitdata.indication.org;
dl.unitdata.indication.activa=1;
L7_ctrl=L7UI;
}
else
if( ((ma.data.indication.sdu->byte)&0x07)==0x03) /*XID*/
{
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
dl.unitdata.indication.dir_org=ma.data.indication.dir_org;
dl.unitdata.indication.dir_dest=ma.data.indication.dir_dest;
L7_ctrl=L7XID;
win_tmp=(int)(ma.data.indication.sdu->byte-0x30);
if(ma.data.indication.sdu->next!=NULL)
{
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
win_tmp =win_tmp*10 + (int)(ma.data.indication.sdu->byte-0x30);
}
if(win_tmp<winXID)
winXID=win_tmp;
RX_BUF_SIZE = (10000/winXID);
MAC_BUF_SIZE=RX_BUF_SIZE;
MAXDATA= RX_BUF_SIZE-40;
if(p_r)
{
dl.unitdata.request.dir_dest=ma.data.indication.dir_org;
strcpy(filename,"XID.CFG");
LLC_interface_envios(UCS,XID,0,0x00);
}
}
else
if( ((ma.data.indication.sdu->byte)&0x07)==0x02) /*TEST*/
{
dl.unitdata.indication.dir_org=ma.data.indication.dir_org;
dl.unitdata.indication.dir_dest=ma.data.indication.dir_dest;
L7_ctrl=L7TEST;
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
cpu_tmp=0;
if(p_r)
{
while((ma.data.indication.sdu->byte!=0x20)&&(cpu_tmp<=486))
{
if(ma.data.indication.sdu->byte!=0x20)
cpu_tmp=cpu_tmp*10+(ma.data.indication.sdu->byte-0x30);
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
}
if(cpu_tmp==CPU)
cpu_tmp=386;
else
CPU=cpu_tmp;
cfg=fopen("test.cfg","w");
260
if(cfg!=NULL)
fprintf(cfg,"%d %s",CPU,"cpu test");
fclose(cfg);
dl.unitdata.request.dir_dest=ma.data.indication.dir_org;
strcpy(filename,"TEST.CFG");
LLC_interface_envios(UCS,TEST,0,0x00);
}
else
{
while((ma.data.indication.sdu->byte!=0x20)&&(cpu_tmp<=486))
{
if(ma.data.indication.sdu->byte!=0x20)
cpu_tmp=cpu_tmp*10+(ma.data.indication.sdu->byte-0x30);
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
}
CPU=cpu_tmp;
if((token_stat==PASO)&&(ma.data.indication.dir_org==Next_Address))
{
if(L7_stat==EXIT)
{
disable();
phy.notify.invoke=1;
enable();
cfg=fopen("input.dep","a");
if(cfg!=NULL)
fprintf(cfg,"\nDisconnect Mode\n");
fclose(cfg);
}
token_stat=NOTOKEN;
L7_ctrl=L7OFF;
timer_token=TIMEOUT_response;
}
}
}
else
fallo=1;
}
else
if(((ma.data.indication.sdu->byte)&0x30)==0x10) /*CMS*/
{
if( ((ma.data.indication.sdu->byte)&0x0F)==0x09) /*SABME*/
{
dl.connect.indication.dir_org=ma.data.indication.dir_org;
dl.connect.indication.dir_dest=ma.data.indication.dir_dest;
dl.connect.indication.activa=1;
if(p_r)
{
dl.connect.confirm.dir_dest=ma.data.indication.dir_org;
strcpy(filename,"vacio");
LLC_interface_envios(CMS,UNNUMBERED,UASABME,0x00);
}
}
else
if( ((ma.data.indication.sdu->byte)&0x0F)==0x0A) /*DISC*/
{
dl.disconnect.indication.dir_org=ma.data.indication.dir_org;
dl.disconnect.indication.dir_dest=ma.data.indication.dir_dest;
dl.disconnect.indication.motivo=0x00;
dl.disconnect.indication.activa=1;
if(p_r)
261
{
dl.disconnect.confirm.dir_dest=ma.data.indication.dir_org;
strcpy(filename,"vacio");
LLC_interface_envios(CMS,UNNUMBERED,UADISC,0x00);
}
}
else
if( ((ma.data.indication.sdu->byte)&0x0F)==0x0B) /*UA*/
{
dl.unitdata.indication.dir_org=ma.data.indication.dir_org;
dl.unitdata.indication.dir_dest=ma.data.indication.dir_dest;
if((L7_stat==CMSUA_SABME)||(L7_stat==CMSUA_DISC)||(L7_stat==CMSUA_RST))
L7_stat++;
}
else
if( ((ma.data.indication.sdu->byte)&0x0F)==0x01) /*DM*/
{
dl.unitdata.indication.dir_org=ma.data.indication.dir_org;
dl.unitdata.indication.dir_dest=ma.data.indication.dir_dest;
L7_stat=REPOSO;
dl.disconnect.indication.dir_org=Local_Address;
dl.disconnect.indication.motivo = 0x03;
dl.disconnect.indication.activa=1;
}
else
if( ((ma.data.indication.sdu->byte)&0x0F)==0x02) /*FRMR*/
{
dl.unitdata.indication.dir_org=ma.data.indication.dir_org;
dl.unitdata.indication.dir_dest=ma.data.indication.dir_dest;
if((L7_stat>=INICMS)&&(L7_stat<CMSACK))
{
L7_stat=INICMS;
dl.unitdata.request.dir_dest=dl.unitdata.indication.dir_org;
}
else
{
if(L7_stat==CMSUA_DISC)
{
filepos=1L;
endfile=1L;
L7_stat=CMSI;
}
else
{
if(L7_stat==CMSUA_RST)
{
strcpy(filename,"vacio");
dl.reset.request.dir_dest=dl.unitdata.indication.dir_org;
LLC_interface_envios(CMS,UNNUMBERED,RST,0x01);
}
}
}
}
else
if( ((ma.data.indication.sdu->byte)&0x0F)==0x03) /*RST*/
{
dl.reset.indication.dir_org=ma.data.indication.dir_org;
dl.reset.indication.dir_dest=ma.data.indication.dir_dest;
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
dl.reset.indication.motivo=ma.data.indication.sdu->byte;
262
dl.reset.indication.activa=1;
if(p_r)
{
dl.reset.confirm.dir_dest=ma.data.indication.dir_org;
strcpy(filename,"vacio");
LLC_interface_envios(CMS,UNNUMBERED,UARST,0x00);
}
}
else
fallo=1;
}
else
if(((ma.data.indication.sdu->byte)&0x30)==0x20) /*ACS*/
{
if( ((ma.data.indication.sdu->byte)&0x07)==0x01) /*AC*/
{
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
if(!p_r)
{
dl.data_ack_status.indication.dir_org=ma.data.indication.dir_org;
dl.data_ack_status.indication.dir_dest=ma.data.indication.dir_dest;
ma.data_status.indication.calidad.estado=0x00;
dl.data_ack_status.indication.estado = ma.data_status.indication.calidad.estado;
dl.data_ack_status.indication.activa=1;
L7_ctrl=L7AC;
}
else
{
dl.data_ack.indication.dir_org=ma.data.indication.dir_org;
dl.data_ack.indication.dir_dest=ma.data.indication.dir_dest;
cfg=fopen("acs.cfg","w");
dinamic_LLC(0x00,DATA_ACK,ma.data.indication.sdu->byte);
if(cfg!=NULL)
fprintf(cfg,"%c",ma.data.indication.sdu->byte);
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
for (l=0;ma.data.indication.sdu!=NULL;l++)
{
dinamic_LLC(0x01,DATA_ACK,ma.data.indication.sdu->byte);
if(cfg!=NULL)
fprintf(cfg,"%c",ma.data.indication.sdu->byte);
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
}
fclose(cfg);
dl.data_ack.request.dir_dest=ma.data.indication.dir_org;
dl.data_ack.indication.datos=dl.data_ack.indication.org;
dl.data_ack.indication.activa=1;
strcpy(filename,"acs.cfg");
LLC_interface_envios(ACS,0,0,0x00);
}
}
else
fallo=1;
}
else
fallo=1;
}
else
if(((ma.data.indication.sdu->byte)&0xC0)==0x80) /* CMS*/
{
if( ((ma.data.indication.sdu->byte)&0x30)==0x00) /*RR*/
263
{
dl.connection_flowcontrol.indication.dir_org=ma.data.indication.dir_org;
dl.connection_flowcontrol.indication.dir_dest=ma.data.indication.dir_dest;
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
dl.connection_flowcontrol.indication.numdatos=(ma.data.indication.sdu->byte)&0x7F;
seqrec=dl.connection_flowcontrol.indication.numdatos;
dl.connection_flowcontrol.indication.activa=1;
if((L7_stat==CMSACK)||(L7_stat==CMSWAIT))
{
timer_ack0=-1;
if(seqrec==winXID)
L7_stat=CMSI;
else
{
L7_stat=CMSUA_RST;
strcpy(filename,"vacio");
dl.reset.request.dir_dest=dl.connection_flowcontrol.indication.dir_org;
LLC_interface_envios(CMS,UNNUMBERED,RST,0x01);
dl.reset.indication.dir_org=Local_Address;
dl.reset.indication.activa=1;
}
}
}
else
if( ((ma.data.indication.sdu->byte)&0x30)==0x10) /*RNR*/
{
dl.connection_flowcontrol.indication.dir_org=ma.data.indication.dir_org;
dl.connection_flowcontrol.indication.dir_dest=ma.data.indication.dir_dest;
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
dl.connection_flowcontrol.indication.numdatos=(ma.data.indication.sdu->byte)&0x7F;
seqrec=dl.connection_flowcontrol.indication.numdatos;
dl.connection_flowcontrol.indication.activa=1;
if( L7_stat==CMSACK)
{
timer_ack0=-1;
if(seqrec==winXID)
L7_stat=CMSWAIT;
else
{
L7_stat=CMSUA_RST;
strcpy(filename,"vacio");
dl.reset.request.dir_dest=dl.connection_flowcontrol.indication.dir_org;
LLC_interface_envios(CMS,UNNUMBERED,RST,0x01);
dl.reset.indication.dir_org=Local_Address;
dl.reset.indication.activa=1;
}
}
}
else
if( ((ma.data.indication.sdu->byte)&0x30)==0x20) /*REJ*/
{
dl.connection_flowcontrol.indication.dir_org=ma.data.indication.dir_org;
dl.connection_flowcontrol.indication.dir_dest=ma.data.indication.dir_dest;
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
dl.connection_flowcontrol.indication.numdatos=(ma.data.indication.sdu->byte)&0x7F;
seqrec=dl.connection_flowcontrol.indication.numdatos;
dl.connection_flowcontrol.indication.activa=1;
timer_ack0=-1;
cfg=fopen(filename,"r");
if(cfg!=NULL)
264
{
fseek(cfg, 0L, SEEK_SET);
if(seqrec>=seqsend)
winseq--;
f= (float)(seqrec)+(float)(winseq*winXID);
f=f*(float)(MAXDATA);
if(f>0.0)
{for(f_aux=0.0;f_aux<f;f_aux=f_aux+1.0)
c=getc(cfg);
}
fgetpos(cfg,&filepos);
seqsend=seqrec;
L7_stat=CMSREJ;
}
if((filepos>endfile)||(cfg==NULL))
{
L7_stat=CMSUA_RST;
strcpy(filename,"vacio");
dl.reset.request.dir_dest=dl.connection_flowcontrol.indication.dir_org;
LLC_interface_envios(CMS,UNNUMBERED,RST,0x01);
dl.reset.indication.dir_org=Local_Address;
dl.reset.indication.activa=1;
}
fclose(cfg);
}
else
fallo=1;
}
else
if(!((ma.data.indication.sdu->byte)&0x80)) /*I*/
{
seqrec=(ma.data.indication.sdu->byte);
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
dinamic_LLC(0x00,DATA,ma.data.indication.sdu->byte);
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
for (l=0;ma.data.indication.sdu!=NULL;l++)
{
dinamic_LLC(0x01,DATA,ma.data.indication.sdu->byte);
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
}
dl.data.indication.datos=dl.data.indication.org;
dl.data.indication.dir_org=ma.data.indication.dir_org;
dl.data.indication.dir_dest=ma.data.indication.dir_dest;
dl.data.indication.activa =1;
}
else
fallo=1;
if(ma.data.indication.org!=NULL)
{
ma.data.indication.sdu=ma.data.indication.org;
for(l=0;ma.data.indication.sdu!=NULL;l++)
{
p=ma.data.indication.sdu->next;
free(ma.data.indication.sdu);
ma.data.indication.sdu=p;
}
ma.data.indication.status=0;
ma.data.indication.org=NULL;
}
265
p=NULL;
free(p);
return(fallo);
}
else
return(1);
}
return(0);
}
/*rutina para limpiar la última operación almacenada ,en el fichero temporal
"EPROM.CFG" de rutinas solicitadas por el usuario*/
void resetEPROM()
{
int aux,cmd,adr,emr;
long posf,finf;
unsigned int dest;
FILE *rom,*tmp;
rom=fopen("EPROM.cfg","r");
tmp=fopen("SRAM.cfg","w");
if((rom!=NULL)&&(tmp!=NULL))
{
fseek(rom,0L,SEEK_END);
if( (finf = ftell(rom)) >0L)
{
fseek(rom,0L,SEEK_SET);
while(!feof(rom)&&!feof(tmp))
{
posf = ftell(rom);
if(!feof(rom)&&!feof(tmp))
fscanf(rom,"%x %d %u %d\n",&cmd,&adr,&dest,&emr);
if(posf!=(finf-1L))
{
if(!feof(rom)&&!feof(tmp))
fprintf(tmp,"%x %d %u %d\n",cmd,adr,dest,emr);
}
}
fclose(rom);
fclose(tmp);
rom=fopen("EPROM.cfg","w");
tmp=fopen("SRAM.cfg","r");
if((rom!=NULL)&&(tmp!=NULL))
{
while(!feof(tmp)&&!feof(rom))
{
aux=getc(tmp);
if(!feof(tmp))
putc(aux,rom);
}
}
}
}
fclose(tmp);
fclose(rom);
}
/*rutina de gestión de las tramas LLC de indicación recibidas,se le ha de pasar el número
de microprocesadores del bus de campo para su actualización,la posición en el eje <y>
de la gráfica de la señal analógica elegida para su actualización,la variable de permiso de
captura de los valores de dicha señal y el número actual de registro de memoria
extendido. Realiza un control de las peticiones locales o externas recibidas ,actualizando
el archivo EPROM.CFG de peticiones de usuario.En caso de fallos graves en las
266
transmisiones devuelve un código de error '1'. Para el servicio CMS realiza el
almacenamiento de punteros a ficheros solicitados por otras estaciones en el fichero de
estado de las transmisiones RAM.CFG.*/
uchar L7_in_level(int *num_plcs,int *col,char *rec,int EMR)
{
div_t V;
int i=0,j=0,comand=-1;
int plc_dir=-1;
uint origen=0;
long l;
one_byte *p;
char string[25],str[64],c_aux1=0,c_aux2=0;
struct restaura
{
uint origen,old,win;
long pos,end;
char find,open;
char nom[20];
}backup;
FILE *TMP,*RAM,*AUX;
/*Gestión de desconexiones de transmisiones en curso ,en caso de ser externas guarda
el contexto de la transmision (secuencias de transmision/recepcion,posicion del
puntero,ventana de trnasmision,etc..)*/
if(dl.disconnect.indication.activa)
{
dl.disconnect.indication.activa=0;
if(dl.disconnect.indication.motivo&&(dl.disconnect.indication.motivo<6))
{
seqsend=0;
winseq=0;
L7_ctrl=OFF;
L7_stat=REPOSO;
}
else
{
if(openFILE)
{
timer_ack1=-1;
if(filepos!=endfile)
{
RAM=fopen("RAM.cfg","a");
if(RAM!=NULL)
fprintf(RAM,"%u %ld %ld %u %u %x %s\n",dl.disconnect.indication.dir_org,filepos,endfile,
oldseq, winXID, openFILE,nomfich);
fclose(RAM);
oldseq=0;
openFILE=0;
}
else
{
winXID=WINDOW;
RX_BUF_SIZE = 10000/winXID;
MAC_BUF_SIZE=RX_BUF_SIZE;
MAXDATA= RX_BUF_SIZE-40;
oldseq=0;
filepos=0;
endfile=0;
openFILE=0;
if((pag==2)&&(!strcmp(nomfich,"plcfile.dat")))
valores();
267
if((pag<2)&&(!strcmp(nomfich,"workst.dat")))
{
TMP=fopen("workst.dat","r");
AUX=fopen("station.dat","w");
while(!feof(TMP)&&!feof(AUX))
fprintf(AUX,"%c",getc(TMP));
fclose(AUX);
fclose(TMP);
}
origen=dl.disconnect.indication.dir_org;
goto resetRAM;
}
}
}
winXID=WINDOW;
RX_BUF_SIZE = 10000/winXID;
MAC_BUF_SIZE=RX_BUF_SIZE;
MAXDATA= RX_BUF_SIZE-40;
filepos=0;
endfile=0;
}
/*Gestión de reinicialización de transmisiones en curso*/
if(dl.reset.indication.activa)
{
dl.reset.indication.activa=0;
seqsend=0;
winseq=0;
winXID=WINDOW;
RX_BUF_SIZE = 10000/winXID;
MAC_BUF_SIZE=RX_BUF_SIZE;
MAXDATA= RX_BUF_SIZE-40;
seqrec=0;
oldseq=0;
filepos=0;
endfile=0;
L7_ctrl=OFF;
openFILE=0;
if(dl.reset.indication.dir_org==Local_Address)
{
L7_stat=INICMS;
dl.unitdata.request.dir_dest=dl.reset.indication.dir_dest;
TMP=fopen("ROM.cfg","w");
fclose(TMP);
resetEPROM();
}
else
{
L7_stat=REPOSO;
origen=dl.reset.indication.dir_org;
goto resetRAM;
}
}
/*servicio UCS ,solicitudes o avisos externos*/
if(dl.unitdata.indication.activa)
{
dl.unitdata.indication.activa=0;
if(pag<2)
{
setfillstyle(SOLID_FILL,0);
bar(332,456,425,472);
268
setcolor(7);
outtextxy(335,460,"Ext.Warning");
}
if(dl.unitdata.indication.org!=NULL)
{
i=-1;
dl.unitdata.indication.datos=dl.unitdata.indication.org;
for(j=0;dl.unitdata.indication.datos!=NULL;j++)
{
p=dl.unitdata.indication.datos->next;
if(L7_ctrl==L7UI)
{
if(i>=0)
string[i++]=dl.unitdata.indication.datos->byte;
if(dl.unitdata.indication.datos->byte==0x23)
{
str[j]='\0';
i=0;
}
if(i<0)
str[j]=dl.unitdata.indication.datos->byte;
}
free(dl.unitdata.indication.datos);
dl.unitdata.indication.datos=p;
}
dl.unitdata.indication.status=0;
dl.unitdata.indication.org=NULL;
if(L7_ctrl==L7UI)
{
origen=dl.unitdata.indication.dir_org;
if(i<0)
str[j]='\0';
else
string[i++]='\0';
j=atoi(string);
if(!strcmp("command: send number of plcs",str))
comand=0x20;
else
if(!strcmp("command: MODBUS error",str))
message("Bus Error",0);
else
if((!strcmp("command: Mode changed to value ",str))&&(pag==2))
{
itoa(j,string,10);
fondo(615,25,625,35,7,8);
outtextxy(619,25,string);
outtextxy(535,25,"Listen Mode");
}
else
if((!strcmp("command: DO changed to value ",str))&&(pag==2))
{
if(j<10)
i=7;
else
i=7-(j/10);
j=j&1;
itoa(j,string,10);
fondo(439+i*10,83,447+i*10,93,7,7);
setcolor(8);
outtextxy(440+i*10,83,string);
269
outtextxy(415,85,"DO");
}
else
if((!strcmp("command: AI value is ",str))&&(pag==3))
{
i=j&0xFF;
j=(j>>8);
j--;
comand=0x40|j;
if(*rec==1)
{
TMP=fopen("historic.dat","a");
if(TMP!=NULL)
fprintf(TMP,"[AI %d]\n",j);
fclose(TMP);
*rec=2;
}
else
if(*rec==2)
{
TMP=fopen("historic.dat","a");
if(TMP!=NULL)
fprintf(TMP,"%d.",i);
fclose(TMP);
}
if(i)
{
V = div(i,51);
if(V.rem)
V.rem= V.rem + V.rem/2;
i=V.quot*80 + V.rem;
putpixel(*col,420-i,10);
}
else
putpixel(*col,420,10);
*col=*col+1;
if(*col>=628)
*col=21;
}
L7_ctrl=L7OFF;
}
p=NULL;
free(p);
}
}
/*servicio ACS ,comandos externos a ejecutar*/
if(dl.data_ack.indication.activa)
{
dl.data_ack.indication.activa=0;
if(pag<2)
{
setfillstyle(SOLID_FILL,0);
bar(332,456,425,472);
setcolor(7);
outtextxy(335,460,"Ext.Command");
}
if(dl.data_ack.indication.org!=NULL)
{
i=-1;
dl.data_ack.indication.datos=dl.data_ack.indication.org;
270
for(j=0;dl.data_ack.indication.datos!=NULL;j++)
{
p=dl.data_ack.indication.datos->next;
if(i>=0)
string[i++]=dl.data_ack.indication.datos->byte;
if(dl.data_ack.indication.datos->byte==0x23)
{
str[j]='\0';
i=0;
}
if(i<0)
str[j]=dl.data_ack.indication.datos->byte;
free(dl.data_ack.indication.datos);
dl.data_ack.indication.datos=p;
}
dl.data_ack.indication.status=0;
dl.data_ack.indication.org=NULL;
string[i++]='\0';
origen=dl.data_ack.indication.dir_org;
i=atoi(string);
if(!strcmp("command: disconnect from lan ",str))
comand=0xFF;
p=NULL;
free(p);
}
}
/*servicio CMS ,transmisión de ficheros de texto (información recogida de las bases de
datos)*/
if(dl.data.indication.activa)
{
dl.data.indication.activa =0;
/*Actualiza última operación realizada con la estación solicitante*/
RAM=fopen("RAM.cfg","r");
TMP=fopen("copia.cfg","w");
if((RAM!=NULL)&&(TMP!=NULL))
{
fseek(RAM,0L,SEEK_END);
if(ftell(RAM)>0L)
{
fseek(RAM,0L,SEEK_SET);
backup.find=0;
while(!feof(RAM)&&!feof(TMP))
{
if(!feof(RAM)&&!feof(TMP))
fscanf(RAM,"%u %ld %ld %u %u %x
%s\n",&backup.origen,&backup.pos,&backup.end,&backup.old,
&backup.win,&backup.open,backup.nom);
if((backup.origen==dl.data.indication.dir_org)&&!backup.find)
{
backup.find=1;
filepos=backup.pos;
endfile=backup.end;
oldseq=backup.old;
winXID=backup.win;
openFILE=backup.open;
strcpy(nomfich,backup.nom);
}
else
{
if(!feof(RAM)&&!feof(TMP))
271
fprintf(TMP,"%u %ld %ld %u %u %x %s\n",backup.origen,backup.pos,backup.end,backup.old,
backup.win, backup.open,backup.nom);
}
}
fclose(RAM);
fclose(TMP);
RAM=fopen("RAM.cfg","w");
TMP=fopen("copia.cfg","r");
if((RAM!=NULL)&&(TMP!=NULL))
{
while(!feof(TMP)&&!feof(RAM))
{
c_aux1=getc(TMP);
if(!feof(TMP))
putc(c_aux1,RAM);
}
}
}
}
fclose(TMP);
fclose(RAM);
if(seqrec!=(oldseq+1))
{
error_sequence:
ma.data.request.activa=0;
if(dl.data.indication.org!=NULL)
{
dl.data.indication.datos=dl.data.indication.org;
for(l=0;dl.data.indication.datos!=NULL;l++)
{
p=dl.data.indication.datos->next;
free(dl.data.indication.datos);
dl.data.indication.datos=p;
}
dl.data.indication.status=0;
dl.data.indication.org=NULL;
}
p=NULL;
free(p);
timer_ack1=TIMEOUT_ack1;
return(1);
}
if(openFILE)
TMP=fopen(nomfich,"a");
if(dl.data.indication.org!=NULL)
{
i=0;
j=0;
c_aux1=0;
c_aux2=0;
dl.data.indication.datos=dl.data.indication.org;
for(l=0;dl.data.indication.datos!=NULL;l++)
{
if(!openFILE)
{
if(!c_aux1)
{
if(dl.data.indication.datos->byte!=0x2E)
{
nomfich[i++]=dl.data.indication.datos->byte;
272
if(i>8)
goto error_sequence;
}
else
{
nomfich[i++]=dl.data.indication.datos->byte;
j=i;
i=0;
c_aux1=1;
}
}
else
{
if(!c_aux2)
{
if(dl.data.indication.datos->byte!=0xFF)
{
nomfich[j+i]=dl.data.indication.datos->byte;
i++;
if(i>3)
goto error_sequence;
}
else
c_aux2=1;
}
else
{
nomfich[i+j]='\0';
TMP=fopen(nomfich,"w");
fclose(TMP);
TMP=fopen(nomfich,"a");
openFILE=1;
endfile=0L;
filepos=0L;
i=0;
}
}
}
if(openFILE)
{
if(endfile==0L)
{
if(dl.data.indication.datos->byte!=0xFF)
{
string[i++]=dl.data.indication.datos->byte;
if(i>7)
{
fclose(TMP);
goto error_sequence;
}
}
else
{
string[i++]='\0';
endfile=atol(string);
string[0]='\0';
i=0;
j=0;
}
}
273
else
{
if(dl.data.indication.datos->byte!=0xFF)
{
if(TMP!=NULL)
fprintf(TMP,"%c",dl.data.indication.datos->byte);
if( ((dl.data.indication.datos->byte==0x23)||j)&&(!strcmp(nomfich,"workst.dat")) )
{
j=1;
if((dl.data.indication.datos->byte>0x29)&&(dl.data.indication.datos->byte<0x40))
{
string[i++]=dl.data.indication.datos->byte;
if(i>2)
{
fclose(TMP);
goto error_sequence;
}
}
}
filepos++;
}
else
{
filepos=endfile;
if(!strcmp(nomfich,"workst.dat"))
{
string[i++]='\0';
*num_plcs=atoi(string);
}
goto da_ack;
}
}
}
dl.data.indication.datos=dl.data.indication.datos->next;
}
}
if(seqrec==winXID)
{
da_ack:
if((unsigned long)coreleft()>=1000L)
{
dl.connection_flowcontrol.request.dir_dest=dl.data.indication.dir_org;
strcpy(filename,"vacio");
LLC_interface_envios(CMS,SUPERVISORY,RR,0x00);
}
else
{
dl.connection_flowcontrol.request.dir_dest=dl.data.indication.dir_org;
strcpy(filename,"vacio");
LLC_interface_envios(CMS,SUPERVISORY,RNR,0x00);
}
oldseq=0;
}
else
oldseq=seqrec;
if(openFILE)
fclose(TMP);
if(pag<2)
{
274
setfillstyle(SOLID_FILL,0);
bar(332,456,425,472);
outtextxy(335,460,"Ext.File");
}
if(dl.data.indication.org!=NULL)
{
dl.data.indication.datos=dl.data.indication.org;
for(l=0;dl.data.indication.datos!=NULL;l++)
{
p=dl.data.indication.datos->next;
free(dl.data.indication.datos);
dl.data.indication.datos=p;
}
dl.data.indication.status=0;
dl.data.indication.org=NULL;
}
timer_ack1=TIMEOUT_ack1;
p=NULL;
free(p);
}
if(comand!=-1)
{
TMP=fopen("EPROM.cfg","a");
if(TMP!=NULL)
fprintf(TMP,"%x %d %u %d\n",comand,plc_dir,origen,EMR);
fclose(TMP);
if(pag<2)
{
setfillstyle(SOLID_FILL,0);
bar(332,456,425,472);
outtextxy(335,460,"Ext. Query");
}
}
return(0);
/*borrado de peticiones ya atendidas*/
resetRAM:
RAM=fopen("RAM.cfg","r");
TMP=fopen("copia.cfg","w");
if((RAM!=NULL)&&(TMP!=NULL))
{
fseek(RAM,0L,SEEK_END);
if(ftell(RAM)>0L)
{
fseek(RAM,0L,SEEK_SET);
while(!feof(RAM)&&!feof(TMP))
{
fscanf(RAM,"%u %ld %ld %u %u %x
%s\n",&backup.origen,&backup.pos,&backup.end,&backup.old,
&backup.win,&backup.open,backup.nom);
if(backup.origen!=origen)
{
if(!feof(TMP)&&!feof(RAM))
fprintf(TMP,"%u %ld %ld %u %u %x %s\n",backup.origen,backup.pos,backup.end,backup.old,
backup.win, backup.open,backup.nom);
}
}
fclose(TMP);
fclose(RAM);
RAM=fopen("RAM.cfg","w");
TMP=fopen("copia.cfg","r");
275
if((RAM!=NULL)&&(TMP!=NULL))
{
while(!feof(TMP)&&!feof(RAM))
{
fscanf(TMP,"%u %ld %ld %u %u %x
%s\n",&backup.origen,&backup.pos,&backup.end,&backup.old
&backup.win,&backup.open,backup.nom);
if(!feof(TMP)&&!feof(RAM))
fprintf(RAM,"%u %ld %ld %u %u %x
%s\n",backup.origen,backup.pos,backup.end,backup.old,backup.win,
backup.open,backup.nom);
}
}
}
}
fclose(RAM);
fclose(TMP);
return(0);
}
/*rutina de visualización de las estaciones y microcontroladores activos en la red local y
en el bus de campo seleccionado,además de la información general de características de
la estación local o de la estación escogida e incluso los estados actuales del nivel
superior y del testigo.Devuelve el valor actualizado de la posición de la estación
local.Necesita que le pase la dirección a borrar del testigo (0 si no hay que realizar tal
operación) ,el ciclo de testigo en que se halla para presentar el estado de acceso a las
otras estaciones definidos por un código de colores (0 iniciado ,1 configurado ,2
finalizado) y el nº de microcontroladores actualizados*/
void showred(uint address,int *posx,int *posy,char ciclo,int num1)
{
int netposx, netposy,i;
uint dir_station=0;
if(!pag)
pantalla(0);
if(pag==1)
{
pantalla(1);
netposx=32;
netposy=324;
for (i=0;i<num1;i++)
{
if(i==16)
{
netposy=372;
netposx=32;
}
fondo(netposx,netposy,netposx+2,netposy-8,3,6);
fondo(netposx,netposy,netposx+10,netposy+10,9,6);
netposx=netposx+32;
}
doc("station.dat",2);
}
if(!pag)
doc("history.dat",2);
netposx=32;
netposy=16;
for (i=0;i<=63;i=i+2)
{
dir_station=(TABLA[i]<<8)|(TABLA[i+1]);
if(i==32)
{
276
netposy=64;
netposx=32;
}
if((dir_station==address)&&address)
{
TABLA[i]=0;
TABLA[i+1]=0;
dir_station=0;
if(pag<2)
{
fondo(netposx,netposy,netposx+2,netposy-8,3,6);
fondo(netposx,netposy,netposx+10,netposy+10,0,6);
}
}
if(pag<2)
{
if(!dir_station)
netposx=netposx+32;
else
{
if(dir_station==Local_Address)
{
if(pag<2)
{
fondo(netposx,netposy,netposx+2,netposy-8,3,6);
fondo(netposx,netposy,netposx+10,netposy+10,11,6);
}
*posx=netposx;
*posy=netposy;
netposx=netposx+32;
}
else
{
if(pag<2)
{
fondo(netposx,netposy,netposx+2,netposy-8,3,6);
if(ciclo<2)
fondo(netposx,netposy,netposx+10,netposy+10,8,6);
else
fondo(netposx,netposy,netposx+10,netposy+10,9,6);
}
netposx=netposx+32;
}
}
}
}
if(pag<2)
{
setcolor(7);
settextstyle(DEFAULT_FONT,HORIZ_DIR,1);
outtextxy(335,430,tokennom[token_stat]);
outtextxy(335,445,L7nom[L7_stat&0x1F]);
}
putimage(mx,my,raton,XOR_PUT);
}
/*rutina de creación de una trama LLC de salida (petición MAC REQUEST) para enviar al
nivel inferior MAC,actualizando el aviso de liberación/retención de la trama de salida
(según el servicio sea con reconocimiento o sin este)*/
void LLC_out()
{
277
if(ma.data.request.activa)
{
ma.data.request.activa=0;
cola();
if(ma.data.request.calidad.tipo!=0x02)
{
ma.data_status.indication.dir_dest=ma.data.request.dir_dest;
ma.data_status.indication.dir_org=Local_Address;
ma.data_status.indication.activa=1;
ma.data_status.indication.calidad.estado=0x00;
}
else
ma.data_status.indication.calidad.estado=0x01;
phy.unitdata.request=1;
}
}
/*rutina que devuelve el comando a ejecutar si se pulsa uno de los botones del
ratón,emplea las funciones definidas en la BIOS para el control del ratón ,se le ha de
pasar el comando para que lo actualice ,el número de microprocesadores que tiene el
bus de campo,la dirección actual del microcontrolador escogido,el número de registro
actual de memoria extendida,la variable de permiso para almacenar los valores actuales
de la señal analógica seleccionada y la posición actual en el eje <y> de la gráfica de
dicha señal mencionada. Pulsando el botón izquierdo se accede a la información y
pulsando el izquierdo regresamos a la pantalla anterior o limpiamos la actual según la
página en la que nos encontremos*/
char mouse_stat(int *cmd,int *numplcs,int plc_adr,int *emr,char *record,int *col,char *buttonhit)
{
union REGS inregs,outregs;
int aux;
char string[25];
inregs.x.ax = 6;
int86(0x33,&inregs,&outregs);
if(((outregs.x.ax&3)==1)&&(!*buttonhit))
{
inregs.x.ax = 3;
int86(0x33,&inregs,&outregs);
*cmd=-1;
if(pag<2)
{
if((outregs.x.dx==456)&&(outregs.x.cx==611))
{
if(!pag)
*cmd=0xF0;
else
*cmd=0xB0;
}
else
{
aux=(int)(outregs.x.cx);
while(aux>0)
{
aux=aux-32;
*cmd=*cmd+1;
}
if(!aux)
{
if(!pag)
{
if((outregs.x.dx==16)||(outregs.x.dx==64))
{
278
if(outregs.x.dx==16)
outregs.x.dx=0x00;
else
outregs.x.dx=0x10;
*cmd=(int)(outregs.x.dx)|*cmd;
}
else
*cmd=-1;
}
else
{
if((outregs.x.dx==324)||(outregs.x.dx==372))
{
if(outregs.x.dx==324)
outregs.x.dx=0x90;
else
outregs.x.dx=0xA0;
*cmd=(int)(outregs.x.dx)|*cmd;
}
else
*cmd=-1;
}
}
else
*cmd=-1;
}
}
else
{
if(pag==2)
{
if((outregs.x.dx==5)&&(outregs.x.cx==5))
{
setcolor(10);
outtextxy(21,8,"Set Now");
*cmd=(plc_adr-1)&0x0F;
if(plc_adr>16)
*cmd=0xA0|*cmd;
else
*cmd=0x90|*cmd;
}
if((outregs.x.dx==200)&&(outregs.x.cx==625))
{
*emr=*emr+1;
if(*emr>12)
*emr=1;
*cmd=(plc_adr-1)&0x0F;
if(plc_adr>16)
*cmd=0xA0|*cmd;
else
*cmd=0x90|*cmd;
}
if((outregs.x.cx==615)&&(outregs.x.dx==25))
*cmd=0xD0;
if(outregs.x.dx==85)
{
if((outregs.x.cx>437)&&(outregs.x.cx<509))
{
aux=outregs.x.cx-438+10;
while(aux>0)
{
279
aux=aux-10;
*cmd=*cmd+1;
}
if(!aux)
{
outregs.x.dx=0x30;
*cmd=(int)(outregs.x.dx)|*cmd;
setcolor(10);
outtextxy(415,85,"DO");
}
else
*cmd=-1;
}
}
if(outregs.x.dx==113)
{
if((outregs.x.cx>407)&&(outregs.x.cx<584))
{
aux=outregs.x.cx-408+25;
while(aux>0)
{
aux=aux-25;
*cmd=*cmd+1;
}
if(!aux)
{
grafica();
putimage(mx,my,raton,XOR_PUT);
itoa(plc_adr,string,10);
setcolor(0);
outtextxy(60,449,string);
itoa(*cmd+1,string,10);
outtextxy(190,449,string);
pag=3;
outregs.x.dx=0x40;
*cmd=(int)(outregs.x.dx)|*cmd;
}
else
*cmd=-1;
}
}
}
else
{
if((outregs.x.cx>548)&&(outregs.x.dx>448)&&(outregs.x.cx<595)&&(outregs.x.dx<465))
{
putimage(mx,my,raton,XOR_PUT);
if(*record)
{
*record=0;
fondo(559,456,568,466,0,0);
fondo(585,455,588,466,4,4);
fondo(590,455,593,466,4,4);
}
else
{
*record=1;
fondo(585,455,588,466,0,0);
fondo(590,455,593,466,0,0);
fondo(559,456,568,466,4,4);
280
}
putimage(mx,my,raton,XOR_PUT);
}
}
}
if(*cmd!=-1)
*buttonhit=1;
}
else
if((outregs.x.ax&3)==2)
{
putimage(mx,my,raton,XOR_PUT);
if(pag==3)
{
*col=21;
resetEPROM();
*cmd= (plc_adr-1)&0xF;
if(plc_adr>16)
*cmd=0xA0|*cmd;
else
*cmd=0x90|*cmd;
pag=2;
microlocal();
putimage(mx,my,raton,XOR_PUT);
return(0);
}
pag--;
if(pag<=0)
{
*numplcs=0;
pag=0;
cfg=fopen("ram.img","w");
fclose(cfg);
cfg=fopen("workst.dat","w");
fclose(cfg);
cfg=fopen("station.dat","w");
fclose(cfg);
}
return(1);
}
return(0);
}
/*Esta rutina permite reiniciar las principales variables empleadas en las
comunicaciones,después de una desconexión lógica de la red para poderse incorporar
de nuevo a ella*/
void reinicio()
{
int aux;
timer_recibo=-1;
timer_envio=-1;
timer_ack0=-1;
timer_ack1=-1;
phy.unitdata.request=0;
ma.data.indication.activa=0;
ma.data_status.indication.activa=0;
ma.data_status.indication.calidad.estado=0;
ma.data.request.activa=0;
ma.data.indication.status=0;
ma.data.request.status=0;
dl.unitdata.indication.activa=0;
281
dl.connect.indication.activa=0;
dl.disconnect.indication.activa=0;
dl.reset.indication.activa=0;
dl.data_ack.indication.activa=0;
dl.data_ack_status.indication.activa=0;
dl.connection_flowcontrol.indication.activa=0;
dl.data.indication.activa =0;
dl.unitdata.indication.status=0;
dl.data.indication.status=0;
dl.data_ack.indication.status=0;
dl.unitdata.request.status=0;
dl.data.request.status=0;
dl.data_ack.request.status=0;
set_adrs=0;
Next_Address = Global_Address;
Previous_Address = 0;
filepos=0L;
endfile= 0L;
openFILE=0;
token_stat=NOTOKEN;
L7_stat=REPOSO;
L7_ctrl=L7OFF;
winXID=WINDOW;
RX_BUF_SIZE = 10000/winXID;
MAC_BUF_SIZE=RX_BUF_SIZE;
MAXDATA= RX_BUF_SIZE-40;
RXB_INDEX=0;
RXS_INDEX=0;
for(aux=0;aux<=RX_BUF_SIZE;aux++)
RX_BUF[aux]=0;
pag=0;
TABLA[0]=(uchar)((Local_Address&0xFF00)>>8);
TABLA[1]=(uchar)(Local_Address&0xFF);
for(aux=2;aux<=63;aux++)
TABLA[aux]=0x00;
timer_token=TIMEOUT_response;
phy.unitdata.indication=0;
rotation=0;
phy.notify.invoke=0;
}
/*Rutina para el control de los tiempos durante las comunicaciones,permite tomar
decisiones como desconexión o reset según los casos ,al detectar condiciones de "fuera
de tiempo" (Timeout)*/
uchar ctrl_ack()
{
if((timer_ack1<0)&&openFILE)
{
strcpy(filename,"vacio");
dl.reset.request.dir_dest=dl.data.indication.dir_org;
LLC_interface_envios(CMS,UNNUMBERED,RST,0x01);
dl.reset.indication.dir_org=Local_Address;
dl.reset.indication.dir_dest=dl.reset.request.dir_dest;
dl.reset.indication.activa=1;
if(pag<2)
{
setfillstyle(SOLID_FILL,0);
bar(332,456,425,472);
outtextxy(335,460,"Local Reset");
}
openFILE=0;
282
}
if(ma.data.request.activa)
return(1);
if((timer_ack0<0)&& (token_stat==TOKENACTV))
{
if ( (L7_stat==CMSUA_RST)||(L7_stat==CMSACK)||(L7_stat==CMSUA_DISC)
||(L7_stat==CMSUA_SABME) )
{
dl.disconnect.indication.dir_org=Local_Address;
dl.disconnect.indication.motivo = 0x04;
dl.disconnect.indication.activa=1;
if(pag<2)
{
setfillstyle(SOLID_FILL,0);
bar(332,456,425,472);
outtextxy(335,460,"Local Disc");
}
strcpy(filename,"vacio");
dl.disconnect.request.dir_dest=dl.data.request.dir_dest;
LLC_interface_envios(CMS,UNNUMBERED,DISC,0x01);
}
}
return(1);
}
/*
P R O
G
R
A
M
A
P
R
I
N
C
I
P
A
L */
int main(void)
{
long l;
one_byte *p;
int EMR=1,token_send=0,oldL7=-1,oldtoken=-1;
char buttonhit=0,busctrl=0,CMService=1,sendfile[25],string[25],recorder=0,FILEopen=0;
int CPUMODEL=486,col=21,Localposx,Localposy,aux=0;
int cmd=-1,numplcs=0,plc_adr=0,plc_data,plc_mask;
uint destino=0,destfile=0,divisor;
union REGS inregs,outregs;
FILE *TMP,*ROM;
struct contexto
{
uint dest;
int cmd,adr,emr;
}backup;
/*configuración local de la estación y las comunicaciones,inicialización de variables*/
phy.config.baudrateFE=119200L;
phy.config.baudrateWS=9600L;
cfg=fopen("config.cfg","r");
if(cfg!=NULL)
fscanf(cfg,"%d %d %d %d %d %u %ld
%ld",&aux,&CPUMODEL,&phy.config.port.WS,&phy.config.port.FE
,&WINDOW,&Local_Address,&phy.config.baudrateWS,&phy.config.baudrateFE);
fclose(cfg);
COM_WS=(phy.config.port.WS)?0x2F8:0x3F8;
com_vecWS=(phy.config.port.WS)?0xB:0xC;
divisor=(uint)(115200L/phy.config.baudrateWS);
outportb(COM_WS+3,0x80);
outportb(COM_WS,divisor&255);
outportb(COM_WS+1,divisor>>8);
outportb(COM_WS+3,3);
outportb(COM_WS+1,1);
outportb(COM_WS+4,0x0B);
outportb(COM_WS+6,0);
283
/*configuración de los vectores de interrupción*/
disable();
o_time_vec=getvect(0x1C);
setvect(0x1C,timer0);
o_com_vecWS=getvect(com_vecWS);
setvect(com_vecWS,serial1);
old_mask=inportb(0x21);
outportb(0x21, old_mask & 0xE7);
enable();
inportb(COM_WS);
/*inicialización del modo gráfico*/
inigraf();
rata();
aux=0;
reinicia:
reinicio();
buttonhit=0;
busctrl=0;
FILEopen=0;
EMR=1;
CMService=0;
CPU=CPUMODEL;
showred(0,&Localposx,&Localposy,rotation,numplcs);
/*bucle infinito del programa principal ,termina en caso de encontrar una excepción
grave o de petición del usuario de abandonar el programa*/
while(OFF==0)
{
espera_ack:
if(kbhit())
if(getch()==79)
L7_stat=EXIT;
if(L7_stat==EXIT)
{
if((cmd!=0xF0)&&(cmd!=0xFF))
goto f1;
}
if( heapcheck() == _HEAPCORRUPT )
descarga();
/*NIVEL MAC DE ENTRADA*/
if(MAC_in_level())
{
if(openFILE)
{
strcpy(filename,"vacio");
dl.unitdata.request.dir_dest=dl.unitdata.indication.dir_org;
LLC_interface_envios(CMS,UNNUMBERED,FRMR,0x01);
}
switch(token_stat)
{
case SUCESOR2:
case SUCESOR1:
{
if(token_send>=2)
{
token_send=1;
token_stat=CONFLICTO;
}
}break;
284
case RECLAMO:
{
token_stat=WAIT;
timer_token=TIMEOUT_response;
}break;
case CONTIENDA:
{
token_stat=WAIT;
timer_token=TIMEOUT_response;
}break;
}
}
if(ma.data.request.activa)
goto correos;
/*NIVEL LLC DE ENTRADA*/
if(LLC_in_level())
{
if(openFILE)
{
strcpy(filename,"vacio");
dl.unitdata.request.dir_dest=dl.unitdata.indication.dir_org;
LLC_interface_envios(CMS,UNNUMBERED,FRMR,0x01);
}
}
if(ma.data.request.activa)
goto correos;
/*NIVEL DE APLICACIÓN DE ENTRADA*/
if(L7_in_level(&numplcs,&col,&recorder,EMR))
{
seqrec=oldseq;
strcpy(filename,"vacio");
dl.connection_flowcontrol.request.dir_dest=dl.data.indication.dir_org;
LLC_interface_envios(CMS,SUPERVISORY,REJ,0x00);
}
if(ma.data.request.activa)
goto correos;
/*VISUALIZACIÓN DEL RATÓN*/
putimage(mx,my,raton,XOR_PUT);
inregs.x.ax = 3;
int86(0x33,&inregs,&outregs);
mx=outregs.x.cx;
my=outregs.x.dx;
putimage(mx,my,raton,XOR_PUT);
/*CONTROL DE ESPERAS*/
if((timer_ack0>=0)||(timer_ack1>=0))
goto espera_ack;
else
{
if(ma.data_status.indication.calidad.estado==0x01)
goto reenvia;
}
/*CONTROL DE ESTADO DE LOS BOTONES DEL RATÓN*/
if(mouse_stat(&cmd,&numplcs,plc_adr,&EMR,&recorder,&col,&buttonhit))
showred(0,&Localposx,&Localposy,rotation,numplcs);
/*atención a solicitudes del usuario recibidas via el ratón del programa,recepción de
comando a ejecutar según el botón pulsado y la posición actual del ratón, si pueden
atenderse se inicia el servicio solicitado sino se almacena la petición en el archivo
EPROM.CFG,sólo se permite una petición por cada posesión del testigo*/
mouse_ctrl:
if(cmd!=-1)
285
{
if(pag<2)
{
setfillstyle(SOLID_FILL,0);
bar(332,456,425,472);
outtextxy(335,460,"Local Query");
}
if((L7_stat==REPOSO)&&(rotation>=2)&&(token_stat==TOKENACTV))
{
aux=cmd&15;
switch(cmd&240)
{
case 0x10: aux=aux+16;
case 0x00:
{
destino=(TABLA[aux*2]<<8)|(TABLA[aux*2+1]);
if(destino&&(destino!=Local_Address))
{
pag=1;
showred(0,&Localposx,&Localposy,rotation,numplcs);
cfg=fopen("station.dat","w");
fclose(cfg);
L7_stat=INIUCS;
strcpy(nombre,"ucsplc.txt");
}
}break;
case 0x20:
{
L7_stat=INICMS;
TMP=fopen("history.dat","r");
ROM=fopen("workst.dat","w");
while(!feof(TMP)&&!feof(ROM))
fprintf(ROM,"%c",getc(TMP));
fclose(ROM);
fclose(TMP);
strcpy(nombre,"workst.dat");
}break;
case 0x30:
{
L7_stat=INIACS;
cmd = 7 - aux;
TMP=fopen("acsdo.txt","w");
if(TMP!=NULL)
fprintf(TMP,"%s #%d","command: change value of DO n§" ,(plc_adr<<8)|cmd);
fclose(TMP);
strcpy(nombre,"acsdo.txt");
cmd=0x30;
}break;
case 0x40:
{
L7_stat=INIACS;
cmd = aux+1;
TMP=fopen("acsai.txt","w");
if(TMP!=NULL)
fprintf(TMP,"%s #%d","command: send value of AI n§",(plc_adr<<8)|cmd);
fclose(TMP);
strcpy(nombre,"acsai.txt");
cmd=0x40;
}break;
case 0xa0: aux=aux+16;
case 0x90:{
286
if(aux<numplcs)
{
aux++;
if(pag==1)
{
EMR=1;
pag=2;
}
plc_adr=aux;
microlocal();
putimage(mx,my,raton,XOR_PUT);
fondo(504,365,517,375,7,7);
setcolor(8);
settextstyle(SMALL_FONT,HORIZ_DIR,4);
itoa(EMR,string,10);
outtextxy(506,366,string);
L7_stat=INIACS;
TMP=fopen("acsplc.txt","w");
if(TMP!=NULL)
fprintf(TMP,"%s #%d","command: send data of plc n§",(plc_adr<<8)|EMR);
fclose(TMP);
strcpy(nombre,"acsplc.txt");
setcolor(7);
outtextxy(21,8,"Set Now");
}
}break;
case 0xD0:
{
L7_stat=INIACS;
TMP=fopen("acsmode.txt","w");
if(TMP!=NULL)
fprintf(TMP,"%s #%d","command: change mode of plc n§",plc_adr);
fclose(TMP);
setcolor(10);
outtextxy(535,25,"Listen Mode");
strcpy(nombre,"acsmode.txt");
}break;
case 0xc0:
{
L7_stat=INICMS;
strcpy(nombre,sendfile);
}break;
case 0xb0:
{
L7_stat=INIACS;
strcpy(nombre,"offmode.txt");
}break;
}
if((cmd==0xF0)||(cmd==0xFF))
token_stat=ESCAPE;
if(destino)
{
dl.unitdata.request.dir_dest=destino;
CPU=CPUMODEL;
cfg=fopen("test.cfg","w");
if(cfg!=NULL)
fprintf(cfg,"%d %s",CPU,"cpu test");
fclose(cfg);
}
}
287
else
{
if((cmd!=0xF0)&&(cmd!=0xFF))
{
TMP=fopen("EPROM.cfg","a");
if(TMP!=NULL)
fprintf(TMP,"%x %d %u %d\n",cmd,plc_adr,destino,EMR);
fclose(TMP);
}
}
if((cmd!=0xF0)&&(cmd!=0xFF))
cmd=-1;
}
if(cmd==0xF0)
{
if(!rotation||(token_stat==WAIT))
{
disable();
phy.notify.invoke=1;
enable();
cfg=fopen("input.dep","a");
if(cfg!=NULL)
fprintf(cfg,"\nDisconnect Mode\n");
fclose(cfg);
L7_stat=EXIT;
token_stat=NOTOKEN;
L7_ctrl=L7OFF;
}
}
/*control de los tiempos en espera de respuestas*/
control_ack:
ctrl_ack();
if(ma.data.request.activa)
goto correos;
/*actualización y visualización de los estados del nivel de aplicación y del control del
testigo*/
if((pag<2)&&((oldL7!=L7_stat)||(oldtoken!=token_stat)))
{
setfillstyle(SOLID_FILL,0);
bar(332,426,425,456);
setcolor(7);
settextstyle(DEFAULT_FONT,HORIZ_DIR,1);
outtextxy(335,430,tokennom[token_stat]);
outtextxy(335,445,L7nom[L7_stat&0x1F]);
oldL7=L7_stat;
oldtoken=token_stat;
}
/*NIVEL DE APLICACIÓN DE SALIDA*/
/*control y atención de los estados del nivel de aplicación ,prestando los servicios
solicitados.Antes de ceder el testigo se almacena la operación en curso según su estado
actual en el fichero ROM.CFG. También atención a peticiones del usuario de envio de
documentos de texto desde el editor de textos,almacenadas en el fichero
MESANGER.CFG y visualización de estado en espera por orden remota*/
estado7:
switch(L7_stat)
{
case EXIT:
{
if((cmd==0xF0)&&(token_stat==NOTOKEN))
{
288
closegraf();
system("word.exe");
inigraf();
TMP=fopen("mesanger.cfg","r");
if(TMP!=NULL)
{
fseek(TMP, 0L, SEEK_END);
if(ftell(TMP)>0L)
{
fseek(TMP, 0L, SEEK_SET);
fscanf(TMP,"%s %u\n",&sendfile,&destfile);
fclose(TMP);
if(!strcmp("exit_program",sendfile))
goto f1;
TMP=fopen("EPROM.cfg","a");
if(TMP!=NULL)
fprintf(TMP,"%x %d %u %d\n",0xC0,0,destfile,EMR);
fclose(TMP);
}
}
fclose(TMP);
cmd=-1;
goto reinicia;
}
else
if((cmd==0xFF)&&(token_stat==NOTOKEN))
{
message("Listen Mode",1);
cmd=-1;
goto reinicia;
}
}break;
case CMSRST:
{
L7_stat=CMSI;
dl.data.request.dir_dest= dl.unitdata.indication.dir_org;
}break;
case CMSDISC:
{
L7_stat=REPOSO;
ROM=fopen("ROM.cfg","w");
fclose(ROM);
}break;
case INIUCS:
case INICMS:
case INIACS:
{
if((token_stat==TOKENACTV)&&(rotation>=2))
{
strcpy(filename,"TEST.CFG");
LLC_interface_envios(UCS,TEST,0,0x01);
L7_stat=L7_stat|0x01;
}
}break;
case UCSTEST:
{
if(!ma.data_status.indication.calidad.estado&&(L7_ctrl==L7TEST))
{
L7_ctrl=OFF;
L7_stat=UCSXID;
289
strcpy(filename,"XID.CFG");
dl.unitdata.request.dir_dest=dl.unitdata.indication.dir_org;
LLC_interface_envios(UCS,XID,0,0x01);
}
}break;
case UCSXID:
{
if(!ma.data_status.indication.calidad.estado&&(L7_ctrl==L7XID))
{
L7_ctrl=OFF;
L7_stat=UCSUI;
for(aux=0;nombre[aux]!='\0';aux++)
filename[aux]=nombre[aux];
filename[aux]='\0';
dl.unitdata.request.dir_dest=dl.unitdata.indication.dir_org;
LLC_interface_envios(UCS,UI,0,0x01);
}
}break;
case UCSUI:
L7_stat=REPOSO;
break;
case ACSTEST:
{
if(!ma.data_status.indication.calidad.estado&&(L7_ctrl==L7TEST))
{
L7_ctrl=OFF;
L7_stat=ACSXID;
strcpy(filename,"XID.CFG");
dl.unitdata.request.dir_dest=dl.unitdata.indication.dir_org;
LLC_interface_envios(UCS,XID,0,0x01);
}
}break;
case ACSXID:
{
if(!ma.data_status.indication.calidad.estado&&(L7_ctrl==L7XID))
{
L7_ctrl=OFF;
L7_stat=ACSAC;
for(aux=0;nombre[aux]!='\0';aux++)
filename[aux]=nombre[aux];
filename[aux]='\0';
dl.data_ack.request.dir_dest=dl.unitdata.indication.dir_org;
LLC_interface_envios(ACS,0,0,0x01);
}
}break;
case ACSAC:
{
if(!ma.data_status.indication.calidad.estado&&(L7_ctrl==L7AC))
{
L7_stat=REPOSO;
L7_ctrl=L7OFF;
}
}break;
case CMSTEST:
{
if(!ma.data_status.indication.calidad.estado&&(L7_ctrl==L7TEST))
{
L7_ctrl=OFF;
L7_stat=CMSUA_SABME;
strcpy(filename,"vacio");
290
dl.connect.request.dir_dest=dl.unitdata.indication.dir_org;
LLC_interface_envios(CMS,UNNUMBERED,SABME,0x01);
timer_ack0=TIMEOUT_ack0*2;
if(CPU==486)
timer_ack0=timer_ack0*2;
}
}break;
case CMSABME:
{
L7_stat=CMSXID;
strcpy(filename,"XID.CFG");
dl.unitdata.request.dir_dest=dl.unitdata.indication.dir_org;
LLC_interface_envios(UCS,XID,0,0x01);
}break;
case CMSXID:
{
if(!ma.data_status.indication.calidad.estado&&(L7_ctrl==L7XID))
{
L7_ctrl=OFF;
L7_stat=CMSI;
if(!CMService)
filepos=0L;
timer_ack0=TIMEOUT_ack0;
dl.data.request.dir_dest=dl.unitdata.indication.dir_org;
}
}break;
case CMSREJ:
case CMSI:
{
if(!filepos||(filepos!=endfile))
{
for(aux=0;nombre[aux]!='\0';aux++)
filename[aux]=nombre[aux];
filename[aux]='\0';
ROM=fopen("ROM.cfg","w");
if(ROM!=NULL)
fprintf(ROM,"%d %u %d %u %u %u %ld %ld
%s\n",CPU,dl.unitdata.request.dir_dest,L7_stat,seqsend,
winseq,winXID,filepos,endfile,nombre);
fclose(ROM);
LLC_interface_envios(CMS,INFORMATION,0,0x01);
if(seqrec==winXID)
seqrec=0;
if(L7_stat==CMSREJ)
{
L7_stat=CMSI;
seqrec=0;
}
timer_ack0=TIMEOUT_ack0;
if(CPU==486)
timer_ack0=timer_ack0*2;
if(seqsend==winXID)
{
seqsend=0;
winseq++;
L7_stat=CMSACK;
}
if((filepos&&(filepos==endfile))||(seqsend==winXID))
{
timer_ack0=TIMEOUT_ack0*2;
291
if(CPU==486)
timer_ack0=timer_ack0*2;
}
}
else
if(filepos&&(filepos==endfile))
{
L7_stat=CMSUA_DISC;
filepos=0L;
endfile=0L;
seqsend=0;
winseq=0;
seqrec=0;
oldseq=0;
CMService=0;
CPU=CPUMODEL;
winXID=WINDOW;
RX_BUF_SIZE = 10000/winXID;
MAC_BUF_SIZE=RX_BUF_SIZE;
MAXDATA= RX_BUF_SIZE-40;
strcpy(filename,"vacio");
dl.disconnect.request.dir_dest=dl.data.request.dir_dest;
LLC_interface_envios(CMS,UNNUMBERED,DISC,0x01);
timer_ack0=TIMEOUT_ack0*2;
}
}break;
}
/*control de las tramas de testigo recibidas y actuación según corresponda*/
token_control:
switch(token_ctrl)
{
case sucesor1:
{
if((Local_Address<ma.data.indication.dir_post_org)&&(Local_Address>ma.data.indication.dir_or
g))
{
MAC_token_interface(STABLISH);
busctrl=1;
}
token_ctrl=OFF;
}break;
case sucesor2:
{
MAC_token_interface(STABLISH);
busctrl=1;
token_ctrl=OFF;
}break;
case quiensigue:
{
if(ma.data.indication.dir_post_org==Previous_Address)
{
MAC_token_interface(STABLISH);
busctrl=1;
}
token_ctrl=OFF;
}break;
case contienda:
{
token_stat=CONTIENDA;
token_send=1;
292
token_ctrl=OFF;
timer_token=TIMEOUT_initoken;
}break;
case paso:
{
Previous_Address = ma.data.indication.dir_org;
dl.unitdata.request.dir_dest=Previous_Address;
strcpy(filename,"TEST.CFG");
LLC_interface_envios(UCS,TEST,0,0x00);
L7_ctrl=L7OFF;
filepos=0L;
endfile=0L;
openFILE=0;
seqsend=0;
winseq=0;
seqrec= 0;
oldseq=0;
buttonhit=0;
L7_stat=REPOSO;
token_stat=TOKENACTV;
FILEopen=0;
if(rotation)
timer_token=TIMEOUT_posesion;
else
timer_token=(TIMEOUT_posesion/20);
rotation++;
if(pag<2)
showred(0,&Localposx,&Localposy,rotation,numplcs);
token_ctrl=OFF;
}break;
case escape:
{
if(Next_Address == ma.data.indication.dir_org)
{
if(ma.data.indication.dir_dest!=Global_Address)
{
Next_Address = ma.data.indication.dir_post_org;
showred(ma.data.indication.dir_org,&Localposx,&Localposy,rotation,numplcs);
}
}
if((token_stat==SUCESOR2)||(token_stat==SUCESOR1)||(token_stat==QUIENSIGUE)||(token_
stat==CONFLICTO))
{
if(Next_Address != ma.data.indication.dir_org)
Next_Address = ma.data.indication.dir_org;
token_send=0;
token_stat=PASO;
timer_token=TIMEOUT_initoken;
}
token_ctrl=OFF;
}break;
}
/*control del estado actual en que se encuentra el token ,gestión del token. Restauración
de peticiones de usuario almacenadas en el fichero EPROM.CFG y de acciones en curso
almacenadas sin finalizar en el fichero ROM.CFG*/
token_st:
switch(token_stat)
{
case ESCAPE:
{
293
MAC_token_interface(STABLISH);
showred(Local_Address,&Localposx,&Localposy,rotation,numplcs);
if(cmd==0xF0)
token_stat=PASO;
else
token_stat=NOTOKEN;
token_send=0;
timer_token=0;
L7_stat=EXIT;
}
case WAIT:
case NOTOKEN:
{
FILEopen=0;
if(pag<2)
{
setfillstyle(SOLID_FILL,0);
bar(332,456,425,472);
}
if((timer_token<0)&&(L7_stat!=EXIT))
{
set_adrs=0;
token_send=1;
rotation=0;
token_stat=RECLAMO;
MAC_token_interface(TOKEN_ASK);
busctrl=1;
timer_token=TIMEOUT_initoken;
}
}break;
case RECLAMO:
{
if(timer_token<0)
{
if(!token_send)
{
token_stat=TOKENACTV;
buttonhit=0;
FILEopen=0;
L7_stat=REPOSO;
L7_ctrl=L7OFF;
openFILE=0;
seqsend=0;
winseq=0;
oldseq=0;
seqrec= 0;
filepos=0L;
endfile=0L;
if(rotation)
timer_token=TIMEOUT_posesion;
else
timer_token=(TIMEOUT_posesion/20);
rotation++;
if(pag<2)
showred(0,&Localposx,&Localposy,rotation,numplcs);
}
else
{
MAC_token_interface(TOKEN_ASK);
busctrl=1;
294
timer_token=TIMEOUT_initoken;
token_send--;
}
}
}break;
case TOKENACTV:
{
if(timer_token<0)
{
if(rotation>=2)
{
if(L7_stat==REPOSO)
{
acabando:
ROM=fopen("ROM.cfg","w");
fclose(ROM);
ma.data_status.indication.calidad.estado=0;
winXID=WINDOW;
RX_BUF_SIZE = 10000/winXID;
MAC_BUF_SIZE=RX_BUF_SIZE;
MAXDATA= RX_BUF_SIZE-40;
reenvio=0;
filepos=0L;
endfile=0L;
seqsend=0;
seqrec=0;
winseq=0;
oldseq=0;
rotation=1;
}
else
{
ma.data.request.activa=0;
ma.data_status.indication.calidad.estado=0;
if(ma.data.request.org!=NULL)
{
ma.data.request.sdu=ma.data.request.org;
for(l=0;ma.data.request.sdu!=NULL;l++)
{
p=ma.data.request.sdu->next;
free(ma.data.request.sdu);
ma.data.request.sdu=p;
}
ma.data.request.status=0;
ma.data.request.org=NULL;
}
/*almacena la última operación en curso antes de ceder el testigo*/
if(L7_stat&0x80)
{
ROM=fopen("ROM.cfg","r");
if(ROM!=NULL)
{
fseek(ROM,0L,SEEK_END);
if(ftell(ROM)==0L)
{
fclose(ROM);
ROM=fopen("ROM.cfg","w");
if((ROM!=NULL)&&(L7_stat!=CMSUA_DISC))
295
fprintf(ROM,"%d %u %d %u %u %u %ld %ld
%s\n",CPU,dl.unitdata.request.dir_dest,L7_stat,seqsend,
winseq,winXID,filepos,endfile,nombre);
}
}
fclose(ROM);
L7_stat=REPOSO;
filepos=0L;
endfile=0L;
seqsend=0;
winseq=0;
seqrec=0;
oldseq=0;
winXID=WINDOW;
RX_BUF_SIZE = 10000/winXID;
MAC_BUF_SIZE=RX_BUF_SIZE;
MAXDATA= RX_BUF_SIZE-40;
strcpy(filename,"vacio");
dl.disconnect.request.dir_dest=dl.data.request.dir_dest;
LLC_interface_envios(CMS,UNNUMBERED,DISC,0x01);
rotation=1;
timer_ack0=TIMEOUT_ack0*2;
goto correos;
}
else
if((L7_stat&0x20)||(L7_stat&0x40))
{
ROM=fopen("ROM.cfg","w");
if(ROM!=NULL)
fprintf(ROM,"%d %u %d %u %u %u %ld %ld %s\n",CPU,dl.unitdata.request.dir_dest
,L7_stat,seqsend ,winseq,winXID,filepos,endfile,nombre);
fclose(ROM);
L7_stat=REPOSO;
rotation=1;
}
}
}
if(rotation==1)
{
token_send=0;
if(Local_Address==32)
{
token_stat=SUCESOR2;
if(Next_Address==0x0001)
token_stat=PASO;
}
else
{
if(Next_Address==(Local_Address+1))
token_stat=PASO;
else
if((Next_Address==Local_Address)||(Next_Address>(Local_Address+1)))
token_stat=SUCESOR1;
else
if(Next_Address<(Local_Address))
token_stat=SUCESOR2;
}
}
}
else
296
{
/*restaura última operación en curso sin finalizar*/
if(!FILEopen)
{
FILEopen=1;
ROM=fopen("ROM.cfg","r");
if(ROM!=NULL)
{
fseek(ROM,0L,SEEK_END);
if(ftell(ROM)>0L)
{
fseek(ROM,0L,SEEK_SET);
if(ROM!=NULL)
fscanf(ROM,"%d %u %d %u %u %u %ld %ld %s\n",&CPU,&destino,&L7_stat,&seqsend,
&winseq, &winXID,&filepos,&endfile,nombre);
fclose(ROM);
if(L7_stat!=REPOSO)
{
if(L7_stat&0x80)
{
if(filepos==0L)
{
L7_stat=INICMS;
endfile=0L;
seqsend=0;
winseq=0;
seqrec=0;
oldseq=0;
dl.unitdata.request.dir_dest=destino;
}
else
{
L7_stat=INICMS;
CMService=1;
dl.unitdata.request.dir_dest=destino;
dl.data.request.dir_dest=destino;
}
ma.data_status.indication.calidad.estado=0;
L7_ctrl=L7OFF;
}
else
{
if(L7_stat&0x20)
L7_stat=INIUCS;
else
if(L7_stat&0x40)
L7_stat=INIACS;
dl.unitdata.request.dir_dest=destino;
ma.data_status.indication.calidad.estado=0;
L7_ctrl=L7OFF;
}
}
ROM=fopen("ROM.cfg","w");
}
}
fclose(ROM);
}
/*restaura peticiones solicitadas*/
if((L7_stat==REPOSO)&&(cmd==-1))
{
297
ROM=fopen("EPROM.cfg","r");
TMP=fopen("SRAM.cfg","w");
if((ROM!=NULL)&&(TMP!=NULL))
{
fseek(ROM,0L,SEEK_END);
if(ftell(ROM)>0L)
{
fseek(ROM,0L,SEEK_SET);
aux=0;
while(!feof(ROM)&&!feof(TMP))
{
if(!feof(ROM))
fscanf(ROM,"%x %d %u %d\n",&backup.cmd,&backup.adr,&backup.dest,&backup.emr);
if(!aux)
{
aux=1;
cmd=backup.cmd;
if(backup.adr>0)
plc_adr=backup.adr;
destino=backup.dest;
EMR=backup.emr;
}
else
{
if(!feof(ROM)&&!feof(TMP))
fprintf(TMP,"%x %d %u %d\n",backup.cmd,backup.adr,backup.dest,backup.emr);
}
}
fclose(ROM);
fclose(TMP);
ROM=fopen("EPROM.cfg","w");
TMP=fopen("SRAM.cfg","r");
if((ROM!=NULL)&&(TMP!=NULL))
{
while(!feof(TMP)&&!feof(ROM))
{
aux=getc(TMP);
if(!feof(TMP))
putc(aux,ROM);
}
}
}
}
fclose(TMP);
fclose(ROM);
}
/*desactivación del tiempo de posesión por falta de peticiones por atender*/
if((L7_stat==REPOSO)&&(cmd==-1))
{
timer_token=0;
goto acabando;
}
}
}break;
case SUCESOR1:
{
if((timer_token<0)&&(token_send<2))
{
MAC_token_interface(SUCESS1);
timer_token=TIMEOUT_initoken;
298
token_send++;
}
else
if(token_send>=2)
{
token_stat=PASO;
token_send=0;
}
}break;
case PASO:
{
if(Next_Address==Global_Address)
token_stat=QUIENSIGUE;
else
{
if((timer_token<0)&&(token_send<2))
{
MAC_token_interface(TOKEN_PASS);
set_adrs=1;
timer_token=TIMEOUT_initoken;
token_send++;
}
else
if(token_send>=2)
{
token_send=0;
token_stat=QUIENSIGUE;
if(Next_Address!=Local_Address)
showred(Next_Address,&Localposx,&Localposy,rotation,numplcs);
}
}
}break;
case QUIENSIGUE:
{
if((timer_token<0)&&(token_send<2))
{
MAC_token_interface(WHO_NEXT);
timer_token=TIMEOUT_initoken;
token_send++;
}
else
if(token_send>=2)
{
token_send=0;
token_stat=SUCESOR2;
}
}break;
case SUCESOR2:
{
if((timer_token<0)&&(token_send<2))
{
MAC_token_interface(SUCESS2);
timer_token=TIMEOUT_initoken;
token_send++;
}
else
if(token_send>=2)
{
token_stat=NOTOKEN;
if(L7_stat!=EXIT)
299
L7_stat=REPOSO;
rotation=0;
token_send=0;
timer_token=TIMEOUT_response;
}
}break;
case CONFLICTO:
{
if(timer_token<0)
{
if(!token_send)
{
token_send=0;
token_stat=PASO;
}
else
{
MAC_token_interface(BATTLE);
timer_token=TIMEOUT_initoken*2;
token_send--;
}
}
}break;
case CONTIENDA:
{
if(timer_token<0)
{
if(!token_send)
{
token_stat=NOTOKEN;
L7_stat=REPOSO;
timer_token=TIMEOUT_response;
}
else
{
MAC_token_interface(STABLISH);
busctrl=1;
timer_token=TIMEOUT_initoken;
token_stat=CONTIENDA;
token_send--;
}
}
}break;
}
/*NIVEL LLC DE SALIDA*/
correos:
LLC_out();
if(ma.data_status.indication.activa&&!ma.data_status.indication.calidad.estado)
ma.data_status.indication.activa=0;
/*NIVEL MAC DE SALIDA*/
if(phy.unitdata.request)
{
phy.unitdata.request=0;
if(busctrl)
{
delay((int)(Local_Address)*50);
busctrl=0;
}
if(phy.unitdata.indication)
goto dejaya;
300
reenvia:
phy.notify.invoke=1;
outportb(COM_WS+4,0x08);
ma.data.request.sdu=ma.data.request.org;
for(l=0;ma.data.request.sdu!=NULL;l++)
{
if(!phy.unitdata.indication)
inportb(COM_WS);
else
goto dejaya;
timer_envio=TIMEOUT_envio;
while(!(inportb(COM_WS+5) & 32));
outportb(COM_WS,ma.data.request.sdu->byte);
if( phy.unitdata.indication||(timer_envio<0))
goto dejaya;
ma.data.request.sdu=ma.data.request.sdu->next;
}
dejaya:
while(!(inportb(COM_WS+5) & 32));
phy.notify.invoke=0;
/*Gestión de la trama de salida ,liberación o no del espacio ocupado dependiendo del
servicio prestado sea con o sin reconocimiento*/
if(!ma.data_status.indication.calidad.estado)
{
reenvio=0;
if(timer_ack0<0)
timer_ack0=TIMEOUT_ack0;
if(ma.data.request.org!=NULL)
{
ma.data.request.sdu=ma.data.request.org;
for(l=0;ma.data.request.sdu!=NULL;l++)
{
p=ma.data.request.sdu->next;
free(ma.data.request.sdu);
ma.data.request.sdu=p;
}
ma.data.request.status=0;
ma.data.request.org=NULL;
}
}
else
if(ma.data_status.indication.calidad.estado==0x01)
{
reenvio++;
if(reenvio>=3)
{
reenvio=0;
if(ma.data.request.org!=NULL)
{
ma.data.request.sdu=ma.data.request.org;
for(l=0;ma.data.request.sdu!=NULL;l++)
{
p=ma.data.request.sdu->next;
free(ma.data.request.sdu);
ma.data.request.sdu=p;
}
ma.data.request.status=0;
ma.data.request.org=NULL;
}
dl.disconnect.indication.dir_org=Local_Address;
301
dl.disconnect.indication.motivo = 0x02;
dl.disconnect.indication.activa=1;
ma.data_status.indication.calidad.estado=0x00;
}
else
{
if(timer_ack0<0)
timer_ack0=TIMEOUT_ack0;
}
}
delay(1);
outportb(COM_WS+4,0x0B);
}
FIN
PROGRAMA */
}/*
f1:
/*restaura modo texto ,liberación memoria ocupada y restaura los vectores
interrupción*/
free(raton);
nosound();
p=NULL;
free(p);
disable();
outportb(COM_WS+4,0x0B);
setvect(com_vecWS,o_com_vecWS);
setvect(0x1C,o_time_vec);
outportb(0x21,old_mask);
enable();
closegraf();
return(0);
}
302
de
2.3.1.2 -Diagramas de flujo del programa
-Diagrama de flujo general del programa
303
- Diagrama de flujo del paso de testigo (TOKEN) :
A
B
304
305
306
307
308
LEYENDA :
309
- Diagramas de flujo de los distintos servicios proporcionados por el
programa:
310
311
312
313
314
2.3.2 -Programación Front-End
Este programa ha de ser instalado en los PCs que se empleen como enlace entre los PCs de la
red local y los microcontroladores del bus de campo.Sus principales funciones son:
-Visualización del estado de la red local y del bus de campo al que estén conectados.
-Visualización de los datos principales de la estación.
-Envio de comandos a los Front-End y recepción de las respuestas.
-Envio y recepción de documentos de texto.
-Desconexión remota tanto de Workstations como de Front-Ends.
-Creación de documentos de texto propios para enviarlos a las otras estaciones.
-Visualización de la información recogida de los procesadores locales accedidos.
-Acceso a programa secundario de testeo del bus de campo.
2.3.2.1 -Código de programa en lenguaje Turbo C
Al emplear el mismo código que la anterior versión ,excepto algunas rutinas añadidas para
gestionar el bus de campo,sólo se comentarán dichas rutinas.
#include <alloc.h>
#include <conio.h>
#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
#include <graphics.h>
#include <string.h>
#define TIMEOUT_recibo
#define TIMEOUT_envio
#define TIMEOUT_response
#define TIMEOUT_initoken
#define TIMEOUT_posesion
#define TIMEOUT_ack0
#define TIMEOUT_ack1
#define UNITDATA
#define DATA
#define DATA_ACK
#define ACS
#define CMS
#define UCS
#define UI
#define XID
#define TEST
#define UNNUMBERED
#define SUPERVISORY
#define INFORMATION
#define SABME
#define DISC
#define UASABME
#define UADISC
#define UARST
#define DMSABME
#define DMDISC
1
1
270
36
180
9
81
0x00
0x01
0x02
0x03
0x02
0x01
0x01
0x02
0x03
0x01
0x02
0x03
0x01
0x02
0x03
0x13
0x23
0x04
0x14
315
#define DMRST
#define FRMR
#define RST
#define RR
#define RNR
#define REJ
#define TOKEN_ASK
#define SUCESS1
#define SUCESS2
#define WHO_NEXT
#define BATTLE
#define TOKEN_PASS
#define STABLISH
#define OFF
#define NOTOKEN
#define TOKENACTV
#define WAIT
#define CONFLICTO
#define RECLAMO
#define PASO
#define SUCESOR1
#define SUCESOR2
#define CONTIENDA
#define QUIENSIGUE
#define ESCAPE
#define reclamo
#define paso
#define sucesor1
#define sucesor2
#define contienda
#define quiensigue
#define escape
#define EXIT
#define REPOSO
#define INIUCS
#define UCSTEST
#define UCSXID
#define UCSUI
#define INIACS
#define ACSTEST
#define ACSXID
#define ACSAC
#define INICMS
#define CMSTEST
#define CMSUA_SABME
#define CMSABME
#define CMSXID
#define CMSACK
#define CMSI
#define CMSREJ
#define CMSUA_DISC
#define CMSDISC
#define CMSWAIT
#define CMSUA_RST
#define CMSRST
#define L7OFF
#define L7TEST
#define L7XID
#define L7UI
#define L7AC
0x24
0x05
0x06
0x01
0x02
0x03
0x00
0x01
0x02
0x03
0x04
0x08
0x0C
0
1
2
3
4
5
6
7
8
9
10
11
0x01
0x02
0x03
0x04
0x05
0x06
0x07
0x0
0x1
0x22
0x23
0x24
0x25
0x46
0x47
0x48
0x49
0x8A
0x8B
0x8C
0x8D
0x8E
0x8F
0x90
0x91
0x92
0x93
0x94
0x95
0x96
0x00
0x11
0x12
0x13
0x31
316
void interrupt (*o_com_vecWS)(void);
void interrupt (*o_com_vecFE)(void);
void interrupt (*o_time_vec)(void);
typedef unsigned int uint;
typedef unsigned char uchar;
typedef struct basic_byte
{
uchar byte;
struct basic_byte *next;
}one_byte;
struct UCS_PRMTR_I
{
one_byte *datos,*org;
uchar activa,status;
uint dir_org,
dir_dest;
};
struct UCS_PRMTR_R
{
one_byte *datos,*org;
uchar activa,status;
uint dir_dest;
};
struct UCS_PRMTV
{
struct UCS_PRMTR_I indication;
struct UCS_PRMTR_R request;
};
struct CMS_PRMTR_CNXN_IC
{
uchar activa;
uint dir_org,dir_dest;
};
struct CMS_PRMTR_CNXN_R
{
uchar activa;
uint dir_dest;
};
struct CMS_PRMTR_DATOS_I
{
one_byte *datos,*org;
uchar activa,status;
uint dir_org,dir_dest;
};
struct CMS_PRMTR_DATOS_R
{
one_byte *datos,*org;
uchar activa,status;
uint dir_dest;
};
struct CMS_PRMTR_RST_R
{
uint dir_dest;
uchar activa;
};
struct CMS_PRMTR_RST_C
{
uint dir_org,dir_dest;
uchar activa;
};
317
struct CMS_PRMTR_DSCNXN_IyRST
{
uchar motivo,activa;
uint dir_org,dir_dest;
};
struct CMS_PRMTR_DSCNXN_C
{
uchar motivo,activa;
uint dir_org,dir_dest;
};
struct CMS_PRMTR_DSCNXN_R
{
uchar motivo,activa;
uint dir_dest;
};
struct CMS_PRMTR_CNTRLFLJ_R
{
uint numdatos,dir_dest;
uchar activa;
};
struct CMS_PRMTR_CNTRLFLJ_I
{
uint numdatos,dir_org,dir_dest;
uchar activa;
};
struct CMS_PRMTV_CNXN
{
struct CMS_PRMTR_CNXN_IC indication,confirm;
struct CMS_PRMTR_CNXN_R request;
};
struct CMS_PRMTV_DATOS
{
struct CMS_PRMTR_DATOS_I indication;
struct CMS_PRMTR_DATOS_R request;
};
struct CMS_PRMTV_DSCNXN
{
struct CMS_PRMTR_DSCNXN_R request;
struct CMS_PRMTR_DSCNXN_C confirm;
struct CMS_PRMTR_DSCNXN_IyRST indication;
};
struct CMS_PRMTV_RST
{
struct CMS_PRMTR_RST_R request;
struct CMS_PRMTR_RST_C confirm;
struct CMS_PRMTR_DSCNXN_IyRST indication;
};
struct CMS_PRMTV_CNTRLFLJ
{
struct CMS_PRMTR_CNTRLFLJ_R request;
struct CMS_PRMTR_CNTRLFLJ_I indication;
};
struct ACS_PRMTR_RCNCMNTyRSPST_I
{
one_byte *datos,*org;
uchar activa,status;
uint dir_org,dir_dest;
};
struct ACS_PRMTR_RCNCMNTyRSPST_R
{
318
one_byte *datos,*org;
uchar activa,status;
uint dir_dest;
};
struct ACS_PRMTR_STDRCNCMNT
{
uchar activa,estado;
uint dir_org,dir_dest;
};
struct ACS_PRMTV_RCNCMNTyRSPST
{
struct ACS_PRMTR_RCNCMNTyRSPST_I indication;
struct ACS_PRMTR_RCNCMNTyRSPST_R request;
};
struct ACS_PRMTV_STDRCNCMNT
{
struct ACS_PRMTR_STDRCNCMNT indication;
};
struct LLC_OBJ
{
struct UCS_PRMTV unitdata;
struct CMS_PRMTV_CNXN connect;
struct CMS_PRMTV_DATOS data;
struct CMS_PRMTV_DSCNXN disconnect;
struct CMS_PRMTV_RST reset;
struct CMS_PRMTV_CNTRLFLJ connection_flowcontrol;
struct ACS_PRMTV_RCNCMNTyRSPST data_ack;
struct ACS_PRMTV_STDRCNCMNT data_ack_status;
char servicio;
}dl;
struct PTCN_SBPRMTR_DT
{
uchar tipo;
};
struct PTCN_SBPRMTR_STD_DT
{
uchar tipo,estado;
};
struct PTCN_PRMTR_DT
{
char activa,status;
uint dir_dest;
one_byte *org,*sdu;
struct PTCN_SBPRMTR_DT calidad;
};
struct NDCCN_PRMTR_DT
{
char activa,status;
uint dir_dest,dir_org,dir_post_org,dir_pre_org;
one_byte *org,*sdu;
};
struct NDCCN_PRMTR_STD_DT
{
char activa;
uint dir_dest,dir_org;
struct PTCN_SBPRMTR_STD_DT calidad;
};
struct PRMTV_DT
{
struct PTCN_PRMTR_DT request;
struct NDCCN_PRMTR_DT indication;
};
319
struct PRMTV_STD_DT
{
struct NDCCN_PRMTR_STD_DT indication;
};
struct MAC_OBJ
{
struct PRMTV_DT data;
struct PRMTV_STD_DT data_status;
}ma;
struct PRMTV_NTF
{
uchar invoke;
};
struct PRMTV_UDATA
{
uchar indication,request;
};
struct PRMTR_PORT
{
char FE,WS;
};
struct PRMTV_CNFG
{
struct PRMTR_PORT port;
long baudrateWS,
baudrateFE;
};
struct PHY_OBJ
{
struct PRMTV_NTF notify;
struct PRMTV_CNFG config;
struct PRMTV_UDATA unitdata;
}phy;
uchar HiCRCtab[] = {
0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1, 0x81,
0x40, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0,0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80,
0x41,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,0x81, 0x40, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01,
0xC0,0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,0x01, 0xC0, 0x80, 0x41,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81,
0x40,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0,0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,0x00, 0xC1, 0x81, 0x40,
0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80,
0x41,0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1,
0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01,
0xC0,0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40,0x01, 0xC0, 0x80, 0x41,
0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1,0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80,
0x41,0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0,0x80, 0x41, 0x00, 0xC1,
0x81, 0x40} ;
uchar LoCRCtab[] = {
0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06,0x07, 0xC7, 0x05, 0xC5, 0xC4,
0x04, 0xCC, 0x0C, 0x0D, 0xCD,0x0F, 0xCF, 0xCE, 0x0E, 0x0A, 0xCA, 0xCB, 0x0B, 0xC9,
0x09,0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9, 0x1B, 0xDB, 0xDA, 0x1A,0x1E, 0xDE, 0xDF, 0x1F,
0xDD, 0x1D, 0x1C, 0xDC, 0x14, 0xD4,0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13,
0xD3,0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3,0xF2, 0x32, 0x36, 0xF6,
320
0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4,0x3C, 0xFC, 0xFD, 0x3D, 0xFF, 0x3F, 0x3E, 0xFE, 0xFA,
0x3A,0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38, 0x28, 0xE8, 0xE9, 0x29,0xEB, 0x2B, 0x2A, 0xEA,
0xEE, 0x2E, 0x2F, 0xEF, 0x2D, 0xED,0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6,
0x26,0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60,0x61, 0xA1, 0x63, 0xA3,
0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67,0xA5, 0x65, 0x64, 0xA4, 0x6C, 0xAC, 0xAD, 0x6D, 0xAF,
0x6F,0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB, 0x69, 0xA9, 0xA8, 0x68,0x78, 0xB8, 0xB9, 0x79,
0xBB, 0x7B, 0x7A, 0xBA, 0xBE, 0x7E,0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74,
0x75, 0xB5,0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71,0x70, 0xB0, 0x50,
0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92,0x96, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54,
0x9C, 0x5C,0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E, 0x5A, 0x9A, 0x9B, 0x5B,0x99, 0x59, 0x58,
0x98, 0x88, 0x48, 0x49, 0x89, 0x4B, 0x8B,0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D,
0x4C, 0x8C,0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42,0x43, 0x83, 0x41,
0x81, 0x80, 0x40} ;
char
tokennom[12][15]={"OFF","NOTOKEN","TOKENACTV","WAIT","CONFLICTO","RECLAMO",
"PASO","SUCESOR1","SUCESOR2","CONTIENDA","QUIENSIGUE","ESCAPE"};
char
L7nom[24][15]={"EXIT","REPOSO","INIUCS","UCSTEST","UCSXID","UCSUI","INIACS",
"ACSTEST","ACSXID","ACSAC","INICMS","CMSTEST","CMSUA_SABME","CMSABME",
"CMSXID","CMSACK","CMSI","CMSREJ","CMSUA_DISC","CMSDISC","CMSWAIT","CMSUA_
RST","CMSRST"};
uint reenvio=0,RXB_INDEX=0, RXS_INDEX=0 ,FE_INDEX=0, old_mask, Local_Address =
0x0001,Global_Address = 0xFFFF,Next_Address = 0xFFFF,Previous_Address = 0x0000,
winXID,seqsend=0,seqrec=0,winseq=0,oldseq=0;
uchar RX_BUF[1000],FE_BUF[256], TABLA[65];
int RX_BUF_SIZE= 640,MAC_BUF_SIZE= 640,MAXDATA= 600, WINDOW=16,CPU=1,feplcs=0,pag=0,COM_WS=0x3F8,COM_FE=0x2F8, com_vecWS=0xC,com_vecFE=0xB,
timer_recibo=-1,timer_envio=-1,timer_ack0=-1,timer_ack1=-1,timeout_plc=-1,timer_token=-1,
mx=220,my=220, token_stat=NOTOKEN,L7_stat=REPOSO;
void *raton;
FILE *cfg;
char nomfich[20]="vacio",nombre[20]="vacio",filename[20]="vacio", set_adrs=0, openFILE=0,
L7_ctrl=L7OFF,token_ctrl=OFF,rotation=0, pl_invoke=0;
long endfile=0L;
fpos_t filepos=0L;
void inigraf()
{
int gdriver = DETECT,
gmode,
errorcode;
initgraph(&gdriver, &gmode, "");
errorcode = graphresult();
if (errorcode != grOk)
{
printf("Graphics error: #%s\n", grapherrormsg(errorcode));
getch();
exit(1);
}
}
void closegraf()
{
cleardevice();
delay(250);
closegraph();
321
delay(250);
}
/*rutina ampliada para restaurar los dos vectores de interrupción de los puertos serie*/
void descarga()
{
disable();
outportb(COM_WS+4,0x0B);
if(feplcs)
{
outportb(COM_FE+4,0x0B);
setvect(com_vecFE,o_com_vecFE);
}
setvect(com_vecWS,o_com_vecWS);
setvect(0x1C,o_time_vec);
outportb(0x21,old_mask);
enable();
closegraf();
exit(-1);
}
/*rutina de recepción de caracteres por el puerto serie 2 (habitualmente el de conector de
25 pines ,dirección 2F8) .La habilitación de la recepción depende de si existen o no
microcontroladores conectados al bus (el número de estos se ha de definir al configurar
el programa al inicio, además el usuario puede detener las recepciones mediante la
variable PL_INVOKE ,los datos recibidos se almacenan en una tabla temporal que se
gestiona como una cola*/
void interrupt serial2()
{
uchar inputbyte;
if(feplcs)
{
timeout_plc=9;
if(inportb(COM_FE+5) & (0x1E))
inportb(COM_FE);
else
{
if(pl_invoke)
goto endirq2;
inputbyte=inportb(COM_FE);
FE_BUF[FE_INDEX]=inputbyte;
FE_INDEX++;
if(FE_INDEX==256)
FE_INDEX=0;
}
}
else
o_com_vecFE();
endirq2:
outportb(0x20,0x20);
}
void interrupt serial1()
{
uchar inputbyte;
timer_recibo=TIMEOUT_recibo;
if(inportb(COM_WS+5) & (0x1E))
inportb(COM_WS);
else
{
inputbyte=inportb(COM_WS);
if(phy.notify.invoke)
goto endirq1;
322
if(!phy.unitdata.indication&&(inputbyte==0x7E))
phy.unitdata.indication=1;
RX_BUF[RXB_INDEX]=inputbyte;
RXB_INDEX++;
if(RXB_INDEX==RX_BUF_SIZE)
RXB_INDEX=0;
}
endirq1:
outportb(0x20,0x20);
}
/*rutina ampliada para contemplar un temporizador de las comunicaciones en el bus de
campo*/
void interrupt timer0(void)
{
if(timer_recibo>=0)
timer_recibo--;
if(timeout_plc>=0)
timeout_plc--;
if(timer_envio>=0)
timer_envio--;
if(timer_token>=0)
timer_token--;
if(timer_ack0>=0)
timer_ack0--;
if(timer_ack1>=0)
timer_ack1--;
o_time_vec();
outportb(0x20,0x20);
}
void rata()
{
unsigned int size;
setcolor(15);
rectangle(0,0,10,10);
line(0,0,10,10);
line(10,0,0,10);
size = imagesize(0,0,10,10);
raton = malloc(size);
if(raton==NULL)
descarga();
getimage(0,0,10,10,raton);
}
void fondo(int x1,int y1,int x2,int y2,int c1,int c2)
{
setfillstyle(SOLID_FILL,c1);
bar(x1,y1,x2,y2);
setcolor(c2);
rectangle(x1,y1,x2,y2);
}
/*rutina adaptada a esta versión contempla la posibilidad de acceso al programa de
apoyo OSCILOS.EXE*/
void pantalla(int part)
{
int i;
setpalette(3,32);
fondo(0,0,639,479,3,3);
for(i=0;i<=1;i++)
{
setcolor(3+i*3);
rectangle(610+i,455+i,620+i,465+i);
323
if(!part)
rectangle(10+i,455+i,20+i,465+i);
setcolor(6-i*3);
setfillstyle(SOLID_FILL,6-i*3);
bar(30+i,7+i,610+i,9+i);
bar(580+i,10+i,580+i,56+i);
bar(30+i,57+i,610+i,59+i);
settextstyle(DEFAULT_FONT,HORIZ_DIR,1);
if(!part)
{
outtextxy(550+i,450+i,"Station");
outtextxy(550+i,460+i,"Access");
outtextxy(30+i,450+i,"Modbus");
outtextxy(30+i,460+i,"Control");
}
else
{
outtextxy(550+i,450+i,"Listen");
outtextxy(550+i,460+i,"Mode");
}
bar(30+i,317+i,610+i,319+i);
bar(580+i,320+i,580+i,366+i);
bar(30+i,367+i,610+i,369+i);
rectangle(200-i,420-i,430-i,476-i);
settextstyle(TRIPLEX_FONT,HORIZ_DIR,1);
outtextxy(600+i,20+i,"LAN");
if(part)
outtextxy(600+i,330+i,"BUS");
settextstyle(DEFAULT_FONT,HORIZ_DIR,1);
outtextxy(205-i,430-i,"Token Status");
outtextxy(205-i,445-i,"Level7 Status");
outtextxy(205-i,460-i,"Control Message");
outtextxy(210-i,410-i,"Control / Status Window");
fondo(330+i,425+i,425+i,472+i,0,7+i);
}
}
char message(char string[],int espera)
{
int i;
fondo(80,150,300,250,7,7);
settextstyle(TRIPLEX_FONT,HORIZ_DIR,2);
setcolor(4);
rectangle(85,155,295,245);
outtextxy(125-(strlen(string)*2),180,string);
settextstyle(TRIPLEX_FONT,HORIZ_DIR,5);
outtextxy(255,170,"!");
for(i=0;i<=4;i++)
{
line(257,168,277+i,210+i);
line(257,168,237-i,210+i);
line(237-i,210+i,277+i,210+i);
}
if(espera)
{
switch(getch())
{
case 'y':
case 13:
case 'Y':return(1);
case 'n':
324
case 'N':
case 27:
default: return(0);
}
}
settextstyle(SMALL_FONT,HORIZ_DIR,4);
return(0);
}
/*rutina nueva para mostrar una pantalla que visualice los principales datos almacenados
en la SRAM del microcontrolador*/
void SRAM()
{
int i,j;
fondo(0,0,639,479,8,8);
for(i=0;i<2;i++)
fondo(20+i*5,10+i*2,233-i*5,459-i*10,7-i*7,i*15);
for(j=0;j<=420;j=j+30)
{
fondo(12,25+j,20,30+j,7,0);
fondo(243,25+j,233,30+j,7,0);
}
for(j=0;j<2;j++)
{
setcolor(7+j);
settextstyle(TRIPLEX_FONT,HORIZ_DIR,2);
outtextxy(400+j,100+j,"SRAM 65256");
outtextxy(410+j,130+j,"64 Kbytes");
settextstyle(TRIPLEX_FONT,HORIZ_DIR,1);
outtextxy(250+j,200+j,"Modbus");
outtextxy(250+j,220+j,"Control Area");
outtextxy(250+j,300+j,"Modbus");
outtextxy(250+j,320+j,"Status Area");
}
setcolor(8);
for(j=192;j<=224;j=j+16)
for(i=0;i<=200;i=i+25)
rectangle(27,13+j,27+i,29+j);
for(j=288;j<320;j=j+16)
for(i=0;i<=200;i=i+25)
rectangle(27,13+j,27+i,29+j);
settextstyle(SANS_SERIF_FONT,HORIZ_DIR,1);
for(j=0;j<=1;j++)
{
setcolor(7+j);
outtextxy(560+j,440+j,"Set Now");
rectangle(600+j,465+j,610+j,475+j);
}
}
void doc(char nom[],int op)
{
char str[2];
int ncar=0,nlin=0,px=0,py=0;
FILE *f;
f=fopen(nom,"r");
if(f!=NULL)
{
if(op!=2)
{
setfillstyle(SOLID_FILL,7);
bar(406,211,634,359);
325
px=406;
py=211;
setcolor(8);
settextstyle(SMALL_FONT,HORIZ_DIR,4);
}
else
{
setfillstyle(SOLID_FILL,3);
bar(30,110,300,315);
px=30;
py=110;
setcolor(6);
settextstyle(DEFAULT_FONT,HORIZ_DIR,1);
}
ncar=0;
nlin=0;
while(!feof(f))
{
str[0]=getc(f);
str[1]='\0';
if((op!=2)&&(ncar>=230))
{
nlin=nlin+8;
ncar=0;
if(nlin==168)
goto fin2;
outtextxy(px+ncar,py+nlin,str);
}
if((op==2)&&(str[0]=='\n'))
{
nlin=nlin+10;
ncar=0;
}
if(!feof(f)&&(str[0]!='\n'))
{
outtextxy(px+ncar,py+nlin,str);
ncar=ncar+8;
}
}
}
fin2:
fclose(f);
}
/*rutina modificada para resaltar la leyenda de la SRAM para que el usuario sepa que
puede acceder a dicha información*/
void microlocal()
{
int i,j,k=0;
int cpu[14];
int zocal[14];
char pattern[8] = {0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55};
fondo(0,0,639,479,7,7);
settextstyle(SMALL_FONT,HORIZ_DIR,4);
for(i=0;i<2;i++)
{
setcolor(8-i);
rectangle(5+i,5+i,15+i,15+i);
outtextxy(20+i,7+i,"Set NOW");
}
setpalette(5,24);
326
setfillpattern(pattern,5); /*placa base*/
bar(50,30,394,478);
setfillstyle(SOLID_FILL,9);
/*DB-9 RS232C*/
bar(50,230,62,234);
bar(50,250,62,254);
bar(50,270,62,274);
bar(50,366,62,370);
bar(50,386,62,390);
bar(50,406,62,410);
bar(25,220,50,280);
bar(25,356,50,420);
for(j=0;j<=90*2;j=j+90)
/*puertos 1,3,7*/
{
setcolor(0);
setfillstyle(SOLID_FILL,8); /*conector 10pines*/
bar(112+j,32,200+j,72);
bar(392,74+j,352,162+j);
setfillstyle(SOLID_FILL,7);
bar(116+j,36,196+j,68);
bar(388,78+j,356,158+j);
setcolor(8);
setfillstyle(SOLID_FILL,8);
for(i=0;i<=4*12;i=i+12)
{
circle(136+i+j,46,4); /*pines*/
floodfill(136+i+j,46,8);
circle(136+i+j,58,4);
floodfill(136+i+j,58,8);
circle(365,98+i+j,4);
floodfill(365,98+i+j,8);
circle(378,98+i+j,4);
floodfill(378,98+i+j,8);
}
k++;
}
/*conector 10pines*/
setfillstyle(SOLID_FILL,8);
bar(392,74+j,352,162+j);
setfillstyle(SOLID_FILL,7);
bar(388,78+j,356,158+j);
setcolor(8);
/*pines del 10*/
setfillstyle(SOLID_FILL,8);
for(i=0;i<=4*12;i=i+12)
{
circle(378,98+j+i,4);
floodfill(378,98+j+i,8);
circle(364,98+i+j,4);
floodfill(364,98+i+j,8);
}
/*conector 26 pines */
bar(168,438,348,478);
setfillstyle(SOLID_FILL,7);
bar(172,442,344,474);
/*conector 14 pines*/
bar(84,450,164,470);
setfillstyle(SOLID_FILL,8);
/*pines del 26*/
for(i=0;i<=12*12;i=i+12)
{
327
circle(192+i,450,4);
floodfill(192+i,450,8);
circle(192+i,466,4);
floodfill(192+i,466,8);
}
for(i=0;i<=6*12;i=i+12) /*pines del 14*/
{
circle(88+i,466,4);
floodfill(88+i,466,8);
circle(88+i,454,4);
floodfill(88+i,454,8);
}
setcolor(0);
zocal[0]=206;
/*zocalo cpu 80c537 */
zocal[1]=78;
zocal[2]=206;
zocal[3]=210;
zocal[4]=214;
zocal[5]=218;
zocal[6]=350;
zocal[7]=218;
zocal[8]=350;
zocal[9]=86;
zocal[10]=342;
zocal[11]=78;
zocal[12]=zocal[0];
zocal[13]=zocal[1];
setfillstyle(SOLID_FILL,8);
fillpoly(7, zocal);
for(i=0;i<=6*28;i=i+28)
{
setcolor(11);
setfillstyle(SOLID_FILL,11); /* Condensadores electroliticos*/
circle(150,98+i,13);
floodfill(150,98+i,11);
setcolor(7);
setfillstyle(SOLID_FILL,7); /* Condensadores electroliticos*/
circle(150,98+i,11);
floodfill(150,98+i,7);
}
setfillstyle(SOLID_FILL,8);
bar(390,474,354,434); /* conector Vcc*/
setcolor(7);
setfillstyle(SOLID_FILL,7);
circle(372,444,6);
floodfill(372,444,7);
circle(372,464,6);
floodfill(372,464,7);
setcolor(0);
line(366,464,378,464);
line(366,444,378,444);
cpu[0]=226;
/*cpu 80c537 */
cpu[1]=98;
cpu[2]=226;
cpu[3]=190;
cpu[4]=234;
cpu[5]=198;
cpu[6]=330;
cpu[7]=198;
cpu[8]=330;
328
cpu[9]=106;
cpu[10]=322;
cpu[11]=98;
cpu[12]=cpu[0];
cpu[13]=cpu[1];
setfillstyle(SOLID_FILL,0);
fillpoly(7, cpu);
setcolor(4);
setfillstyle(SOLID_FILL,4); /*led */
circle(96,50,10);
floodfill(96,50,4);
setcolor(12);
setfillstyle(SOLID_FILL,12);
circle(96,50,8);
floodfill(96,50,12);
setfillstyle(SOLID_FILL,14); /*reset clk*/
bar(105,81,127,104);
setfillstyle(SOLID_FILL,15); /*reset*/
bar(58,82,80,104);
setcolor(15);
setfillstyle(SOLID_FILL,8);
settextstyle(SMALL_FONT,VERT_DIR,4);
outtextxy(270,118,"CPU SIEMENS");
outtextxy(280,118,"SAB 80C537");
outtextxy(35,225,"RS232C/1");
outtextxy(35,365,"RS232C/0");
settextstyle(SMALL_FONT,HORIZ_DIR,4);
bar(294,262,198,238); /*DEMULTIPLEXOR 74HCT573*/
bar(294,262,298,254);
bar(294,238,298,246);
outtextxy(215,245,"74HCT573");
bar(298,342,162,286); /*SRAM 65256*/
bar(158,286,162,302);
bar(158,342,162,322);
setcolor(10);
outtextxy(195,310,"SRAM 65256");
setcolor(15);
bar(298,422,162,366); /*EPROM 27C256*/
bar(158,366,162,386);
bar(158,422,162,402);
outtextxy(195,394,"EPROM 27C256");
settextstyle(SMALL_FONT,VERT_DIR,4);
bar(110,266,118,262);
/*SELECCION MEMORIA 74HCT00*/
bar(122,266,130,262);
bar(110,266,130,326);
outtextxy(115,274,"74HCT00");
bar(110,166,118,170);
/*MAX232*/
bar(122,166,130,170);
bar(110,246,130,170);
outtextxy(115,188,"MAX 232");
bar(110,154,118,150);
/*LT485*/
bar(122,154,130,150);
bar(110,122,130,150);
outtextxy(115,125,"485");
bar(110,358,118,362);
/*PHANTOM WATCH*/
bar(122,358,130,362);
bar(110,438,130,362);
outtextxy(115,370,"PHANTOM");
bar(54,138,90,182);
/*conector RS-485*/
329
setcolor(7);
setfillstyle(SOLID_FILL,7);
circle(72,149,6);
floodfill(72,149,7);
circle(72,171,6);
floodfill(72,171,7);
setcolor(0);
line(66,149,78,149);
line(66,171,78,171);
setcolor(0);
setfillstyle(SOLID_FILL,15);
bar(174,154,190,194); /* conector Cristal cuarzo*/
outtextxy(177,156,"12 MHz");
setcolor(0);
outtextxy(408,116,">");
outtextxy(433,116,">");
outtextxy(458,116,">");
outtextxy(483,116,">");
outtextxy(508,116,">");
outtextxy(533,116,">");
outtextxy(558,116,">");
outtextxy(583,116,">");
setcolor(0);
rectangle(615,25,625,35);
setcolor(8);
rectangle(615-1,25,625+3,35+2);
for(j=0;j<2;j++)
{
setcolor(8-j);
settextstyle(SMALL_FONT,HORIZ_DIR,4);
outtextxy(415+j,25-j,"ID :");
outtextxy(465+j,25-j,"ADR :");
outtextxy(535+j,25-j,"Listen Mode :");
outtextxy(415+j,155-j,"_Status Relays_");
outtextxy(415+j,165+j,"Man/Auto");
outtextxy(415+j,175-j,"Bypass");
outtextxy(415+j,185-j,"Alarm");
outtextxy(415+j,55-j,"Bit");
outtextxy(415+j,70-j,"DI");
outtextxy(415+j,85-j,"DO");
line(438+j,55+j,438+j,95+j);
line(448+j,50+j,448+j,95+j);
line(458+j,50+j,458+j,95+j);
line(468+j,50+j,468+j,95+j);
line(478+j,50+j,478+j,95+j);
line(488+j,50+j,488+j,95+j);
line(498+j,50+j,498+j,95+j);
line(508+j,50+j,508+j,95+j);
outtextxy(440+j,55+j,"1");
outtextxy(450+j,55+j,"2");
outtextxy(460+j,55+j,"3");
outtextxy(470+j,55+j,"4");
outtextxy(480+j,55+j,"5");
outtextxy(490+j,55+j,"6");
outtextxy(500+j,55+j,"7");
outtextxy(510+j,55+j,"8");
outtextxy(615+j,128-j,"AI");
outtextxy(421+j,115+j,"1");
outtextxy(446+j,115+j,"2");
outtextxy(471+j,115+j,"3");
330
outtextxy(494+j,115+j,"4");
outtextxy(521+j,115+j,"5");
outtextxy(546+j,115+j,"6");
outtextxy(571+j,115+j,"7");
outtextxy(596+j,115+j,"8");
for(i=0;i<=200;i=i+25)
line(408+i+j,125+j,408+i+j,140+j);
for(i=0;i<=30;i=i+15)
line(415+j,65+i+j,520+j,65+i+j);
line(408+j,125+j,608+j,125+j);
line(408+j,140+j,608+j,140+j);
outtextxy(445+j,200-j,"Extended Memory Registers");
rectangle(405+j,200+j,635+j,380+j);
line(415+j,200+j,415+j,210+j);
line(625+j,200+j,625+j,210+j);
line(405+j,210+j,635+j,210+j);
line(405+j,360+j,635+j,360+j);
outtextxy(410+j,365-j,"E.M.R. number: #");
outtextxy(630+j,200+j,">");
outtextxy(415+j,385-j,"ROM
Kb");
outtextxy(415+j,395-j,"RAM
Kb");
outtextxy(415+j,405-j,"Software Version .0");
outtextxy(415+j,415-j,"Bus Type");
outtextxy(415+j,425-j,"Baudrate");
outtextxy(415+j,435-j,"Frames received");
outtextxy(415+j,445-j,"Frames transmited");
outtextxy(415+j,455-j,"Frames accepted");
}
}
uchar valores()
{
int i,c_aux2,c_aux1;
char string[15];
FILE *TMP,*cfg;
TMP=fopen("plcfile.dat","r");
i=0;
c_aux2=0;
if(TMP!=NULL)
{
settextstyle(SMALL_FONT,HORIZ_DIR,4);
setcolor(8);
while(!feof(TMP))
{
c_aux1=getc(TMP);
if(c_aux1!='\n')
string[i++]=c_aux1;
else
{
string[i++]='\0';
if(i>4)
goto fallo;
if(c_aux2==13)
{
i=(atoi(string)-1)*4800;
itoa(i,string,10);
}
i=0;
switch(c_aux2)
{
case 0: outtextxy(495,25,string);break;
331
case 1: outtextxy(619,25,string);break;
case 2: outtextxy(500,165,string);break;
case 3: outtextxy(500,175,string);break;
case 4: outtextxy(500,185,string);break;
case 5: outtextxy(520,435,string);break;
case 6: outtextxy(520,445,string);break;
case 7: outtextxy(520,455,string);break;
case 8: outtextxy(520,395,string);break;
case 9: outtextxy(520,385,string);break;
case 10: outtextxy(440,25,string);break;
case 11: outtextxy(520,405,string);break;
case 12: outtextxy(520,415,string);break;
case 13: outtextxy(520,425,string);break;
case 14: outtextxy(413,128,string);break;
case 15: outtextxy(437,128,string);break;
case 16: outtextxy(462,128,string);break;
case 17: outtextxy(487,128,string);break;
case 18: outtextxy(512,128,string);break;
case 19: outtextxy(537,128,string);break;
case 20: outtextxy(563,128,string);break;
case 21: outtextxy(587,128,string);break;
case 22: outtextxy(440,68,string);break;
case 23: outtextxy(450,68,string);break;
case 24: outtextxy(460,68,string);break;
case 25: outtextxy(470,68,string);break;
case 26: outtextxy(480,68,string);break;
case 27: outtextxy(490,68,string);break;
case 28: outtextxy(500,68,string);break;
case 29: outtextxy(510,68,string);break;
case 30: outtextxy(440,83,string);break;
case 31: outtextxy(450,83,string);break;
case 32: outtextxy(460,83,string);break;
case 33: outtextxy(470,83,string);break;
case 34: outtextxy(480,83,string);break;
case 35: outtextxy(490,83,string);break;
case 36: outtextxy(500,83,string);break;
case 37: outtextxy(510,83,string);break;
}
c_aux2++;
if(c_aux2==38)
goto acaba;
}
}
}
goto fallo;
acaba:
cfg=fopen("ram.img","w");
if(cfg!=NULL)
{
c_aux1=0;
while(!feof(cfg)&&!feof(TMP))
{
c_aux1=getc(TMP);
if(!feof(TMP))
putc(c_aux1,cfg);
}
}
fclose(cfg);
fclose(TMP);
doc("ram.img",1);
332
return(0);
fallo:
fclose(TMP);
cfg=fopen("ram.img","w");
fclose(cfg);
return(1);
}
void PDU_dinamica(uchar etapa,uchar tipo,uchar dato)
{
if(etapa==0x00)
{
switch(tipo)
{
case UNITDATA:
{
if( (dl.unitdata.request.datos= malloc(sizeof(one_byte)))==NULL)
descarga();
dl.unitdata.request.status=1;
dl.unitdata.request.org=dl.unitdata.request.datos;
dl.unitdata.request.datos->byte=dato;
dl.unitdata.request.datos->next=NULL;
}break;
case DATA:
{
if((dl.data.request.datos= malloc(sizeof(one_byte)))==NULL)
descarga();
dl.data.request.status=1;
dl.data.request.org=dl.data.request.datos;
dl.data.request.datos->byte=dato;
dl.data.request.datos->next=NULL;
}break;
case DATA_ACK:
{
if((dl.data_ack.request.datos= malloc(sizeof(one_byte)))==NULL)
descarga();
dl.data_ack.request.status=1;
dl.data_ack.request.org=dl.data_ack.request.datos;
dl.data_ack.request.datos->byte=dato;
dl.data_ack.request.datos->next=NULL;
}break;
}
}
else
{
switch(tipo)
{
case UNITDATA:
{
if((dl.unitdata.request.datos->next= malloc(sizeof(one_byte)))==NULL)
descarga();
dl.unitdata.request.datos=dl.unitdata.request.datos->next;
dl.unitdata.request.datos->byte=dato;
dl.unitdata.request.datos->next=NULL;
}break;
case DATA:
{
if((dl.data.request.datos->next= malloc(sizeof(one_byte)))==NULL)
descarga();
dl.data.request.datos=dl.data.request.datos->next;
dl.data.request.datos->byte=dato;
333
dl.data.request.datos->next=NULL;
}break;
case DATA_ACK:
{
if((dl.data_ack.request.datos->next= malloc(sizeof(one_byte)))==NULL)
descarga();
dl.data_ack.request.datos=dl.data_ack.request.datos->next;
dl.data_ack.request.datos->byte=dato;
dl.data_ack.request.datos->next=NULL;
}break;
}
}
}
void LLC_dinamica(uchar etapa,uchar dato)
{
if(etapa==0x00)
{
if((ma.data.request.sdu= malloc(sizeof(one_byte)))==NULL)
descarga();
ma.data.request.status=1;
ma.data.request.org=ma.data.request.sdu;
ma.data.request.sdu->byte=dato;
ma.data.request.sdu->next=NULL;
}
else
{
if((ma.data.request.sdu->next= malloc(sizeof(one_byte)))==NULL)
descarga();
ma.data.request.sdu=ma.data.request.sdu->next;
ma.data.request.sdu->byte=dato;
ma.data.request.sdu->next=NULL;
}
}
uchar download_fichero(uchar tipo)
{
uchar car_tmp=0;
long l=0L;
one_byte *p;
char string[25];
int i,nbytes=0;
FILE *txt;
txt=fopen(filename,"r");
if(txt!=NULL)
{
fseek(txt, 0L, SEEK_END);
endfile = ftell(txt);
fseek(txt, 0L, SEEK_SET);
if(tipo==DATA)
{
if(filepos==0L)
{
seqsend=0;
winseq=0;
for(i=0;filename[i]!='\0';i++)
{
if(!i)
PDU_dinamica(0x00,tipo,filename[i]);
else
PDU_dinamica(0x01,tipo,filename[i]);
}
334
PDU_dinamica(0x01,tipo,0xFF);
ltoa(endfile,string,10);
for(i=0;string[i]!='\0';i++)
{
car_tmp=(uchar)(string[i]);
PDU_dinamica(0x01,tipo,car_tmp);
}
PDU_dinamica(0x01,tipo,0xFF);
}
else
{
if (fsetpos(txt, &filepos)!=0)
descarga();
}
}
nbytes=0;
while(!feof(txt))
{
car_tmp=(uchar)(getc(txt));
if(!feof(txt))
{
if(!nbytes)
{
if(tipo==DATA)
{
if(filepos==0L)
PDU_dinamica(0x01,tipo,car_tmp);
else
PDU_dinamica(0x00,tipo,car_tmp);
}
else
PDU_dinamica(0x00,tipo,car_tmp);
}
else
PDU_dinamica(0x01,tipo,car_tmp);
nbytes++;
if((nbytes>64)&&(tipo!=DATA))
goto end_file;
if((nbytes>=MAXDATA)&&(tipo==DATA))
{
fgetpos(txt,&filepos);
seqsend++;
fclose(txt);
if(filepos==endfile)
PDU_dinamica(0x01,tipo,0xFF);
return(0);
}
}
}
if(tipo==DATA)
{
seqsend++;
fgetpos(txt, &filepos);
PDU_dinamica(0x01,tipo,0xFF);
}
fclose(txt);
return(0);
}
else
{
335
fclose(txt);
L7_stat=REPOSO;
dl.disconnect.indication.dir_org=Local_Address;
dl.disconnect.indication.motivo=0x01;
dl.disconnect.indication.activa=1;
if(pag<2)
{
setfillstyle(SOLID_FILL,0);
bar(332,456,425,472);
outtextxy(335,460,"Empty File");
}
return(1);
}
end_file:
fclose(txt);
L7_stat=REPOSO;
dl.disconnect.indication.dir_org=Local_Address;
dl.disconnect.indication.motivo=0x05;
dl.disconnect.indication.activa=1;
if(pag<2)
{
setfillstyle(SOLID_FILL,0);
bar(332,456,425,472);
outtextxy(335,460,"File Disc");
}
switch(tipo)
{
case UNITDATA:
{
if(dl.unitdata.request.org!=NULL)
{
dl.unitdata.request.datos=dl.unitdata.request.org;
for(l=0;dl.unitdata.request.datos!=NULL;l++)
{
p=dl.unitdata.request.datos->next;
free(dl.unitdata.request.datos);
dl.unitdata.request.datos=p;
}
dl.unitdata.request.status=0;
dl.unitdata.request.org=NULL;
}
}break;
case DATA:
{
if(dl.data.request.org!=NULL)
{
dl.data.request.datos=dl.data.request.org;
for(l=0;dl.data.request.datos!=NULL;l++)
{ p=dl.data.request.datos->next;
free(dl.data.request.datos);
dl.data.request.datos=p;
}
dl.data.request.status=0;
dl.data.request.org=NULL;
}
}break;
case DATA_ACK:
{
if(dl.data_ack.request.org!=NULL)
{
336
dl.data_ack.request.datos=dl.data_ack.request.org;
for(l=0;dl.data_ack.request.datos!=NULL;l++)
{
p=dl.data_ack.request.datos->next;
free(dl.data_ack.request.datos);
dl.data_ack.request.datos=p;
}
dl.data_ack.request.status=0;
dl.data_ack.request.org=NULL;
}
}break;
}
p=NULL;
free(p);
return(1);
}
void dinamic_LLC(uchar etapa,uchar tipo,uchar dato)
{
if(etapa==0x00)
{
switch(tipo)
{
case UNITDATA:
{
if ( (dl.unitdata.indication.datos= (malloc(sizeof(one_byte))) )==NULL)
descarga();
dl.unitdata.indication.status=1;
dl.unitdata.indication.org=dl.unitdata.indication.datos;
dl.unitdata.indication.datos->byte=dato;
dl.unitdata.indication.datos->next=NULL;
}break;
case DATA:
{
if ( (dl.data.indication.datos= (malloc(sizeof(one_byte))) )==NULL)
descarga();
dl.data.indication.status=1;
dl.data.indication.org=dl.data.indication.datos;
dl.data.indication.datos->byte=dato;
dl.data.indication.datos->next=NULL;
}break;
case DATA_ACK:
{
if ( (dl.data_ack.indication.datos= (malloc(sizeof(one_byte))) )==NULL)
descarga();
dl.data_ack.indication.status=1;
dl.data_ack.indication.org=dl.data_ack.indication.datos;
dl.data_ack.indication.datos->byte=dato;
dl.data_ack.indication.datos->next=NULL;
}break;
}
}
else
{
switch(tipo)
{
case UNITDATA:
{
if((dl.unitdata.indication.datos->next= (malloc(sizeof(one_byte))) )==NULL)
descarga();
dl.unitdata.indication.datos=dl.unitdata.indication.datos->next;
337
dl.unitdata.indication.datos->byte=dato;
dl.unitdata.indication.datos->next=NULL;
}break;
case DATA:
{
if((dl.data.indication.datos->next= (malloc(sizeof(one_byte))) )==NULL)
descarga();
dl.data.indication.datos=dl.data.indication.datos->next;
dl.data.indication.datos->byte=dato;
dl.data.indication.datos->next=NULL;
}break;
case DATA_ACK:
{
if((dl.data_ack.indication.datos->next= malloc(sizeof(one_byte)))==NULL)
descarga();
dl.data_ack.indication.datos=dl.data_ack.indication.datos->next;
dl.data_ack.indication.datos->byte=dato;
dl.data_ack.indication.datos->next=NULL;
}break;
}
}
}
void cola()
{
uchar HiCRC = 0xFF,LoCRC = 0xFF;
uint IndexCRC;
long l;
ma.data.request.sdu=ma.data.request.org;
ma.data.request.sdu=ma.data.request.sdu->next;
ma.data.request.sdu=ma.data.request.sdu->next;
while (ma.data.request.sdu!=NULL)
{
IndexCRC = HiCRC ^ (ma.data.request.sdu->byte);
ma.data.request.sdu=ma.data.request.sdu->next;
HiCRC = LoCRC ^ HiCRCtab[IndexCRC];
LoCRC = LoCRCtab[IndexCRC];
}
ma.data.request.sdu=ma.data.request.org;
for (l=0;ma.data.request.sdu->next!=NULL;l++)
ma.data.request.sdu=ma.data.request.sdu->next;
LLC_dinamica(0x01,HiCRC);
LLC_dinamica(0x01,LoCRC);
LLC_dinamica(0x01,0xD8);
ma.data.request.sdu=ma.data.request.org;
}
uchar MAC_token_interface(uchar func)
{
uint index;
int i;
uchar dir_tmp;
if(phy.unitdata.request)
{
if(pag<2)
outtextxy(335,460,"MAC oV");
return(1);
}
switch(func)
{
case TOKEN_PASS:ma.data.request.dir_dest=Next_Address;break;
case STABLISH:{
338
if(token_stat==ESCAPE)
ma.data.request.dir_dest=Previous_Address;
else
ma.data.request.dir_dest=Global_Address;
}break;
default:ma.data.request.dir_dest=Global_Address;break;
}
LLC_dinamica(0x00,0x7E);
LLC_dinamica(0x01,0xD8);
LLC_dinamica(0x01,func);
dir_tmp = (uchar)((ma.data.request.dir_dest)>>8);
LLC_dinamica(0x01,dir_tmp);
dir_tmp= (uchar)( (ma.data.request.dir_dest)&0xFF);
LLC_dinamica(0x01,dir_tmp);
dir_tmp = (uchar)((Local_Address)>>8);
LLC_dinamica(0x01,dir_tmp);
dir_tmp =(uchar)( (Local_Address)&0xFF);
LLC_dinamica(0x01,dir_tmp);
if(func==TOKEN_PASS)
{
LLC_dinamica(0x01,(uchar)(Previous_Address>>8));
LLC_dinamica(0x01,(uchar)(Previous_Address&0xFF));
}
else
{
LLC_dinamica(0x01,(uchar)(Next_Address>>8));
LLC_dinamica(0x01,(uchar)(Next_Address&0xFF));
}
if((func==TOKEN_ASK)||(func==STABLISH))
{
for(index=0;index<=63;index++)
LLC_dinamica(0x01,0x7e);
}
else
if(func==TOKEN_PASS)
{
for (i=0;i<=63;i++)
LLC_dinamica(0x01,TABLA[i]);
}
cola();
phy.unitdata.request=1;
return(0);
}
uchar LLC_interface_envios (char service,char tipo,char opcion,char resp)
{
uchar field_ctrl1=0x00,field_ctrl2=0x00;
one_byte *p;
char emptyfile=1;
long index=0;
uchar dir_tmp;
if(ma.data.request.activa)
{
if(pag<2)
outtextxy(335,460,"LLC oV");
return(1);
}
ma.data.request.activa=0;
if(!strcmp(filename,"vacio"))
goto sigueme;
switch(service)
339
{
case UCS:
{
if(download_fichero(UNITDATA))
return(1);
}break;
case CMS:
{
if(download_fichero(DATA))
return(1);
}break;
case ACS:
{
if(download_fichero(DATA_ACK))
return(1);
}break;
}
emptyfile=0;
sigueme:
switch(service)
{
case UCS:
{
dl.servicio=0x01;
switch(tipo)
{
case UI:
{
if(emptyfile)
return(1);
field_ctrl1 = 0xC9;
ma.data.request.calidad.tipo =0x01;
}break;
case XID:
{
if(emptyfile)
return(1);
field_ctrl1 = 0xCB;
ma.data.request.calidad.tipo =0x02;
}break;
case TEST:
{
if(emptyfile)
return(1);
field_ctrl1 = 0xCA;
ma.data.request.calidad.tipo =0x02;
}break;
}
if(!resp)
{
field_ctrl1=field_ctrl1&0xF7;
ma.data.request.calidad.tipo = 0x04;
}
ma.data.request.dir_dest=dl.unitdata.request.dir_dest;
}break;
case CMS:
{
dl.servicio=0x02;
ma.data.request.calidad.tipo =0x01;
switch(tipo)
340
{
case UNNUMBERED:
{
switch(opcion)
{
case SABME:
{
field_ctrl1 = 0xD9;
ma.data.request.dir_dest=dl.connect.request.dir_dest;
}break;
case DISC:
{
field_ctrl1 = 0xDA;
ma.data.request.dir_dest=dl.disconnect.request.dir_dest;
}break;
case UASABME:
{
field_ctrl1 = 0xDB;
ma.data.request.dir_dest=dl.connect.confirm.dir_dest;
}break;
case UADISC:
{
field_ctrl1 = 0xDB;
ma.data.request.dir_dest=dl.disconnect.confirm.dir_dest;
}break;
case UARST:
{
field_ctrl1 = 0xDB;
ma.data.request.dir_dest=dl.reset.confirm.dir_dest;
}break;
case DMSABME:
{
field_ctrl1 = 0xD1;
ma.data.request.dir_dest=dl.connect.confirm.dir_dest;
}break;
case DMDISC:
{
field_ctrl1 = 0xD1;
ma.data.request.dir_dest=dl.disconnect.confirm.dir_dest;
}break;
case DMRST:
{
field_ctrl1 = 0xD1;
ma.data.request.dir_dest=dl.reset.confirm.dir_dest;
}break;
case FRMR:
{
field_ctrl1 = 0xD2;
ma.data.request.dir_dest=dl.unitdata.request.dir_dest;
}break;
case RST:
{
field_ctrl1 = 0xD3;
ma.data.request.dir_dest=dl.reset.request.dir_dest;
}break;
}
}break;
case SUPERVISORY:
{
switch(opcion)
341
{
case RR: {field_ctrl1 = 0x80;}break;
case RNR:{field_ctrl1 = 0x90;}break;
case REJ:{field_ctrl1 = 0xA0;}break;
}
field_ctrl2=0x80|seqrec;
if(!resp)
field_ctrl2=field_ctrl2&0x7F;
ma.data.request.dir_dest=dl.connection_flowcontrol.request.dir_dest;
}break;
case INFORMATION:
{
if(emptyfile)
return(1);
field_ctrl1=seqsend;
field_ctrl2=0x80|seqrec;
if(!resp)
field_ctrl2=field_ctrl2&0x7F;
ma.data.request.dir_dest=dl.data.request.dir_dest;
}break;
}
}break;
case ACS:
{
if(emptyfile)
return(1);
dl.servicio=0x03;
field_ctrl1 = 0xE9;
ma.data.request.calidad.tipo =0x02;
if(!resp)
{
field_ctrl1=field_ctrl1&0xF7;
ma.data.request.calidad.tipo = 0x04;
}
ma.data.request.dir_dest=dl.data_ack.request.dir_dest;
}break;
}
LLC_dinamica(0x00,0x7E);
LLC_dinamica(0x01,0xD8);
LLC_dinamica(0x01,(ma.data.request.calidad.tipo<<3) | 0x40);
dir_tmp = (uchar)((ma.data.request.dir_dest)>>8);
LLC_dinamica(0x01,dir_tmp);
dir_tmp= (uchar)( (ma.data.request.dir_dest)&0x00FF);
LLC_dinamica(0x01,dir_tmp);
dir_tmp = (uchar)((Local_Address)>>8);
LLC_dinamica(0x01,dir_tmp);
dir_tmp =(uchar)( (Local_Address)&0x00FF);
LLC_dinamica(0x01,dir_tmp);
LLC_dinamica(0x01,field_ctrl1);
if((dl.servicio==CMS)&&(field_ctrl1<0xC0))
LLC_dinamica(0x01,field_ctrl2);
if(emptyfile)
goto nolibre;
switch(dl.servicio)
{
case UCS:
{
if(dl.unitdata.request.org!=NULL)
{
dl.unitdata.request.datos=dl.unitdata.request.org;
for(index=0;dl.unitdata.request.datos!=NULL;index++)
342
{
p=dl.unitdata.request.datos->next;
LLC_dinamica(0x01,dl.unitdata.request.datos->byte);
free(dl.unitdata.request.datos);
dl.unitdata.request.datos=p;
}
dl.unitdata.request.status=0;
dl.unitdata.request.org=NULL;
}
}break;
case CMS:
{
if(tipo==INFORMATION)
{
if(dl.data.request.org!=NULL)
{
dl.data.request.datos=dl.data.request.org;
for(index=0;dl.data.request.datos!=NULL;index++)
{
p=dl.data.request.datos->next;
LLC_dinamica(0x01,dl.data.request.datos->byte);
free(dl.data.request.datos);
dl.data.request.datos=p;
}
dl.data.request.status=0;
dl.data.request.org=NULL;
}
}
}break;
case ACS:
{
if(dl.data_ack.request.org!=NULL)
{
dl.data_ack.request.datos=dl.data_ack.request.org;
for(index=0;dl.data_ack.request.datos!=NULL;index++)
{
p=dl.data_ack.request.datos->next;
LLC_dinamica(0x01,dl.data_ack.request.datos->byte);
free(dl.data_ack.request.datos);
dl.data_ack.request.datos=p;
}
dl.data_ack.request.status=0;
dl.data_ack.request.org=NULL;
}
}break;
}
p=NULL;
free(p);
nolibre:
ma.data.request.activa=1;
return(0);
}
uchar MAC_in_level(void)
{
long l=0L,index;
one_byte *p;
uint NPATRON,dir_tmp,func_tmp,aux,estat;
uchar RX_BYTE_IN=-1;
uint IndexCRC;
uchar HiCRC = 0xFF,
343
LoCRC = 0xFF;
FILE *in;
if(phy.unitdata.indication)
{
ma.data.indication.activa=0;
timer_recibo=TIMEOUT_recibo;
l=0L;
do{
disable();
estat=RXB_INDEX-RXS_INDEX;
enable();
}while((timer_recibo>=0)&&!estat);
if (estat)
{
RX_BYTE_IN = RX_BUF[RXS_INDEX];
RXS_INDEX++;
if(RXS_INDEX ==RX_BUF_SIZE)
RXS_INDEX=0;
l++;
}
else
{
phy.notify.invoke=0;
phy.unitdata.indication=0;
return(1);
}
NPATRON=0;
if( (ma.data.indication.sdu= malloc(sizeof(one_byte)))==NULL)
descarga();
ma.data.indication.status=1;
ma.data.indication.org=ma.data.indication.sdu;
ma.data.indication.sdu->byte=RX_BYTE_IN;
ma.data.indication.sdu->next=NULL;
in=fopen("input.dep","a");
if(in!=NULL)
fprintf(in,"\n%x.",RX_BYTE_IN);
if(RX_BYTE_IN==0xD8)
NPATRON++;
while(!phy.notify.invoke)
{
timer_recibo=TIMEOUT_recibo;
do{
disable();
estat=RXB_INDEX-RXS_INDEX;
enable();
}while((timer_recibo>=0)&&!estat);
if (estat)
{
RX_BYTE_IN = RX_BUF[RXS_INDEX];
RXS_INDEX++;
if(RXS_INDEX ==RX_BUF_SIZE)
RXS_INDEX=0;
l++;
if((RX_BYTE_IN!=0xD8)&&(NPATRON==2))
NPATRON=1;
if(RX_BYTE_IN==0xD8)
NPATRON++;
if(NPATRON>=2)
NPATRON=2;
if(l >= MAC_BUF_SIZE )
344
goto termina;
else
{
if((ma.data.indication.sdu->next= malloc(sizeof(one_byte)))==NULL)
descarga();
ma.data.indication.sdu=ma.data.indication.sdu->next;
ma.data.indication.sdu->byte=RX_BYTE_IN;
ma.data.indication.sdu->next=NULL;
if( ((RX_BYTE_IN>64)&&(RX_BYTE_IN<91))||((RX_BYTE_IN>96)&&(RX_BYTE_IN<123)))
{
if(in!=NULL)
fprintf(in,"%c.",RX_BYTE_IN);
}
else
{
if(in!=NULL)
fprintf(in,"%x.",RX_BYTE_IN);
}
}
}
else
{
termina:
phy.notify.invoke=1;
fclose(in);
if((NPATRON!=2)||(l >= MAC_BUF_SIZE))
{
phy.notify.invoke=0;
goto finito;
}
}
}
phy.notify.invoke=0;
ma.data.indication.sdu=ma.data.indication.org;
while((ma.data.indication.sdu->byte==0x7E))
{
p=ma.data.indication.sdu->next;
free(ma.data.indication.sdu);
ma.data.indication.sdu=p;
}
ma.data.indication.org=ma.data.indication.sdu;
if(ma.data.indication.sdu->byte==0xD8)
{
p=ma.data.indication.sdu->next;
free(ma.data.indication.sdu);
ma.data.indication.sdu=p;
ma.data.indication.org=ma.data.indication.sdu;
l=0L;
while(ma.data.indication.sdu->next!=NULL)
{
l++;
ma.data.indication.sdu=ma.data.indication.sdu->next;
}
if(ma.data.indication.sdu->byte!=0xD8)
goto finito;
ma.data.indication.sdu=ma.data.indication.org;
l=l-1L;
for(index=0;index<l;index++)
ma.data.indication.sdu=ma.data.indication.sdu->next;
p=ma.data.indication.sdu->next;
345
ma.data.indication.sdu->next=NULL;
ma.data.indication.sdu=p;
free(ma.data.indication.sdu);
ma.data.indication.sdu=ma.data.indication.org;
while (ma.data.indication.sdu!=NULL)
{
IndexCRC = HiCRC ^ (ma.data.indication.sdu->byte);
ma.data.indication.sdu=ma.data.indication.sdu->next;
HiCRC = LoCRC ^ HiCRCtab[IndexCRC];
LoCRC = LoCRCtab[IndexCRC] ;
}
ma.data.indication.sdu=ma.data.indication.org;
if(HiCRC||LoCRC)
goto finito;
l=l-2L;
for(index=0;index<l;index++)
ma.data.indication.sdu=ma.data.indication.sdu->next;
p=ma.data.indication.sdu->next;
ma.data.indication.sdu->next=NULL;
ma.data.indication.sdu=p;
p=ma.data.indication.sdu->next;
free(ma.data.indication.sdu);
ma.data.indication.sdu=p;
free(ma.data.indication.sdu);
ma.data.indication.sdu=ma.data.indication.org;
if(ma.data.indication.sdu->byte&0x40)
{
if(ma.data.indication.sdu->byte&0x08)
ma.data_status.indication.calidad.tipo=0x08;
else
if(ma.data.indication.sdu->byte&0x10)
ma.data_status.indication.calidad.tipo=0x10;
else
if(ma.data.indication.sdu->byte&0x20)
ma.data_status.indication.calidad.tipo=0x20;
else
goto finito;
ma.data.indication.sdu=ma.data.indication.org;
p=ma.data.indication.sdu->next;
free(ma.data.indication.sdu);
ma.data.indication.sdu=p;
ma.data.indication.dir_dest=((uint)(ma.data.indication.sdu->byte))<<8;
p=ma.data.indication.sdu->next;
free(ma.data.indication.sdu);
ma.data.indication.sdu=p;
ma.data.indication.org=ma.data.indication.sdu;
ma.data.indication.dir_dest= ma.data.indication.dir_dest | (ma.data.indication.sdu->byte);
if( (ma.data.indication.dir_dest==Local_Address)||(ma.data.indication.dir_dest=
=Global_Address))
{
p=ma.data.indication.sdu->next;
free(ma.data.indication.sdu);
ma.data.indication.sdu=p;
ma.data.indication.dir_org=((uint)(ma.data.indication.sdu->byte))<<8;
p=ma.data.indication.sdu->next;
free(ma.data.indication.sdu);
ma.data.indication.sdu=p;
ma.data.indication.org=ma.data.indication.sdu;
ma.data.indication.dir_org= ma.data.indication.dir_org | (ma.data.indication.sdu->byte);
if((ma.data.indication.dir_org==Local_Address)||(ma.data.indication.dir_org==Global_Address))
346
goto finito;
p=ma.data.indication.sdu->next;
free(ma.data.indication.sdu);
ma.data.indication.sdu=p;
ma.data.indication.org=ma.data.indication.sdu;
}
else
goto finito;
if (ma.data_status.indication.calidad.estado==0x01)
{
if(ma.data_status.indication.calidad.tipo==0x20)
{
ma.data_status.indication.dir_dest=ma.data.indication.dir_dest;
ma.data_status.indication.dir_org=ma.data.indication.dir_org;
ma.data_status.indication.calidad.estado=0x00;
if(ma.data.request.org!=NULL)
{
ma.data.request.sdu=ma.data.request.org;
for(l=0;ma.data.request.sdu!=NULL;l++)
{
p=ma.data.request.sdu->next;
free(ma.data.request.sdu);
ma.data.request.sdu=p;
}
ma.data.request.status=0;
ma.data.request.org=NULL;
}
ma.data_status.indication.activa=1;
timer_ack0=-1;
reenvio=0;
}
else
{
ma.data_status.indication.dir_dest=ma.data.indication.dir_dest;
ma.data_status.indication.dir_org=ma.data.indication.dir_org;
ma.data_status.indication.calidad.estado=0x01;
ma.data_status.indication.activa=1;
}
}
ma.data.indication.activa=1;
}
else
{
timer_token=TIMEOUT_response;
func_tmp=(ma.data.indication.sdu->byte);
if( func_tmp > 0x0C)
goto finito;
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
ma.data.indication.dir_dest=((uint)(ma.data.indication.sdu->byte))<<8;
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
ma.data.indication.dir_dest= ma.data.indication.dir_dest | (ma.data.indication.sdu->byte);
if( (ma.data.indication.dir_dest==Local_Address)||(ma.data.indication.dir_dest=
=Global_Address) )
{
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
ma.data.indication.dir_org=((uint)(ma.data.indication.sdu->byte))<<8;
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
ma.data.indication.dir_org= ma.data.indication.dir_org | (ma.data.indication.sdu->byte);
if((ma.data.indication.dir_org==Local_Address)||(ma.data.indication.dir_org==Global_Address) )
goto finito;
347
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
dir_tmp=((uint)(ma.data.indication.sdu->byte))<<8;
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
dir_tmp= dir_tmp | (ma.data.indication.sdu->byte);
if(func_tmp!=TOKEN_PASS)
ma.data.indication.dir_post_org = dir_tmp;
else
{
ma.data.indication.dir_pre_org = dir_tmp;
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
for (aux=0;ma.data.indication.sdu->next!=NULL;aux++)
{
if(aux<=63)
TABLA[aux]=ma.data.indication.sdu->byte;
else
goto finito;
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
}
for (aux=0;aux<=63;aux=aux+2)
{
dir_tmp=(TABLA[aux]<<8)|(TABLA[aux+1]);
if(!set_adrs&&(!TABLA[aux])&&(!TABLA[aux+1]))
{
TABLA[aux]=(uchar)((Local_Address&0xFF00)>>8);
TABLA[aux+1]=(uchar)(Local_Address&0xFF);
set_adrs=1;
}
}
}
if(ma.data.indication.org!=NULL)
{
ma.data.indication.sdu=ma.data.indication.org;
for(l=0;ma.data.indication.sdu!=NULL;l++)
{
p=ma.data.indication.sdu->next;
free(ma.data.indication.sdu);
ma.data.indication.sdu=p;
}
ma.data.indication.status=0;
ma.data.indication.org=NULL;
}
switch(func_tmp)
{
case TOKEN_ASK:token_stat=WAIT;break;
case SUCESS1:token_ctrl=sucesor1;break;
case SUCESS2:token_ctrl=sucesor2;break;
case WHO_NEXT:token_ctrl=quiensigue;break;
case BATTLE:token_ctrl=contienda;break;
case TOKEN_PASS:token_ctrl=paso;break;
case STABLISH:token_ctrl=escape;break;
}
}
else
goto finito;
ma.data.indication.activa=0;
}
}
else
{
finito:
348
if(ma.data.indication.org!=NULL)
{
ma.data.indication.sdu=ma.data.indication.org;
for(l=0;ma.data.indication.sdu!=NULL;l++)
{
p=ma.data.indication.sdu->next;
free(ma.data.indication.sdu);
ma.data.indication.sdu=p;
}
ma.data.indication.status=0;
ma.data.indication.org=NULL;
}
phy.unitdata.indication=0;
p=NULL;
free(p);
return(1);
}
phy.unitdata.indication=0;
p=NULL;
free(p);
}
return(0);
}
char LLC_in_level(void)
{
char p_r=0,c,fallo=0;
int cpu_tmp=0,win_tmp;
long l;
float f,f_aux;
one_byte *p;
if(ma.data.indication.activa)
{
ma.data.indication.activa=0;
if(ma.data.indication.org!=NULL)
{
ma.data.indication.sdu=ma.data.indication.org;
if(((ma.data.indication.sdu->byte)&0xC0)==0xC0)
{
if(ma.data.indication.sdu->byte&0x08)
p_r=1;
if(! ((ma.data.indication.sdu->byte)&0x30) ) /*UCS*/
{
if( ((ma.data.indication.sdu->byte)&0x07)==0x01) /*UI*/
{
dl.unitdata.indication.dir_org=ma.data.indication.dir_org;
dl.unitdata.indication.dir_dest=ma.data.indication.dir_dest;
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
dinamic_LLC(0x00,UNITDATA,ma.data.indication.sdu->byte);
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
for (l=0;ma.data.indication.sdu!=NULL;l++)
{
dinamic_LLC(0x01,UNITDATA,ma.data.indication.sdu->byte);
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
}
dl.unitdata.indication.datos=dl.unitdata.indication.org;
dl.unitdata.indication.activa=1;
L7_ctrl=L7UI;
}
else
if( ((ma.data.indication.sdu->byte)&0x07)==0x03) /*XID*/
349
{
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
dl.unitdata.indication.dir_org=ma.data.indication.dir_org;
dl.unitdata.indication.dir_dest=ma.data.indication.dir_dest;
L7_ctrl=L7XID;
win_tmp=(int)(ma.data.indication.sdu->byte-0x30);
if(ma.data.indication.sdu->next!=NULL)
{
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
win_tmp =win_tmp*10 + (int)(ma.data.indication.sdu->byte-0x30);
}
if(win_tmp<winXID)
winXID=win_tmp;
RX_BUF_SIZE = (10000/winXID);
MAC_BUF_SIZE=RX_BUF_SIZE;
MAXDATA= RX_BUF_SIZE-40;
if(p_r)
{
dl.unitdata.request.dir_dest=ma.data.indication.dir_org;
strcpy(filename,"XID.CFG");
LLC_interface_envios(UCS,XID,0,0x00);
}
}
else
if( ((ma.data.indication.sdu->byte)&0x07)==0x02) /*TEST*/
{
dl.unitdata.indication.dir_org=ma.data.indication.dir_org;
dl.unitdata.indication.dir_dest=ma.data.indication.dir_dest;
L7_ctrl=L7TEST;
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
cpu_tmp=0;
if(p_r)
{
while((ma.data.indication.sdu->byte!=0x20)&&(cpu_tmp<=486))
{
if(ma.data.indication.sdu->byte!=0x20)
cpu_tmp=cpu_tmp*10+(ma.data.indication.sdu->byte-0x30);
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
}
if(cpu_tmp==CPU)
cpu_tmp=386;
else
CPU=cpu_tmp;
cfg=fopen("test.cfg","w");
if(cfg!=NULL)
fprintf(cfg,"%d %s",CPU,"cpu test");
fclose(cfg);
dl.unitdata.request.dir_dest=ma.data.indication.dir_org;
strcpy(filename,"TEST.CFG");
LLC_interface_envios(UCS,TEST,0,0x00);
}
else
{
while((ma.data.indication.sdu->byte!=0x20)&&(cpu_tmp<=486))
{
if(ma.data.indication.sdu->byte!=0x20)
cpu_tmp=cpu_tmp*10+(ma.data.indication.sdu->byte-0x30);
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
}
CPU=cpu_tmp;
350
if((token_stat==PASO)&&(ma.data.indication.dir_org==Next_Address))
{
if(L7_stat==EXIT)
{
disable();
phy.notify.invoke=1;
enable();
cfg=fopen("input.dep","a");
if(cfg!=NULL)
fprintf(cfg,"\nDisconnect Mode\n");
fclose(cfg);
}
token_stat=NOTOKEN;
L7_ctrl=L7OFF;
timer_token=TIMEOUT_response;
}
}
}
else
fallo=1;
}
else
if(((ma.data.indication.sdu->byte)&0x30)==0x10) /*CMS*/
{
if( ((ma.data.indication.sdu->byte)&0x0F)==0x09) /*SABME*/
{
dl.connect.indication.dir_org=ma.data.indication.dir_org;
dl.connect.indication.dir_dest=ma.data.indication.dir_dest;
dl.connect.indication.activa=1;
if(p_r)
{
dl.connect.confirm.dir_dest=ma.data.indication.dir_org;
strcpy(filename,"vacio");
LLC_interface_envios(CMS,UNNUMBERED,UASABME,0x00);
}
}
else
if( ((ma.data.indication.sdu->byte)&0x0F)==0x0A) /*DISC*/
{
dl.disconnect.indication.dir_org=ma.data.indication.dir_org;
dl.disconnect.indication.dir_dest=ma.data.indication.dir_dest;
dl.disconnect.indication.motivo=0x00;
dl.disconnect.indication.activa=1;
if(p_r)
{
dl.disconnect.confirm.dir_dest=ma.data.indication.dir_org;
strcpy(filename,"vacio");
LLC_interface_envios(CMS,UNNUMBERED,UADISC,0x00);
}
}
else
if( ((ma.data.indication.sdu->byte)&0x0F)==0x0B) /*UA*/
{
dl.unitdata.indication.dir_org=ma.data.indication.dir_org;
dl.unitdata.indication.dir_dest=ma.data.indication.dir_dest;
if((L7_stat==CMSUA_SABME)||(L7_stat==CMSUA_DISC)||(L7_stat==CMSUA_RST))
L7_stat++;
}
else
if( ((ma.data.indication.sdu->byte)&0x0F)==0x01) /*DM*/
351
{
dl.unitdata.indication.dir_org=ma.data.indication.dir_org;
dl.unitdata.indication.dir_dest=ma.data.indication.dir_dest;
L7_stat=REPOSO;
dl.disconnect.indication.dir_org=Local_Address;
dl.disconnect.indication.motivo = 0x03;
dl.disconnect.indication.activa=1;
}
else
if( ((ma.data.indication.sdu->byte)&0x0F)==0x02) /*FRMR*/
{
dl.unitdata.indication.dir_org=ma.data.indication.dir_org;
dl.unitdata.indication.dir_dest=ma.data.indication.dir_dest;
if((L7_stat>=INICMS)&&(L7_stat<CMSACK))
{
L7_stat=INICMS;
dl.unitdata.request.dir_dest=dl.unitdata.indication.dir_org;
}
else
{
if(L7_stat==CMSUA_DISC)
{
filepos=1L;
endfile=1L;
L7_stat=CMSI;
}
else
{
if(L7_stat==CMSUA_RST)
{
strcpy(filename,"vacio");
dl.reset.request.dir_dest=dl.unitdata.indication.dir_org;
LLC_interface_envios(CMS,UNNUMBERED,RST,0x01);
}
}
}
}
else
if( ((ma.data.indication.sdu->byte)&0x0F)==0x03) /*RST*/
{
dl.reset.indication.dir_org=ma.data.indication.dir_org;
dl.reset.indication.dir_dest=ma.data.indication.dir_dest;
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
dl.reset.indication.motivo=ma.data.indication.sdu->byte;
dl.reset.indication.activa=1;
if(p_r)
{
dl.reset.confirm.dir_dest=ma.data.indication.dir_org;
strcpy(filename,"vacio");
LLC_interface_envios(CMS,UNNUMBERED,UARST,0x00);
}
}
else
fallo=1;
}
else
if(((ma.data.indication.sdu->byte)&0x30)==0x20) /*ACS*/
{
if( ((ma.data.indication.sdu->byte)&0x07)==0x01) /*AC*/
{
352
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
if(!p_r)
{
dl.data_ack_status.indication.dir_org=ma.data.indication.dir_org;
dl.data_ack_status.indication.dir_dest=ma.data.indication.dir_dest;
ma.data_status.indication.calidad.estado=0x00;
dl.data_ack_status.indication.estado = ma.data_status.indication.calidad.estado;
dl.data_ack_status.indication.activa=1;
L7_ctrl=L7AC;
}
else
{
dl.data_ack.indication.dir_org=ma.data.indication.dir_org;
dl.data_ack.indication.dir_dest=ma.data.indication.dir_dest;
cfg=fopen("acs.cfg","w");
dinamic_LLC(0x00,DATA_ACK,ma.data.indication.sdu->byte);
if(cfg!=NULL)
fprintf(cfg,"%c",ma.data.indication.sdu->byte);
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
for (l=0;ma.data.indication.sdu!=NULL;l++)
{
dinamic_LLC(0x01,DATA_ACK,ma.data.indication.sdu->byte);
if(cfg!=NULL)
fprintf(cfg,"%c",ma.data.indication.sdu->byte);
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
}
fclose(cfg);
dl.data_ack.request.dir_dest=ma.data.indication.dir_org;
dl.data_ack.indication.datos=dl.data_ack.indication.org;
dl.data_ack.indication.activa=1;
strcpy(filename,"acs.cfg");
LLC_interface_envios(ACS,0,0,0x00);
}
}
else
fallo=1;
}
else
fallo=1;
}
else
if(((ma.data.indication.sdu->byte)&0xC0)==0x80) /* CMS*/
{
if( ((ma.data.indication.sdu->byte)&0x30)==0x00) /*RR*/
{
dl.connection_flowcontrol.indication.dir_org=ma.data.indication.dir_org;
dl.connection_flowcontrol.indication.dir_dest=ma.data.indication.dir_dest;
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
dl.connection_flowcontrol.indication.numdatos=(ma.data.indication.sdu->byte)&0x7F;
seqrec=dl.connection_flowcontrol.indication.numdatos;
dl.connection_flowcontrol.indication.activa=1;
if((L7_stat==CMSACK)||(L7_stat==CMSWAIT))
{
timer_ack0=-1;
if(seqrec==winXID)
L7_stat=CMSI;
else
{
L7_stat=CMSUA_RST;
strcpy(filename,"vacio");
353
dl.reset.request.dir_dest=dl.connection_flowcontrol.indication.dir_org;
LLC_interface_envios(CMS,UNNUMBERED,RST,0x01);
dl.reset.indication.dir_org=Local_Address;
dl.reset.indication.activa=1;
}
}
}
else
if( ((ma.data.indication.sdu->byte)&0x30)==0x10) /*RNR*/
{
dl.connection_flowcontrol.indication.dir_org=ma.data.indication.dir_org;
dl.connection_flowcontrol.indication.dir_dest=ma.data.indication.dir_dest;
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
dl.connection_flowcontrol.indication.numdatos=(ma.data.indication.sdu->byte)&0x7F;
seqrec=dl.connection_flowcontrol.indication.numdatos;
dl.connection_flowcontrol.indication.activa=1;
if( L7_stat==CMSACK)
{
timer_ack0=-1;
if(seqrec==winXID)
L7_stat=CMSWAIT;
else
{
L7_stat=CMSUA_RST;
strcpy(filename,"vacio");
dl.reset.request.dir_dest=dl.connection_flowcontrol.indication.dir_org;
LLC_interface_envios(CMS,UNNUMBERED,RST,0x01);
dl.reset.indication.dir_org=Local_Address;
dl.reset.indication.activa=1;
}
}
}
else
if( ((ma.data.indication.sdu->byte)&0x30)==0x20) /*REJ*/
{
dl.connection_flowcontrol.indication.dir_org=ma.data.indication.dir_org;
dl.connection_flowcontrol.indication.dir_dest=ma.data.indication.dir_dest;
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
dl.connection_flowcontrol.indication.numdatos=(ma.data.indication.sdu->byte)&0x7F;
seqrec=dl.connection_flowcontrol.indication.numdatos;
dl.connection_flowcontrol.indication.activa=1;
timer_ack0=-1;
cfg=fopen(filename,"r");
if(cfg!=NULL)
{
fseek(cfg, 0L, SEEK_SET);
if(seqrec>=seqsend)
winseq--;
f= (float)(seqrec)+(float)(winseq*winXID);
f=f*(float)(MAXDATA);
if(f>0.0)
{for(f_aux=0.0;f_aux<f;f_aux=f_aux+1.0)
c=getc(cfg);
}
fgetpos(cfg,&filepos);
seqsend=seqrec;
L7_stat=CMSREJ;
}
if((filepos>endfile)||(cfg==NULL))
{
354
L7_stat=CMSUA_RST;
strcpy(filename,"vacio");
dl.reset.request.dir_dest=dl.connection_flowcontrol.indication.dir_org;
LLC_interface_envios(CMS,UNNUMBERED,RST,0x01);
dl.reset.indication.dir_org=Local_Address;
dl.reset.indication.activa=1;
}
fclose(cfg);
}
else
fallo=1;
}
else
if(!((ma.data.indication.sdu->byte)&0x80)) /*I*/
{
seqrec=(ma.data.indication.sdu->byte);
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
dinamic_LLC(0x00,DATA,ma.data.indication.sdu->byte);
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
for (l=0;ma.data.indication.sdu!=NULL;l++)
{
dinamic_LLC(0x01,DATA,ma.data.indication.sdu->byte);
(ma.data.indication.sdu)=(ma.data.indication.sdu->next);
}
dl.data.indication.datos=dl.data.indication.org;
dl.data.indication.dir_org=ma.data.indication.dir_org;
dl.data.indication.dir_dest=ma.data.indication.dir_dest;
dl.data.indication.activa =1;
}
else
fallo=1;
if(ma.data.indication.org!=NULL)
{
ma.data.indication.sdu=ma.data.indication.org;
for(l=0;ma.data.indication.sdu!=NULL;l++)
{
p=ma.data.indication.sdu->next;
free(ma.data.indication.sdu);
ma.data.indication.sdu=p;
}
ma.data.indication.status=0;
ma.data.indication.org=NULL;
}
p=NULL;
free(p);
return(fallo);
}
else
return(1);
}
return(0);
}
void resetEPROM()
{
int aux,cmd,adr,emr;
long posf,finf;
unsigned int dest;
FILE *rom,*tmp;
rom=fopen("EPROM.cfg","r");
355
tmp=fopen("SRAM.cfg","w");
if((rom!=NULL)&&(tmp!=NULL))
{
fseek(rom,0L,SEEK_END);
if( (finf = ftell(rom)) >0L)
{
fseek(rom,0L,SEEK_SET);
while(!feof(rom)&&!feof(tmp))
{
posf = ftell(rom);
if(!feof(rom)&&!feof(tmp))
fscanf(rom,"%x %d %u %d\n",&cmd,&adr,&dest,&emr);
if(posf!=(finf-1L))
{
if(!feof(rom)&&!feof(tmp))
fprintf(tmp,"%x %d %u %d\n",cmd,adr,dest,emr);
}
}
fclose(rom);
fclose(tmp);
rom=fopen("EPROM.cfg","w");
tmp=fopen("SRAM.cfg","r");
if((rom!=NULL)&&(tmp!=NULL))
{
while(!feof(tmp)&&!feof(rom))
{
aux=getc(tmp);
if(!feof(tmp))
putc(aux,rom);
}
}
}
}
fclose(tmp);
fclose(rom);
}
uchar L7_in_level(int *num_plcs,int EMR)
{
div_t V;
int i=0,j=0,comand=-1;
int plc_dir=-1;
uint origen=0;
long l;
one_byte *p;
char string[25],str[64],c_aux1=0,c_aux2=0;
struct restaura
{
uint origen,old,win;
long pos,end;
char find,open;
char nom[20];
}backup;
FILE *TMP,*RAM,*AUX;
if(dl.disconnect.indication.activa)
{
dl.disconnect.indication.activa=0;
if(dl.disconnect.indication.motivo&&(dl.disconnect.indication.motivo<6))
{
seqsend=0;
winseq=0;
356
L7_ctrl=OFF;
L7_stat=REPOSO;
}
else
{
if(openFILE)
{
timer_ack1=-1;
if(filepos!=endfile)
{
RAM=fopen("RAM.cfg","a");
if(RAM!=NULL)
fprintf(RAM,"%u %ld %ld %u %u %x %s\n",dl.disconnect.indication.dir_org,filepos,endfile,
oldseq, winXID,openFILE,nomfich);
fclose(RAM);
oldseq=0;
openFILE=0;
}
else
{
winXID=WINDOW;
RX_BUF_SIZE = 10000/winXID;
MAC_BUF_SIZE=RX_BUF_SIZE;
MAXDATA= RX_BUF_SIZE-40;
oldseq=0;
filepos=0;
endfile=0;
openFILE=0;
if((pag==2)&&(!strcmp(nomfich,"plcfile.dat")))
valores();
if((pag<2)&&(!strcmp(nomfich,"workst.dat")))
{
TMP=fopen("workst.dat","r");
AUX=fopen("station.dat","w");
while(!feof(TMP)&&!feof(AUX))
fprintf(AUX,"%c",getc(TMP));
fclose(AUX);
fclose(TMP);
}
origen=dl.disconnect.indication.dir_org;
goto resetRAM;
}
}
}
winXID=WINDOW;
RX_BUF_SIZE = 10000/winXID;
MAC_BUF_SIZE=RX_BUF_SIZE;
MAXDATA= RX_BUF_SIZE-40;
filepos=0;
endfile=0;
}
if(dl.reset.indication.activa)
{
dl.reset.indication.activa=0;
seqsend=0;
winseq=0;
winXID=WINDOW;
RX_BUF_SIZE = 10000/winXID;
MAC_BUF_SIZE=RX_BUF_SIZE;
MAXDATA= RX_BUF_SIZE-40;
357
seqrec=0;
oldseq=0;
filepos=0;
endfile=0;
L7_ctrl=OFF;
openFILE=0;
if(dl.reset.indication.dir_org==Local_Address)
{
L7_stat=INICMS;
dl.unitdata.request.dir_dest=dl.reset.indication.dir_dest;
TMP=fopen("ROM.cfg","w");
fclose(TMP);
resetEPROM();
}
else
{
L7_stat=REPOSO;
origen=dl.reset.indication.dir_org;
goto resetRAM;
}
}
if(dl.unitdata.indication.activa)
{
dl.unitdata.indication.activa=0;
if(pag<2)
{
setfillstyle(SOLID_FILL,0);
bar(332,456,425,472);
setcolor(7);
outtextxy(335,460,"Ext.Warning");
}
if(dl.unitdata.indication.org!=NULL)
{
i=-1;
dl.unitdata.indication.datos=dl.unitdata.indication.org;
for(j=0;dl.unitdata.indication.datos!=NULL;j++)
{
p=dl.unitdata.indication.datos->next;
if(L7_ctrl==L7UI)
{
if(i>=0)
string[i++]=dl.unitdata.indication.datos->byte;
if(dl.unitdata.indication.datos->byte==0x23)
{
str[j]='\0';
i=0;
}
if(i<0)
str[j]=dl.unitdata.indication.datos->byte;
}
free(dl.unitdata.indication.datos);
dl.unitdata.indication.datos=p;
}
dl.unitdata.indication.status=0;
dl.unitdata.indication.org=NULL;
if(L7_ctrl==L7UI)
{
origen=dl.unitdata.indication.dir_org;
if(i<0)
str[j]='\0';
358
else
string[i++]='\0';
j=atoi(string);
if(!strcmp("command: send number of plcs",str))
comand=0x20;
else
if(!strcmp("command: MODBUS error",str))
message("Bus Error",0);
else
if((!strcmp("command: Mode changed to value ",str))&&(pag==2))
{
itoa(j,string,10);
fondo(615,25,625,35,7,8);
outtextxy(619,25,string);
outtextxy(535,25,"Listen Mode");
}
else
if((!strcmp("command: DO changed to value ",str))&&(pag==2))
{
if(j<10)
i=7;
else
i=7-(j/10);
j=j&1;
itoa(j,string,10);
fondo(439+i*10,83,447+i*10,93,7,7);
setcolor(8);
outtextxy(440+i*10,83,string);
outtextxy(415,85,"DO");
}
L7_ctrl=L7OFF;
}
p=NULL;
free(p);
}
}
if(dl.data_ack.indication.activa)
{
dl.data_ack.indication.activa=0;
if(pag<2)
{
setfillstyle(SOLID_FILL,0);
bar(332,456,425,472);
setcolor(7);
outtextxy(335,460,"Ext.Command");
}
if(dl.data_ack.indication.org!=NULL)
{
i=-1;
dl.data_ack.indication.datos=dl.data_ack.indication.org;
for(j=0;dl.data_ack.indication.datos!=NULL;j++)
{
p=dl.data_ack.indication.datos->next;
if(i>=0)
string[i++]=dl.data_ack.indication.datos->byte;
if(dl.data_ack.indication.datos->byte==0x23)
{
str[j]='\0';
i=0;
}
359
if(i<0)
str[j]=dl.data_ack.indication.datos->byte;
free(dl.data_ack.indication.datos);
dl.data_ack.indication.datos=p;
}
dl.data_ack.indication.status=0;
dl.data_ack.indication.org=NULL;
string[i++]='\0';
origen=dl.data_ack.indication.dir_org;
i=atoi(string);
if(!strcmp("command: disconnect from lan ",str))
comand=0xFF;
else
if(!strcmp("command: change mode of plc n§ ",str))
{
plc_dir=i&0x2F;
comand=0xE0;
}
else
if(!strcmp("command: send value of AI n§ ",str))
{
plc_dir=i>>8;
i=i&0xF;
comand=0x80|i;
}
else
if(!strcmp("command: change value of DO n§ ",str))
{
plc_dir=i>>8;
i=i&0xF;
comand=0x70|i;
}
else
if(!strcmp("command: send data of plc n§ ",str))
{
j=i>>8;
EMR=i&0x0F;
j--;
if(j>15)
{
j=j-16;
comand=0x60|j;
}
else
comand=0x50|j;
plc_dir=j+1;
}
p=NULL;
free(p);
}
}
if(dl.data.indication.activa)
{
dl.data.indication.activa =0;
RAM=fopen("RAM.cfg","r");
TMP=fopen("copia.cfg","w");
if((RAM!=NULL)&&(TMP!=NULL))
{
fseek(RAM,0L,SEEK_END);
if(ftell(RAM)>0L)
360
{
fseek(RAM,0L,SEEK_SET);
backup.find=0;
while(!feof(RAM)&&!feof(TMP))
{
if(!feof(RAM)&&!feof(TMP))
fscanf(RAM,"%u %ld %ld %u %u %x %s\n",&backup.origen,&backup.pos,&backup.end,
&backup.old, &backup.win,&backup.open,backup.nom);
if((backup.origen==dl.data.indication.dir_org)&&!backup.find)
{
backup.find=1;
filepos=backup.pos;
endfile=backup.end;
oldseq=backup.old;
winXID=backup.win;
openFILE=backup.open;
strcpy(nomfich,backup.nom);
}
else
{
if(!feof(RAM)&&!feof(TMP))
fprintf(TMP,"%u %ld %ld %u %u %x %s\n",backup.origen,backup.pos,backup.end,backup.old,
backup.win,backup.open,backup.nom);
}
}
fclose(RAM);
fclose(TMP);
RAM=fopen("RAM.cfg","w");
TMP=fopen("copia.cfg","r");
if((RAM!=NULL)&&(TMP!=NULL))
{
while(!feof(TMP)&&!feof(RAM))
{
c_aux1=getc(TMP);
if(!feof(TMP))
putc(c_aux1,RAM);
}
}
}
}
fclose(TMP);
fclose(RAM);
if(seqrec!=(oldseq+1))
{
error_sequence:
ma.data.request.activa=0;
if(dl.data.indication.org!=NULL)
{
dl.data.indication.datos=dl.data.indication.org;
for(l=0;dl.data.indication.datos!=NULL;l++)
{
p=dl.data.indication.datos->next;
free(dl.data.indication.datos);
dl.data.indication.datos=p;
}
dl.data.indication.status=0;
dl.data.indication.org=NULL;
}
p=NULL;
free(p);
361
timer_ack1=TIMEOUT_ack1;
return(1);
}
if(openFILE)
TMP=fopen(nomfich,"a");
if(dl.data.indication.org!=NULL)
{
i=0;
j=0;
c_aux1=0;
c_aux2=0;
dl.data.indication.datos=dl.data.indication.org;
for(l=0;dl.data.indication.datos!=NULL;l++)
{
if(!openFILE)
{
if(!c_aux1)
{
if(dl.data.indication.datos->byte!=0x2E)
{
nomfich[i++]=dl.data.indication.datos->byte;
if(i>8)
goto error_sequence;
}
else
{
nomfich[i++]=dl.data.indication.datos->byte;
j=i;
i=0;
c_aux1=1;
}
}
else
{
if(!c_aux2)
{
if(dl.data.indication.datos->byte!=0xFF)
{
nomfich[j+i]=dl.data.indication.datos->byte;
i++;
if(i>3)
goto error_sequence;
}
else
c_aux2=1;
}
else
{
nomfich[i+j]='\0';
TMP=fopen(nomfich,"w");
fclose(TMP);
TMP=fopen(nomfich,"a");
openFILE=1;
endfile=0L;
filepos=0L;
i=0;
}
}
}
if(openFILE)
362
{
if(endfile==0L)
{
if(dl.data.indication.datos->byte!=0xFF)
{
string[i++]=dl.data.indication.datos->byte;
if(i>7)
{
fclose(TMP);
goto error_sequence;
}
}
else
{
string[i++]='\0';
endfile=atol(string);
string[0]='\0';
i=0;
j=0;
}
}
else
{
if(dl.data.indication.datos->byte!=0xFF)
{
if(TMP!=NULL)
fprintf(TMP,"%c",dl.data.indication.datos->byte);
if( ((dl.data.indication.datos->byte==0x23)||j)&&(!strcmp(nomfich,"workst.dat")) )
{
j=1;
if((dl.data.indication.datos->byte>0x29)&&(dl.data.indication.datos->byte<0x40))
{
string[i++]=dl.data.indication.datos->byte;
if(i>2)
{
fclose(TMP);
goto error_sequence;
}
}
}
filepos++;
}
else
{
filepos=endfile;
if(!strcmp(nomfich,"workst.dat"))
{
string[i++]='\0';
*num_plcs=atoi(string);
}
goto da_ack;
}
}
}
dl.data.indication.datos=dl.data.indication.datos->next;
}
}
if(seqrec==winXID)
{
363
da_ack:
if((unsigned long)coreleft()>=1000L)
{
dl.connection_flowcontrol.request.dir_dest=dl.data.indication.dir_org;
strcpy(filename,"vacio");
LLC_interface_envios(CMS,SUPERVISORY,RR,0x00);
}
else
{
dl.connection_flowcontrol.request.dir_dest=dl.data.indication.dir_org;
strcpy(filename,"vacio");
LLC_interface_envios(CMS,SUPERVISORY,RNR,0x00);
}
oldseq=0;
}
else
oldseq=seqrec;
if(openFILE)
fclose(TMP);
if(pag<2)
{
setfillstyle(SOLID_FILL,0);
bar(332,456,425,472);
outtextxy(335,460,"Ext.File");
}
if(dl.data.indication.org!=NULL)
{
dl.data.indication.datos=dl.data.indication.org;
for(l=0;dl.data.indication.datos!=NULL;l++)
{
p=dl.data.indication.datos->next;
free(dl.data.indication.datos);
dl.data.indication.datos=p;
}
dl.data.indication.status=0;
dl.data.indication.org=NULL;
}
timer_ack1=TIMEOUT_ack1;
p=NULL;
free(p);
}
if(comand!=-1)
{
TMP=fopen("EPROM.cfg","a");
if(TMP!=NULL)
fprintf(TMP,"%x %d %u %d\n",comand,plc_dir,origen,EMR);
fclose(TMP);
if(pag<2)
{
setfillstyle(SOLID_FILL,0);
bar(332,456,425,472);
outtextxy(335,460,"Ext. Query");
}
}
return(0);
resetRAM:
RAM=fopen("RAM.cfg","r");
TMP=fopen("copia.cfg","w");
if((RAM!=NULL)&&(TMP!=NULL))
{
364
fseek(RAM,0L,SEEK_END);
if(ftell(RAM)>0L)
{
fseek(RAM,0L,SEEK_SET);
while(!feof(RAM)&&!feof(TMP))
{
fscanf(RAM,"%u %ld %ld %u %u %x %s\n",&backup.origen,&backup.pos,&backup.end,
&backup.old, &backup.win,&backup.open,backup.nom);
if(backup.origen!=origen)
{
if(!feof(TMP)&&!feof(RAM))
fprintf(TMP,"%u %ld %ld %u %u %x %s\n",backup.origen,backup.pos,backup.end,backup.old,
backup.win,backup.open,backup.nom);
}
}
fclose(TMP);
fclose(RAM);
RAM=fopen("RAM.cfg","w");
TMP=fopen("copia.cfg","r");
if((RAM!=NULL)&&(TMP!=NULL))
{
while(!feof(TMP)&&!feof(RAM))
{
fscanf(TMP,"%u %ld %ld %u %u %x %s\n",&backup.origen,&backup.pos,&backup.end,
&backup.old, &backup.win,&backup.open,backup.nom);
if(!feof(TMP)&&!feof(RAM))
fprintf(RAM,"%u %ld %ld %u %u %x %s\n",backup.origen,backup.pos,backup.end,backup.old,
backup.win,backup.open,backup.nom);
}
}
}
}
fclose(RAM);
fclose(TMP);
return(0);
}
void showred(uint address,int *posx,int *posy,char ciclo,int num1,int num2)
{
int netposx, netposy,i,n;
uint dir_station=0;
if(pag<2)
{
pantalla(pag);
netposx=32;
netposy=324;
if(!pag)
n=num1;
else
n=num2;
for (i=0;i<n;i++)
{
if(i==16)
{
netposy=372;
netposx=32;
}
fondo(netposx,netposy,netposx+2,netposy-8,3,6);
fondo(netposx,netposy,netposx+10,netposy+10,9,6);
netposx=netposx+32;
}
365
if(pag)
doc("station.dat",2);
else
doc("history.dat",2);
}
netposx=32;
netposy=16;
for (i=0;i<=63;i=i+2)
{
dir_station=(TABLA[i]<<8)|(TABLA[i+1]);
if(i==32)
{
netposy=64;
netposx=32;
}
if((dir_station==address)&&address)
{
TABLA[i]=0;
TABLA[i+1]=0;
dir_station=0;
if(pag<2)
{
fondo(netposx,netposy,netposx+2,netposy-8,3,6);
fondo(netposx,netposy,netposx+10,netposy+10,0,6);
}
}
if(pag<2)
{
if(!dir_station)
netposx=netposx+32;
else
{
if(dir_station==Local_Address)
{
fondo(netposx,netposy,netposx+2,netposy-8,3,6);
fondo(netposx,netposy,netposx+10,netposy+10,11,6);
*posx=netposx;
*posy=netposy;
netposx=netposx+32;
}
else
{
fondo(netposx,netposy,netposx+2,netposy-8,3,6);
if(ciclo<2)
fondo(netposx,netposy,netposx+10,netposy+10,8,6);
else
fondo(netposx,netposy,netposx+10,netposy+10,9,6);
netposx=netposx+32;
}
}
}
}
if(pag<2)
{
setcolor(7);
settextstyle(DEFAULT_FONT,HORIZ_DIR,1);
outtextxy(335,430,tokennom[token_stat]);
outtextxy(335,445,L7nom[L7_stat&0x1F]);
}
putimage(mx,my,raton,XOR_PUT);
366
}
void LLC_out()
{
if(ma.data.request.activa)
{
ma.data.request.activa=0;
cola();
if(ma.data.request.calidad.tipo!=0x02)
{
ma.data_status.indication.dir_dest=ma.data.request.dir_dest;
ma.data_status.indication.dir_org=Local_Address;
ma.data_status.indication.activa=1;
ma.data_status.indication.calidad.estado=0x00;
}
else
ma.data_status.indication.calidad.estado=0x01;
phy.unitdata.request=1;
}
}
char mouse_stat(int *cmd,int *numplcs,int plc_adr,int *emr ,char *buttonhit)
{
union REGS inregs,outregs;
int aux;
char string[25];
inregs.x.ax = 6;
int86(0x33,&inregs,&outregs);
if( ((outregs.x.ax&3)==1)&&(!*buttonhit))
{
inregs.x.ax = 3;
int86(0x33,&inregs,&outregs);
*cmd=-1;
if(pag<2)
{
if((outregs.x.dx==456)&&(outregs.x.cx==11))
*cmd=0x40;
else
if((outregs.x.dx==456)&&(outregs.x.cx==611))
{
if(!pag)
*cmd=0xF0;
else
*cmd=0xB0;
}
else
{
aux=(int)(outregs.x.cx);
while(aux>0)
{
aux=aux-32;
*cmd=*cmd+1;
}
if(!aux)
{
if(!pag)
{
if((outregs.x.dx==16)||(outregs.x.dx==64))
{
if(outregs.x.dx==16)
outregs.x.dx=0x00;
else
367
outregs.x.dx=0x10;
*cmd=(int)(outregs.x.dx)|*cmd;
*buttonhit=1;
}
else
if((outregs.x.dx==324)||(outregs.x.dx==372))
{
if(outregs.x.dx==324)
outregs.x.dx=0x90;
else
outregs.x.dx=0xA0;
*cmd=(int)(outregs.x.dx)|*cmd;
}
else
*cmd=-1;
}
else
*cmd=-1;
}
else
*cmd=-1;
}
}
else
{
if(pag==2)
{
if((outregs.x.dx==5)&&(outregs.x.cx==5))
{
setcolor(10);
outtextxy(21,8,"Set Now");
*cmd=(plc_adr-1)&0x0F;
if(plc_adr>16)
*cmd=0xA0|*cmd;
else
*cmd=0x90|*cmd;
}
if((outregs.x.dx==200)&&(outregs.x.cx==625))
{
*emr=*emr+1;
if(*emr>12)
*emr=1;
*cmd=(plc_adr-1)&0x0F;
if(plc_adr>16)
*cmd=0xA0|*cmd;
else
*cmd=0x90|*cmd;
}
if((outregs.x.dx>285)&&(outregs.x.cx>161)&&(outregs.x.dx<343)&&(outregs.x.cx<299))
{
pag=3;
SRAM();
*cmd=0x30;
putimage(mx,my,raton,XOR_PUT);
}
}
else
if(pag==3)
{
if((outregs.x.dx>464)&&(outregs.x.cx>599)&&(outregs.x.dx<476)&&(outregs.x.cx<611))
368
{
SRAM();
*cmd=0x30;
putimage(mx,my,raton,XOR_PUT);
setcolor(10);
settextstyle(SANS_SERIF_FONT,HORIZ_DIR,1);
outtextxy(561,441,"Set Now");
}
}
}
}
else
if((outregs.x.ax&3)==2)
{
putimage(mx,my,raton,XOR_PUT);
if(pag>2)
{
*cmd= (plc_adr-1)&0xF;
if(plc_adr>16)
*cmd=0xA0|*cmd;
else
*cmd=0x90|*cmd;
pag=2;
microlocal();
putimage(mx,my,raton,XOR_PUT);
return(0);
}
pag=0;
if(pag<=0)
{
*numplcs=0;
pag=0;
cfg=fopen("ram.img","w");
fclose(cfg);
cfg=fopen("workst.dat","w");
fclose(cfg);
cfg=fopen("station.dat","w");
fclose(cfg);
}
return(1);
}
return(0);
}
void reinicio()
{
int aux;
timer_recibo=-1;
timer_envio=-1;
timer_ack0=-1;
timer_ack1=-1;
phy.unitdata.request=0;
ma.data.indication.activa=0;
ma.data_status.indication.activa=0;
ma.data_status.indication.calidad.estado=0;
ma.data.request.activa=0;
ma.data.indication.status=0;
ma.data.request.status=0;
dl.unitdata.indication.activa=0;
dl.connect.indication.activa=0;
dl.disconnect.indication.activa=0;
369
dl.reset.indication.activa=0;
dl.data_ack.indication.activa=0;
dl.data_ack_status.indication.activa=0;
dl.connection_flowcontrol.indication.activa=0;
dl.data.indication.activa =0;
dl.unitdata.indication.status=0;
dl.data.indication.status=0;
dl.data_ack.indication.status=0;
dl.unitdata.request.status=0;
dl.data.request.status=0;
dl.data_ack.request.status=0;
set_adrs=0;
Next_Address = Global_Address;
Previous_Address = 0;
filepos=0L;
endfile= 0L;
openFILE=0;
token_stat=NOTOKEN;
L7_stat=REPOSO;
L7_ctrl=L7OFF;
winXID=WINDOW;
RX_BUF_SIZE = 10000/winXID;
MAC_BUF_SIZE=RX_BUF_SIZE;
MAXDATA= RX_BUF_SIZE-40;
RXB_INDEX=0;
RXS_INDEX=0;
for(aux=0;aux<=RX_BUF_SIZE;aux++)
RX_BUF[aux]=0;
pag=0;
TABLA[0]=(uchar)((Local_Address&0xFF00)>>8);
TABLA[1]=(uchar)(Local_Address&0xFF);
for(aux=2;aux<=63;aux++)
TABLA[aux]=0x00;
timer_token=TIMEOUT_response;
phy.unitdata.indication=0;
rotation=0;
phy.notify.invoke=0;
}
uchar ctrl_ack()
{
if((timer_ack1<0)&&openFILE)
{
strcpy(filename,"vacio");
dl.reset.request.dir_dest=dl.data.indication.dir_org;
LLC_interface_envios(CMS,UNNUMBERED,RST,0x01);
dl.reset.indication.dir_org=Local_Address;
dl.reset.indication.dir_dest=dl.reset.request.dir_dest;
dl.reset.indication.activa=1;
if(pag<2)
{
setfillstyle(SOLID_FILL,0);
bar(332,456,425,472);
outtextxy(335,460,"Local Reset");
}
openFILE=0;
}
if(ma.data.request.activa)
return(1);
if((timer_ack0<0)&& (token_stat==TOKENACTV))
{
370
if ( (L7_stat==CMSUA_RST)||(L7_stat==CMSACK)|| (L7_stat= =CMSUA_DISC)
||(L7_stat==CMSUA_SABME) )
{
dl.disconnect.indication.dir_org=Local_Address;
dl.disconnect.indication.motivo = 0x04;
dl.disconnect.indication.activa=1;
if(pag<2)
{
setfillstyle(SOLID_FILL,0);
bar(332,456,425,472);
outtextxy(335,460,"Local Disc");
}
strcpy(filename,"vacio");
dl.disconnect.request.dir_dest=dl.data.request.dir_dest;
LLC_interface_envios(CMS,UNNUMBERED,DISC,0x01);
}
}
return(1);
}
/*Rutina de comunicaciones con el bus de campo,se le ha de pasar la dirección del
microcontrolador elegido,la orden deseada (basada en el protocolo MODBUS) que
realice,además de la dirección de inicio y el parámetro correspondiente si son
necesarios, se encarga de construir mediante esos datos la trama MODBUS
correspondiente y de enviarla por el bus de campo (las tramas enviadas se almacenan
en un fichero de texto llamado OUTPUT.DEP. Se hace resaltar el retardo introducido de
2ms antes de inhabilitar la transmisión ya que sino el último byte de dicha trama se
perdería.Enviada la trama MODBUS escucha la respuesta de no haberla el temporizador
del bus se desborda y la función al detectarlo devuelve un código de error '1'. Si se
recibe respuesta se comprueba el CRC y que el microcontrolador no haya enviado una
respuesta de excepción (MSB del byte de función a '1'). Las respuestas recibidas se
guardan en un fichero de texto llamado BUSIN.DEP.Si la respuesta es correcta devuelve
un valor nulo. Para acceder a los datos recibidos hay que dirigirse a la tabla FE_BUF*/
uchar MOD(uchar adr,uchar func,uchar dir,uchar param)
{
int aux,nelement=1;
uchar HiCRC = 0xFF,LoCRC = 0xFF,MODtabla[15]="vacio";
uint IndexCRC;
FILE *dep;
MODtabla[0]=adr;
MODtabla[1]=func;
nelement=1;
switch(func)
{
case 1:
case 2:{
/*writeDI-DO*/
MODtabla[2]=0;
MODtabla[3]=0;
MODtabla[4]=0;
MODtabla[5]=7;
MODtabla[6]='\0';
nelement=5;
}break;
case 3:{
/*readCPURAM*/
MODtabla[2]=0;
MODtabla[3]=0;
MODtabla[4]=0;
MODtabla[5]=32;
MODtabla[6]='\0';
nelement=5;
}break;
371
case 4:{
/*readAI*/
MODtabla[2]=0;
MODtabla[3]=dir;
MODtabla[4]=0;
MODtabla[5]=param;
MODtabla[6]='\0';
nelement=5;
}break;
case 5:{
/*writeD0*/
MODtabla[2]=0;
MODtabla[3]=dir;
MODtabla[4]=param;
MODtabla[5]=0;
nelement=5;
MODtabla[6]='\0';
}break;
case 8:{
/*diagnostico*/
MODtabla[2]=0;
MODtabla[3]=param;
switch(param)
{
case 0:{
MODtabla[4]=170;
MODtabla[5]=85;
MODtabla[6]='\0';
nelement=5;
}break;
case 1:
{
MODtabla[4]=255;
MODtabla[5]=0;
MODtabla[6]='\0';
nelement=5;
}break;
default:
{
MODtabla[4]='\0';
nelement=3;
}break;
}
}break;
case 7:
/*reles emergencia y tipo esclavo*/
case 17:{
MODtabla[2]='\0';
nelement=1;
}break;
case 20:{
/*E.M.R.*/
MODtabla[2]=7;
MODtabla[3]=6;
MODtabla[4]=0;
MODtabla[5]=dir;
MODtabla[6]=0;
MODtabla[7]=param;
MODtabla[8]=0;
MODtabla[9]=64; /*256 bytes en 4 lecturas de (64x2) bytes*/
MODtabla[10]='\0';
nelement=9;
}break;
}
HiCRC = 0xFF;
372
LoCRC = 0xFF;
for(aux=0;aux<=nelement;aux++)
{
IndexCRC = HiCRC ^ MODtabla[aux];
HiCRC = LoCRC ^ HiCRCtab[IndexCRC];
LoCRC = LoCRCtab[IndexCRC];
}
MODtabla[aux++]=HiCRC;
MODtabla[aux++]=LoCRC;
MODtabla[aux]='\0';
nelement=aux-1;
outportb(COM_FE+4,0x08);
pl_invoke=1;
dep=fopen("output.dep","a");
for(aux=0;aux<=nelement;aux++)
{
while(!(inportb(COM_FE+5) & 32));
outportb(COM_FE,MODtabla[aux]);
if(dep!=NULL)
fprintf(dep,"%x.",MODtabla[aux]);
}
while(!(inportb(COM_FE+5) & 32));
pl_invoke=0;
delay(2);
outportb(COM_FE+4,0x0B);
fprintf(dep,"\n");
fclose(dep);
for(aux=0;aux<=255;aux++)
FE_BUF[aux]=0x00;
FE_INDEX=0;
pl_invoke=0;
timeout_plc=9;
while(timeout_plc>=0);
pl_invoke=1;
if(!FE_BUF[0])
return(1);
aux=0;
dep=fopen("busin.dep","a");
HiCRC = 0xFF;
LoCRC = 0xFF;
for (aux=0;aux<FE_INDEX;aux++)
{
IndexCRC = HiCRC ^ FE_BUF[aux];
if(dep!=NULL)
fprintf(dep,"%x.",FE_BUF[aux]);
HiCRC = LoCRC ^ HiCRCtab[IndexCRC];
LoCRC = LoCRCtab[IndexCRC];
}
if(dep!=NULL)
fprintf(dep,"\n");
fclose(dep);
if(!HiCRC&&!LoCRC)
{
if(FE_BUF[1]&0x80)
return(1);
else
return(0);
}
else
return(1);
373
}
/*Rutina empleada para recoger la información más destacada del microprocesador
elegido,la dirección de este ,así como el número de registro de memoria extendido
deseado. Para iniciar el servicio CMS y enviar los datos a otra estación que no sea la
local se le pasa la variable LOCAL. A continuación se describen las solicitudes creadas
por esta función: - petición de la dirección configurada en el esclavo (ha de coincidir con
la dirección del que se ha elegido), -petición del estado del modo escucha , -solicitud de
lectura del estad de los reles definidos (MAN/BYPASS/ALARM), -lectura de los
contadores de las comunicaciones y su posterior inicialización a cero, -obtención de las
características del fabricante almacenadas en memoria, -lectura de los valores de las
entradas analógicas, - lectura de las entradas y salidas digitales y para finalizar lectura
del registro de memoria extendida elegido (esta operación la realiza en cuatro peticiones
por tener definido el protocolo MODBUS un máximo de 256 caracteres por trama).Si no
se recibe respuesta o se recibe una respuesta a excepción se avisa de ello por la
ventana de avisos al usuario si se encuentra en las primeras pantallas del programa o
muestra una ventana de error en el bus si se encuentra en las posteriores pantallas. En
caso de error devuelve un valor '1'. Los datos recopilados se almacenan temporalmente
en el archivo PLCFILE.DAT. En la versión Front-End no se pueden modificar las salidas o
leer los valores analógicos en tiempo real,sólo las estaciones de traajo están autorizadas
para realizar dicha función*/
char encuesta(int plc_adr,int EMR,char local)
{
int inc,plc_mask,plc_data,aux;
char reles=0;
FILE *plcin;
plcin=fopen("plcfile.dat","w");
if(plcin!=NULL)
{
fprintf(plcin,"%d\n",plc_adr);
/*adr*/
if(MOD((uchar)(plc_adr),8,0,8))
goto mesagerror;
plc_data=FE_BUF[6]&0x01;
fprintf(plcin,"%d\n",plc_data); /*listen mode*/
if(MOD((uchar)(plc_adr),7,0,0))
goto mesagerror;
plc_data=FE_BUF[2]&0x07;
plc_mask=1;
for(inc=0;inc<3;inc++)
{
if(plc_data&plc_mask)
{
fprintf(plcin,"%d\n",1); /*reles*/
if(inc<2)
reles=1;
}
else
fprintf(plcin,"%d\n",0);
plc_mask=plc_mask<<1;
}
if(MOD((uchar)(plc_adr),8,0,9))
goto mesagerror;
for(inc=5;inc<=7;inc++)
{
plc_data=FE_BUF[inc]&0xFF;
fprintf(plcin,"%d\n",plc_data); /*rec ,send ,bad & otros*/
}
if(MOD((uchar)(plc_adr),8,0,10)) /*borra contadores*/
goto mesagerror;
if(MOD((uchar)(plc_adr),17,0,0))
374
goto mesagerror;
for(inc=13;inc<=18;inc++)
{
plc_data=FE_BUF[inc]&0xFF;
if(inc<15)
plc_data++;
if((inc==15)||(inc==17))
fprintf(plcin,"%x\n",plc_data);
else
fprintf(plcin,"%d\n",plc_data); /* ram ,rom ,id ,soft ,bus ,bauds*/
}
if(MOD((uchar)(plc_adr),4,0,8))
goto mesagerror;
for(inc=3;inc<=10;inc++)
{
plc_data=FE_BUF[inc]&0xFF;
fprintf(plcin,"%d\n",plc_data); /* AI1..AI8*/
}
for(aux=2;aux>=1;aux--)
{
if(MOD((uchar)(plc_adr),aux,0,0))
{
if(!reles)
goto mesagerror;
else
plc_data=0xFF;
}
plc_data=FE_BUF[3]&0xFF;
plc_mask=0x80;
for(inc=0;inc<8;inc++)
{
if(plc_data&plc_mask)
fprintf(plcin,"%d\n",1); /*DI ,DO*/
else
fprintf(plcin,"%d\n",0);
plc_mask=plc_mask>>1;
}
}
for(aux=0;aux<=192;aux=aux+64)
{
if(MOD((uchar)(plc_adr),20,EMR,aux))
goto mesagerror;
for(inc=6;inc<=132;inc=inc+2)
{
plc_data=FE_BUF[inc]&0xFF;
fprintf(plcin,"%x",plc_data);
}
}
fprintf(plcin,"\n");
fclose(plcin);
if(!local)
{
L7_stat=INICMS;
strcpy(nombre,"plcfile.dat");
}
}
else
{
mesagerror:
fprintf(plcin,"\n");
375
fclose(plcin);
if(pag<2)
{
setfillstyle(SOLID_FILL,0);
bar(332,456,425,472);
setcolor(7);
outtextxy(335,460,"Bus Error");
}
else
message("bus error",0);
return(1);
}
return(0);
}
/*rutina de configuración de los puertos serie empleados,lee los parámetros pasados por
el programa de configuración de inicio y devuelve el tipo de CPU (rápida 486 o lenta 386)
según su velocidad de procesamiento y ejecución de instrucciones*/
int iniconfig()
{
int CPUMODEL;
phy.config.baudrateFE=119200L;
phy.config.baudrateWS=9600L;
cfg=fopen("config.cfg","r");
if(cfg!=NULL)
fscanf(cfg,"%d %d %d %d %d %u %ld %ld",&feplcs,&CPUMODEL,&phy.config.port.WS,
&phy.config.port.FE,&WINDOW,&Local_Address,&phy.config.baudrateWS,
&phy.config.baudrateFE);
fclose(cfg);
COM_WS=(phy.config.port.WS)?0x2F8:0x3F8;
if(feplcs)
{
COM_FE=(phy.config.port.FE)?0x2F8:0x3F8;
com_vecFE=(phy.config.port.FE)?0xB:0xC;
}
com_vecWS=(phy.config.port.WS)?0xB:0xC;
return(CPUMODEL);
}
/*rutina de inicialización de los puertos serie 1 y 2 (direcciones,vectores,velocidad de
transmisión),inhabilita las transmisiones RS485 al arrancar y define lo vectores de las
interrupciones de dichos puertos y del reloj del sistema.*/
void iniserial()
{
uint divisor;
divisor=(uint)(115200L/phy.config.baudrateWS);
outportb(COM_WS+3,0x80);
outportb(COM_WS,divisor&255);
outportb(COM_WS+1,divisor>>8);
outportb(COM_WS+3,3);
outportb(COM_WS+1,1);
outportb(COM_WS+4,0x0B);
outportb(COM_WS+6,0);
if(feplcs)
{
divisor=(uint)(115200L/phy.config.baudrateFE);
outportb(COM_FE+3,0x80);
outportb(COM_FE,divisor&255);
outportb(COM_FE+1,divisor>>8);
outportb(COM_FE+3,3);
outportb(COM_FE+1,1);
outportb(COM_FE+4,0x0B);
376
outportb(COM_FE+6,0);
}
disable();
o_time_vec=getvect(0x1C);
setvect(0x1C,timer0);
o_com_vecWS=getvect(com_vecWS);
setvect(com_vecWS,serial1);
if(feplcs)
{
o_com_vecFE=getvect(com_vecFE);
setvect(com_vecFE,serial2);
}
old_mask=inportb(0x21);
outportb(0x21, old_mask & 0xE7);
enable();
inportb(COM_WS);
if(feplcs)
inportb(COM_FE);
}
/*rutina para restaurar los vectores de las interrupciones serie y del reloj del sistema*/
void finserial()
{
disable();
outportb(COM_WS+4,0x0B);
setvect(com_vecWS,o_com_vecWS);
if(feplcs)
{
outportb(COM_FE+4,0x0B);
setvect(com_vecFE,o_com_vecFE);
}
setvect(0x1C,o_time_vec);
outportb(0x21,old_mask);
enable();
}
/*rutina similar a ENCUESTA pero que realiza la adquisición de datos almacenados en la
SRAM del microcontrolador para visualizar su disposición en esta , el programa solicita
los valores de los contadores de las comunicaciones y de la infomación del fabricante
(en este caso toda la disponible ,no como en la función ENCUESTA que s´lo accede a
parte de dicha información*/
uchar insideRAM(int plc_adr)
{
int aux,plc_data;
char string[25];
if(!MOD((uchar)(plc_adr),8,0,9))
{
settextstyle(SMALL_FONT,HORIZ_DIR,4);
setcolor(15);
for(aux=5;aux<=12;aux++)
{
plc_data=FE_BUF[aux]&0xFF;
itoa(plc_data,string,10);
outtextxy(206-(aux-5)*25,16*20,string);
}
for(aux=13;aux<=14;aux++)
{
plc_data=FE_BUF[aux]&0xFF;
itoa(plc_data,string,10);
outtextxy(206-(aux-13)*25,16*19,string);
}
if(!MOD((uchar)(plc_adr),8,0,10))
377
{
if(!MOD((uchar)(plc_adr),17,0,0))
{
for(aux=3;aux<=10;aux++)
{
plc_data=FE_BUF[aux]&0xFF;
itoa(plc_data,string,10);
outtextxy(206-(aux-3)*25,16*15,string);
}
for(aux=11;aux<=18;aux++)
{
plc_data=FE_BUF[aux]&0xFF;
itoa(plc_data,string,10);
outtextxy(206-(aux-11)*25,16*14,string);
}
for(aux=19;aux<=26;aux++)
{
plc_data=FE_BUF[aux]&0xFF;
itoa(plc_data,string,10);
outtextxy(206-(aux-19)*25,16*13,string);
}
return(0);
}
}
}
return(1);
}
/* P R O G R A M A
P R I N C I P A L*/
int main(void)
{
long l;
one_byte *p;
int EMR=1,token_send=0,oldL7=-1,oldtoken=-1;
char buttonhit=0,busctrl=0,buserror=0,CMService=1,sendfile[25],string[25],FILEopen=0;
int CPUMODEL=486,Localposx,Localposy,aux=0;
int cmd=-1,numplcs=0,plc_adr=0,plc_data,plc_mask;
uint destino=0,destfile=0;
union REGS inregs,outregs;
FILE *TMP,*ROM;
struct contexto
{
uint dest;
int cmd,adr,emr;
}backup;
inigraf();
rata();
CPUMODEL=iniconfig();
iniserial();
reinicia:
reinicio();
FILEopen=0;
buttonhit=0;
busctrl=0;
EMR=1;
CMService=0;
CPU=CPUMODEL;
showred(0,&Localposx,&Localposy,rotation,feplcs,numplcs);
while(OFF==0)
{
espera_ack:
378
if(kbhit())
if(getch()==79)
L7_stat=EXIT;
if(L7_stat==EXIT)
{
if((cmd!=0xF0)&&(cmd!=0xFF)&&(cmd!=0x40))
goto f1;
}
if( heapcheck() == _HEAPCORRUPT )
descarga();
/*NIVEL MAC DE ENTRADA*/
if(MAC_in_level())
{
if(openFILE)
{
strcpy(filename,"vacio");
dl.unitdata.request.dir_dest=dl.unitdata.indication.dir_org;
LLC_interface_envios(CMS,UNNUMBERED,FRMR,0x01);
}
switch(token_stat)
{
case SUCESOR2:
case SUCESOR1:
{
if(token_send>=2)
{
token_send=1;
token_stat=CONFLICTO;
}
}break;
case RECLAMO:
{
token_stat=WAIT;
timer_token=TIMEOUT_response;
}break;
case CONTIENDA:
{
token_stat=WAIT;
timer_token=TIMEOUT_response;
}break;
}
}
if(ma.data.request.activa)
goto correos;
/*NIVEL LLC DE ENTRADA*/
if(LLC_in_level())
{
if(openFILE)
{
strcpy(filename,"vacio");
dl.unitdata.request.dir_dest=dl.unitdata.indication.dir_org;
LLC_interface_envios(CMS,UNNUMBERED,FRMR,0x01);
}
}
if(ma.data.request.activa)
goto correos;
/*NIVEL DE APLICACIÓN DE ENTRADA*/
if(L7_in_level(&numplcs,EMR))
{
seqrec=oldseq;
strcpy(filename,"vacio");
379
dl.connection_flowcontrol.request.dir_dest=dl.data.indication.dir_org;
LLC_interface_envios(CMS,SUPERVISORY,REJ,0x00);
}
if(ma.data.request.activa)
goto correos;
putimage(mx,my,raton,XOR_PUT);
inregs.x.ax = 3;
int86(0x33,&inregs,&outregs);
mx=outregs.x.cx;
my=outregs.x.dx;
putimage(mx,my,raton,XOR_PUT);
if((timer_ack0>=0)||(timer_ack1>=0))
goto espera_ack;
else
{
if(ma.data_status.indication.calidad.estado==0x01)
goto reenvia;
}
if(mouse_stat(&cmd,&numplcs,plc_adr,&EMR,&buttonhit))
showred(0,&Localposx,&Localposy,rotation,feplcs,numplcs);
mouse_ctrl:
if(cmd!=-1)
{
if(pag<2)
{
setfillstyle(SOLID_FILL,0);
bar(332,456,425,472);
outtextxy(335,460,"Local Query");
}
/*Modificación de algunos comandos para adaptarlos a peticiones locales de
recopilación de información de los microprocesadores del bus de campo*/
if(((cmd&240)==0x90)||((cmd&240)==0x30)||((cmd&240)==0xa0)||((L7_stat==REPOSO)&&(rotat
ion>=2)&&(token_stat==TOKENACTV)))
{
aux=cmd&15;
buserror=0;
switch(cmd&240)
{
case 0x10: aux=aux+16;
case 0x00:
{
destino=(TABLA[aux*2]<<8)|(TABLA[aux*2+1]);
if(destino&&(destino!=Local_Address))
{
pag=1;
showred(0,&Localposx,&Localposy,rotation,feplcs,numplcs);
cfg=fopen("station.dat","w");
fclose(cfg);
L7_stat=INIUCS;
strcpy(nombre,"ucsplc.txt");
}
}break;
case 0x20:
{
L7_stat=INICMS;
TMP=fopen("history.dat","r");
ROM=fopen("workst.dat","w");
while(!feof(TMP)&&!feof(ROM))
fprintf(ROM,"%c",getc(TMP));
fclose(ROM);
380
fclose(TMP);
strcpy(nombre,"workst.dat");
}break;
case 0x30:
{
if(insideRAM(plc_adr))
message("Bus error",0);
setcolor(7);
settextstyle(SANS_SERIF_FONT,HORIZ_DIR,1);
outtextxy(561,441,"Set Now");
}break;
case 0x60:
aux=aux+16;
case 0x50:
{
plc_adr=aux+1;
buserror=encuesta(plc_adr,EMR,0);
}break;
case 0x70:
{
buserror=MOD((uchar)(plc_adr),1,0,0);
if(!buserror)
{
plc_data=FE_BUF[3]&0xFF;
plc_mask=1;
for(cmd=0;cmd<aux;cmd++)
plc_mask=plc_mask<<1;
plc_data=plc_data&plc_mask;
if(plc_data)
{
MOD(plc_adr,5,aux,0);
aux=aux*10 + 0x00;
}
else
{
MOD(plc_adr,5,aux,255);
aux=aux*10 + 0x01;
}
TMP=fopen("ucsdo.txt","w");
if(TMP!=NULL)
fprintf(TMP,"%s #%d","command: DO changed to value",aux);
fclose(TMP);
L7_stat=INIUCS;
strcpy(nombre,"ucsdo.txt");
}
cmd=0x70;
}break;
case 0x80:
{
buserror=MOD((uchar)(plc_adr),4,(uchar)(aux),1);
if(!buserror)
{
plc_data=FE_BUF[4]&0xFF;
TMP=fopen("ucsai.txt","w");
if(TMP!=NULL)
fprintf(TMP,"%s #%d","command: AI value is",(aux<<8)|plc_data);
fclose(TMP);
L7_stat=INIUCS;
strcpy(nombre,"ucsai.txt");
}
}break;
381
case 0xa0: aux=aux+16;
case 0x90:
{
if(aux<feplcs)
{
aux++;
if(!pag)
{
EMR=1;
pag=2;
}
plc_adr=aux;
microlocal();
putimage(mx,my,raton,XOR_PUT);
fondo(504,365,517,375,7,7);
setcolor(8);
settextstyle(SMALL_FONT,HORIZ_DIR,4);
itoa(EMR,string,10);
outtextxy(506,366,string);
if(!encuesta(aux,EMR,1))
{
valores();
setcolor(7);
outtextxy(21,8,"Set Now");
}
}
}break;
case 0xE0:
{
buserror=MOD((uchar)(plc_adr),8,0,8);
if(!buserror)
{
plc_data=FE_BUF[6]&0x01;
if(plc_data)
{
buserror=MOD((uchar)(plc_adr),8,0,1);
if(buserror)
goto plcfail;
plc_data=0;
}
else
{
buserror=MOD((uchar)(plc_adr),8,0,4);
if(buserror)
goto plcfail;
plc_data=1;
}
L7_stat=INIUCS;
TMP=fopen("ucsmode.txt","w");
if(TMP!=NULL)
fprintf(TMP,"%s #%d","command: Mode changed to value",plc_data);
fclose(TMP);
strcpy(nombre,"ucsmode.txt");
}
plcfail:;
}break;
case 0xc0:
{
L7_stat=INICMS;
strcpy(nombre,sendfile);
382
}break;
case 0xb0:
{
L7_stat=INIACS;
strcpy(nombre,"offmode.txt");
}break;
}
if(buserror)
{
L7_stat=INIUCS;
strcpy(nombre,"buserr.txt");
buserror=0;
}
if((cmd==0xF0)||(cmd==0xFF)||(cmd==0x40))
token_stat=ESCAPE;
if(destino)
{
dl.unitdata.request.dir_dest=destino;
CPU=CPUMODEL;
cfg=fopen("test.cfg","w");
if(cfg!=NULL)
fprintf(cfg,"%d %s",CPU,"cpu test");
fclose(cfg);
}
}
else
{
if((cmd!=0xF0)&&(cmd!=0x40)&&((cmd&240)!=0x30)&&(cmd!=0xFF)&&((cmd&240)!=0xa0)&&((
cmd&240)!=0x90))
{
TMP=fopen("EPROM.cfg","a");
if(TMP!=NULL)
fprintf(TMP,"%x %d %u %d\n",cmd,plc_adr,destino,EMR);
fclose(TMP);
}
}
if((cmd!=0xF0)&&(cmd!=0xFF)&&(cmd!=0x40))
cmd=-1;
}
if((cmd==0xF0)||(cmd==0x40))
{
if(!rotation||(token_stat==WAIT))
{
disable();
phy.notify.invoke=1;
enable();
cfg=fopen("input.dep","a");
if(cfg!=NULL)
fprintf(cfg,"\nDisconnect Mode\n");
fclose(cfg);
L7_stat=EXIT;
token_stat=NOTOKEN;
L7_ctrl=L7OFF;
}
}
control_ack:
ctrl_ack();
if(ma.data.request.activa)
goto correos;
if((pag<2)&&((oldL7!=L7_stat)||(oldtoken!=token_stat)))
383
{
setfillstyle(SOLID_FILL,0);
bar(332,426,425,456);
setcolor(7);
settextstyle(DEFAULT_FONT,HORIZ_DIR,1);
outtextxy(335,430,tokennom[token_stat]);
outtextxy(335,445,L7nom[L7_stat&0x1F]);
oldL7=L7_stat;
oldtoken=token_stat;
}
/*NIVEL LLC DE SALIDA*/
estado7:
switch(L7_stat)
{
case EXIT:
{
if((cmd==0xF0)&&(token_stat==NOTOKEN))
{
closegraf();
system("word.exe");
inigraf();
TMP=fopen("mesanger.cfg","r");
if(TMP!=NULL)
{
fseek(TMP, 0L, SEEK_END);
if(ftell(TMP)>0L)
{
fseek(TMP, 0L, SEEK_SET);
fscanf(TMP,"%s %u\n",&sendfile,&destfile);
fclose(TMP);
if(!strcmp("exit_program",sendfile))
goto f1;
TMP=fopen("EPROM.cfg","a");
if(TMP!=NULL)
fprintf(TMP,"%x %d %u %d\n",0xC0,0,destfile,EMR);
fclose(TMP);
}
}
fclose(TMP);
cmd=-1;
goto reinicia;
}
else
if((cmd==0x40)&&(token_stat==NOTOKEN))
{
/*Ampliación añadida para acceder al programa de Apoyo OSCILOS ,para chequear el
estado de los puertos y las comunicaciones con el bus de campo ,antes de llamarlo se
desconecta del anillo lógico y cuando regresa de este se ha de incorporar de nuevo*/
finserial();
closegraf();
system("oscilos.exe");
inigraf();
iniserial();
cmd=-1;
goto reinicia;
}
else
if((cmd==0xFF)&&(token_stat==NOTOKEN))
{
message("Listen Mode",1);
384
cmd=-1;
goto reinicia;
}
}break;
case CMSRST:
{
L7_stat=CMSI;
dl.data.request.dir_dest= dl.unitdata.indication.dir_org;
}break;
case CMSDISC:{ L7_stat=REPOSO;
ROM=fopen("ROM.cfg","w");
fclose(ROM);
}break;
case INIUCS:
case INICMS:
case INIACS:
{
if((token_stat==TOKENACTV)&&(rotation>=2))
{
strcpy(filename,"TEST.CFG");
LLC_interface_envios(UCS,TEST,0,0x01);
L7_stat=L7_stat|0x01;
}
}break;
case UCSTEST:
{
if(!ma.data_status.indication.calidad.estado&&(L7_ctrl==L7TEST))
{
L7_ctrl=OFF;
L7_stat=UCSXID;
strcpy(filename,"XID.CFG");
dl.unitdata.request.dir_dest=dl.unitdata.indication.dir_org;
LLC_interface_envios(UCS,XID,0,0x01);
}
}break;
case UCSXID:
{
if(!ma.data_status.indication.calidad.estado&&(L7_ctrl==L7XID))
{
L7_ctrl=OFF;
L7_stat=UCSUI;
for(aux=0;nombre[aux]!='\0';aux++)
filename[aux]=nombre[aux];
filename[aux]='\0';
dl.unitdata.request.dir_dest=dl.unitdata.indication.dir_org;
LLC_interface_envios(UCS,UI,0,0x01);
}
}break;
case UCSUI: L7_stat=REPOSO; break;
case ACSTEST:
{
if(!ma.data_status.indication.calidad.estado&&(L7_ctrl==L7TEST))
{
L7_ctrl=OFF;
L7_stat=ACSXID;
strcpy(filename,"XID.CFG");
dl.unitdata.request.dir_dest=dl.unitdata.indication.dir_org;
LLC_interface_envios(UCS,XID,0,0x01);
}
}break;
385
case ACSXID:
{
if(!ma.data_status.indication.calidad.estado&&(L7_ctrl==L7XID))
{
L7_ctrl=OFF;
L7_stat=ACSAC;
for(aux=0;nombre[aux]!='\0';aux++)
filename[aux]=nombre[aux];
filename[aux]='\0';
dl.data_ack.request.dir_dest=dl.unitdata.indication.dir_org;
LLC_interface_envios(ACS,0,0,0x01);
}
}break;
case ACSAC:
{
if(!ma.data_status.indication.calidad.estado&&(L7_ctrl==L7AC))
{
L7_stat=REPOSO;
L7_ctrl=L7OFF;
}
}break;
case CMSTEST:
{
if(!ma.data_status.indication.calidad.estado&&(L7_ctrl==L7TEST))
{
L7_ctrl=OFF;
L7_stat=CMSUA_SABME;
strcpy(filename,"vacio");
dl.connect.request.dir_dest=dl.unitdata.indication.dir_org;
LLC_interface_envios(CMS,UNNUMBERED,SABME,0x01);
timer_ack0=TIMEOUT_ack0*2;
if(CPU==486)
timer_ack0=timer_ack0*2;
}
}break;
case CMSABME:
{
L7_stat=CMSXID;
strcpy(filename,"XID.CFG");
dl.unitdata.request.dir_dest=dl.unitdata.indication.dir_org;
LLC_interface_envios(UCS,XID,0,0x01);
}break;
case CMSXID:
{
if(!ma.data_status.indication.calidad.estado&&(L7_ctrl==L7XID))
{
L7_ctrl=OFF;
L7_stat=CMSI;
if(!CMService)
filepos=0L;
timer_ack0=TIMEOUT_ack0;
dl.data.request.dir_dest=dl.unitdata.indication.dir_org;
}
}break;
case CMSREJ:
case CMSI:
{
if(!filepos||(filepos!=endfile))
{
for(aux=0;nombre[aux]!='\0';aux++)
386
filename[aux]=nombre[aux];
filename[aux]='\0';
ROM=fopen("ROM.cfg","w");
if(ROM!=NULL)
fprintf(ROM,"%d %u %d %u %u %u %ld %ld %s\n",CPU,dl.unitdata.request.dir_dest,L7_stat,
seqsend, winseq,winXID,filepos,endfile,nombre);
fclose(ROM);
LLC_interface_envios(CMS,INFORMATION,0,0x01);
if(seqrec==winXID)
seqrec=0;
if(L7_stat==CMSREJ)
{
L7_stat=CMSI;
seqrec=0;
}
timer_ack0=TIMEOUT_ack0;
if(CPU==486)
timer_ack0=timer_ack0*2;
if(seqsend==winXID)
{
seqsend=0;
winseq++;
L7_stat=CMSACK;
}
if((filepos&&(filepos==endfile))||(seqsend==winXID))
{
timer_ack0=TIMEOUT_ack0*2;
if(CPU==486)
timer_ack0=timer_ack0*2;
}
}
else
if(filepos&&(filepos==endfile))
{
L7_stat=CMSUA_DISC;
filepos=0L;
endfile=0L;
seqsend=0;
winseq=0;
seqrec=0;
oldseq=0;
CMService=0;
CPU=CPUMODEL;
winXID=WINDOW;
RX_BUF_SIZE = 10000/winXID;
MAC_BUF_SIZE=RX_BUF_SIZE;
MAXDATA= RX_BUF_SIZE-40;
strcpy(filename,"vacio");
dl.disconnect.request.dir_dest=dl.data.request.dir_dest;
LLC_interface_envios(CMS,UNNUMBERED,DISC,0x01);
timer_ack0=TIMEOUT_ack0*2;
}
}break;
}
/*CONTROL DEL TESTIGO*/
token_control:
switch(token_ctrl)
{
case sucesor1:
{
387
if((Local_Address<ma.data.indication.dir_post_org)&&(Local_Address>ma.data.indication.dir_or
g))
{
MAC_token_interface(STABLISH);
busctrl=1;
}
token_ctrl=OFF;
}break;
case sucesor2:
{
MAC_token_interface(STABLISH);
busctrl=1;
token_ctrl=OFF;
}break;
case quiensigue:
{
if(ma.data.indication.dir_post_org==Previous_Address)
{
MAC_token_interface(STABLISH);
busctrl=1;
}
token_ctrl=OFF;
}break;
case contienda:
{
token_stat=CONTIENDA;
token_send=1;
token_ctrl=OFF;
timer_token=TIMEOUT_initoken;
}break;
case paso:
{
Previous_Address = ma.data.indication.dir_org;
dl.unitdata.request.dir_dest=Previous_Address;
strcpy(filename,"TEST.CFG");
LLC_interface_envios(UCS,TEST,0,0x00);
L7_ctrl=L7OFF;
filepos=0L;
endfile=0L;
openFILE=0;
seqsend=0;
winseq=0;
seqrec= 0;
oldseq=0;
buttonhit=0;
L7_stat=REPOSO;
token_stat=TOKENACTV;
FILEopen=0;
if(rotation)
timer_token=TIMEOUT_posesion;
else
timer_token=(TIMEOUT_posesion/20);
rotation++;
if(pag<2)
showred(0,&Localposx,&Localposy,rotation,feplcs,numplcs);
token_ctrl=OFF;
}break;
case escape:
{
if(Next_Address == ma.data.indication.dir_org)
388
{
if(ma.data.indication.dir_dest!=Global_Address)
{
Next_Address = ma.data.indication.dir_post_org;
showred(ma.data.indication.dir_org,&Localposx,&Localposy,rotation,feplcs,numplcs);
}
}
if((token_stat==SUCESOR2)||(token_stat==SUCESOR1)||(token_stat==QUIENSIGUE)||(token_
stat==CONFLICTO))
{
if(Next_Address != ma.data.indication.dir_org)
Next_Address = ma.data.indication.dir_org;
token_send=0;
token_stat=PASO;
timer_token=TIMEOUT_initoken;
}
token_ctrl=OFF;
}break;
}
/* GESTIÓN DEL ESTADO DEL TESTIGO*/
token_st:
switch(token_stat)
{
case ESCAPE:
{
MAC_token_interface(STABLISH);
showred(Local_Address,&Localposx,&Localposy,rotation,feplcs,numplcs);
if((cmd==0xF0)||(cmd==0x40))
token_stat=PASO;
else
token_stat=NOTOKEN;
token_send=0;
timer_token=0;
L7_stat=EXIT;
}
case WAIT:
case NOTOKEN:
{
FILEopen=0;
if(pag<2)
{
etfillstyle(SOLID_FILL,0);
bar(332,456,425,472);
}
if((timer_token<0)&&(L7_stat!=EXIT))
{
set_adrs=0;
rotation=0;
token_stat=RECLAMO;
token_send=1;
MAC_token_interface(TOKEN_ASK);
busctrl=1;
timer_token=TIMEOUT_initoken;
}
}break;
case RECLAMO:
{
if(timer_token<0)
{
if(!token_send)
389
{
token_stat=TOKENACTV;
FILEopen=0;
L7_stat=REPOSO;
L7_ctrl=L7OFF;
openFILE=0;
seqsend=0;
winseq=0;
oldseq=0;
seqrec= 0;
filepos=0L;
endfile=0L;
buttonhit=0;
if(rotation)
timer_token=TIMEOUT_posesion;
else
timer_token=(TIMEOUT_posesion/20);
rotation++;
if(pag<2)
showred(0,&Localposx,&Localposy,rotation,feplcs,numplcs);
}
else
{
MAC_token_interface(TOKEN_ASK);
busctrl=1;
timer_token=TIMEOUT_initoken;
token_send=0;
}
}
}break;
case TOKENACTV:
{
if(timer_token<0)
{
if(rotation>=2)
{
if(L7_stat==REPOSO)
{
acabando:
ROM=fopen("ROM.cfg","w");
fclose(ROM);
ma.data_status.indication.calidad.estado=0;
winXID=WINDOW;
RX_BUF_SIZE = 10000/winXID;
MAC_BUF_SIZE=RX_BUF_SIZE;
MAXDATA= RX_BUF_SIZE-40;
reenvio=0;
filepos=0L;
endfile=0L;
seqsend=0;
seqrec=0;
winseq=0;
oldseq=0;
rotation=1;
}
else
{
ma.data.request.activa=0;
ma.data_status.indication.calidad.estado=0;
if(ma.data.request.org!=NULL)
390
{
ma.data.request.sdu=ma.data.request.org;
for(l=0;ma.data.request.sdu!=NULL;l++)
{
p=ma.data.request.sdu->next;
free(ma.data.request.sdu);
ma.data.request.sdu=p;
}
ma.data.request.status=0;
ma.data.request.org=NULL;
}
if(L7_stat&0x80)
{
ROM=fopen("ROM.cfg","r");
if(ROM!=NULL)
{
fseek(ROM,0L,SEEK_END);
if(ftell(ROM)==0L)
{
fclose(ROM);
ROM=fopen("ROM.cfg","w");
if((ROM!=NULL)&&(L7_stat!=CMSUA_DISC))
fprintf(ROM,"%d %u %d %u %u %u %ld %ld %s\n",CPU,dl.unitdata.request.dir_dest,L7_stat,
seqsend, winseq,winXID,filepos,endfile,nombre);
}
}
fclose(ROM);
L7_stat=REPOSO;
filepos=0L;
endfile=0L;
seqsend=0;
winseq=0;
seqrec=0;
oldseq=0;
winXID=WINDOW;
RX_BUF_SIZE = 10000/winXID;
MAC_BUF_SIZE=RX_BUF_SIZE;
MAXDATA= RX_BUF_SIZE-40;
strcpy(filename,"vacio");
dl.disconnect.request.dir_dest=dl.data.request.dir_dest;
LLC_interface_envios(CMS,UNNUMBERED,DISC,0x01);
rotation=1;
timer_ack0=TIMEOUT_ack0*2;
goto correos;
}
else
if((L7_stat&0x20)||(L7_stat&0x40))
{
ROM=fopen("ROM.cfg","w");
if(ROM!=NULL)
fprintf(ROM,"%d %u %d %u %u %u %ld %ld %s\n",CPU,dl.unitdata.request.dir_dest,L7_stat,
seqsend,winseq,winXID,filepos,endfile,nombre);
fclose(ROM);
L7_stat=REPOSO;
rotation=1;
}
}
}
if(rotation==1)
{
391
token_send=0;
if(Local_Address==32)
{
token_stat=SUCESOR2;
if(Next_Address==0x0001)
token_stat=PASO;
}
else
{
if(Next_Address==(Local_Address+1))
token_stat=PASO;
else
if((Next_Address==Local_Address)||(Next_Address>(Local_Address+1)))
token_stat=SUCESOR1;
else
if(Next_Address<(Local_Address))
token_stat=SUCESOR2;
}
}
}
else
{
if(!FILEopen)
{
FILEopen=1;
ROM=fopen("ROM.cfg","r");
if(ROM!=NULL)
{
fseek(ROM,0L,SEEK_END);
if(ftell(ROM)>0L)
{
fseek(ROM,0L,SEEK_SET);
if(ROM!=NULL)
fscanf(ROM,"%d %u %d %u %u %u %ld %ld %s\n",&CPU,&destino,&L7_stat,&seqsend,
&winseq,&winXID,&filepos,&endfile,nombre);
fclose(ROM);
if(L7_stat!=REPOSO)
{
if(L7_stat&0x80)
{
if(filepos==0L)
{
L7_stat=INICMS;
endfile=0L;
seqsend=0;
winseq=0;
seqrec=0;
oldseq=0;
dl.unitdata.request.dir_dest=destino;
}
else
{
L7_stat=INICMS;
CMService=1;
dl.unitdata.request.dir_dest=destino;
dl.data.request.dir_dest=destino;
}
ma.data_status.indication.calidad.estado=0;
L7_ctrl=L7OFF;
}
392
else
{
if(L7_stat&0x20)
L7_stat=INIUCS;
else
if(L7_stat&0x40)
L7_stat=INIACS;
dl.unitdata.request.dir_dest=destino;
ma.data_status.indication.calidad.estado=0;
L7_ctrl=L7OFF;
}
}
ROM=fopen("ROM.cfg","w");
}
}
fclose(ROM);
}
if((L7_stat==REPOSO)&&(cmd==-1))
{
ROM=fopen("EPROM.cfg","r");
TMP=fopen("SRAM.cfg","w");
if((ROM!=NULL)&&(TMP!=NULL))
{
fseek(ROM,0L,SEEK_END);
if(ftell(ROM)>0L)
{
fseek(ROM,0L,SEEK_SET);
aux=0;
while(!feof(ROM)&&!feof(TMP))
{
if(!feof(ROM))
fscanf(ROM,"%x %d %u %d\n",&backup.cmd,&backup.adr,&backup.dest,&backup.emr);
if(!aux)
{
aux=1;
cmd=backup.cmd;
if(backup.adr>0)
plc_adr=backup.adr;
destino=backup.dest;
EMR=backup.emr;
}
else
{
if(!feof(ROM)&&!feof(TMP))
fprintf(TMP,"%x %d %u %d\n",backup.cmd,backup.adr,backup.dest,backup.emr);
}
}
fclose(ROM);
fclose(TMP);
ROM=fopen("EPROM.cfg","w");
TMP=fopen("SRAM.cfg","r");
if((ROM!=NULL)&&(TMP!=NULL))
{
while(!feof(TMP)&&!feof(ROM))
{
aux=getc(TMP);
if(!feof(TMP))
putc(aux,ROM);
}
}
393
}
}
fclose(TMP);
fclose(ROM);
}
if((L7_stat==REPOSO)&&(cmd==-1))
{
timer_token=0;
goto acabando;
}
}
}break;
case SUCESOR1:
{
if((timer_token<0)&&(token_send<2))
{
MAC_token_interface(SUCESS1);
timer_token=TIMEOUT_initoken;
token_send++;
}
else
if(token_send>=2)
{
token_stat=PASO;
token_send=0;
}
}break;
case PASO:
{
if(Next_Address==Global_Address)
token_stat=QUIENSIGUE;
else
{
if((timer_token<0)&&(token_send<2))
{
MAC_token_interface(TOKEN_PASS);
set_adrs=1;
timer_token=TIMEOUT_initoken;
token_send++;
}
else
if(token_send>=2)
{
token_send=0;
token_stat=QUIENSIGUE;
if(Next_Address!=Local_Address)
showred(Next_Address,&Localposx,&Localposy,rotation,feplcs,numplcs);
}
}
}break;
case QUIENSIGUE:
{
if((timer_token<0)&&(token_send<2))
{
MAC_token_interface(WHO_NEXT);
timer_token=TIMEOUT_initoken;
token_send++;
}
else
if(token_send>=2)
{
394
token_send=0;
token_stat=SUCESOR2;
}
}break;
case SUCESOR2:
{
if((timer_token<0)&&(token_send<2))
{
MAC_token_interface(SUCESS2);
timer_token=TIMEOUT_initoken;
token_send++;
}
else
if(token_send>=2)
{
token_stat=NOTOKEN;
if(L7_stat!=EXIT)
L7_stat=REPOSO;
rotation=0;
token_send=0;
timer_token=TIMEOUT_response;
}
}break;
case CONFLICTO:
{
if(timer_token<0)
{
if(!token_send)
{
token_send=0;
token_stat=PASO;
}
else
{
MAC_token_interface(BATTLE);
timer_token=TIMEOUT_initoken*2;
token_send=0;
}
}
}break;
case CONTIENDA:
{
if(timer_token<0)
{
if(!token_send)
{
token_stat=NOTOKEN;
L7_stat=REPOSO;
timer_token=TIMEOUT_response;
}
else
{
MAC_token_interface(STABLISH);
busctrl=1;
timer_token=TIMEOUT_initoken;
token_stat=CONTIENDA;
token_send=0;
}
}
}break;
395
}
correos:
/*^NIVEL LLC DE SALIDA*/
LLC_out();
if(ma.data_status.indication.activa&&!ma.data_status.indication.calidad.estado)
ma.data_status.indication.activa=0;
/*NIVEL MAC DE SALIDA*/
if(phy.unitdata.request)
{
phy.unitdata.request=0;
if(busctrl)
{
delay((int)(Local_Address)*50);
busctrl=0;
}
if(phy.unitdata.indication)
goto dejaya;
reenvia:
outportb(COM_WS+4,0x08);
phy.notify.invoke=1;
ma.data.request.sdu=ma.data.request.org;
for(l=0;ma.data.request.sdu!=NULL;l++)
{
if(!phy.unitdata.indication)
inportb(COM_WS);
else
goto dejaya;
timer_envio=TIMEOUT_envio;
while(!(inportb(COM_WS+5) & 32));
outportb(COM_WS,ma.data.request.sdu->byte);
if( phy.unitdata.indication||(timer_envio<0))
goto dejaya;
ma.data.request.sdu=ma.data.request.sdu->next;
}
dejaya:
while(!(inportb(COM_WS+5) & 32));
phy.notify.invoke=0;
if(!ma.data_status.indication.calidad.estado)
{
reenvio=0;
if(timer_ack0<0)
timer_ack0=TIMEOUT_ack0;
if(ma.data.request.org!=NULL)
{
ma.data.request.sdu=ma.data.request.org;
for(l=0;ma.data.request.sdu!=NULL;l++)
{
p=ma.data.request.sdu->next;
free(ma.data.request.sdu);
ma.data.request.sdu=p;
}
ma.data.request.status=0;
ma.data.request.org=NULL;
}
}
else
if(ma.data_status.indication.calidad.estado==0x01)
{
reenvio++;
if(reenvio>=3)
396
{
reenvio=0;
if(ma.data.request.org!=NULL)
{
ma.data.request.sdu=ma.data.request.org;
for(l=0;ma.data.request.sdu!=NULL;l++)
{
p=ma.data.request.sdu->next;
free(ma.data.request.sdu);
ma.data.request.sdu=p;
}
ma.data.request.status=0;
ma.data.request.org=NULL;
}
dl.disconnect.indication.dir_org=Local_Address;
dl.disconnect.indication.motivo = 0x02;
dl.disconnect.indication.activa=1;
ma.data_status.indication.calidad.estado=0x00;
}
else
{
if(timer_ack0<0)
timer_ack0=TIMEOUT_ack0;
}
}
delay(1);
outportb(COM_WS+4,0x0B);
}
}
f1:
free(raton);
nosound();
p=NULL;
free(p);
finserial();
closegraf();
return(0);
}
/* F I N
D E
P R O G R A
397
M
A*/
2.3.2.2 -Diagramas de flujo del programa
Se pueden aplicar los mismos diagramas de flujo que la versión Workstation ,tanto de gestión
del testigo como de los servicios LLC prestados y el esquema global del programa. La única
diferencia existente entre ambas versiones es que en esta se provee de las rutinas MODBUS
necesarias para solicitar información a los microcontroladores ,en vez de acudir a la base de
datos propia.
398
2.4 -Manuales de los programas
Este apartado pretende familiarizar al usuario con el software proporcionado.Se divide en dos
partes: la primera dedicada al programa de las Workstations y la segunda dedicada a los FrontEnds. A continuación se explica cada ventana del programa en que consiste, las dos primeras
ventanas (presentación y configuración) y la ventana del editor son comunes para ambas
partes. Para instalar el programa de red y todos sus componentes ,basta con ejecutar el
comando A:\INSTALL . Una vez instalado podremos pasar a ejecutar una de las dos versiones
disponibles.
2.4.1 -Manual del programa de las Workstations (Estaciones de
Trabajo)
Al ejecutar el archivo SRM.BAT ,con el que se inician los programas de la red local, aparece un
mensaje para elegir el tipo de estación a emplear . El usuario decide que tipo de estación va a
configurar,por defecto y pasado un límite preestablecido de tiempo se selecciona por defecto la
primera opción (Workstation).
PRESENTACION (PRESENTA) : Es una pantalla de inicio y presentación del software creado
para la red local. Basta con pulsar el botón derecho del ratón o una tecla para iniciar el
programa de configuración de la estación.
CONFIGURACIÓN DE LA ESTACIÓN (COMSETUP) : Permite al usuario especificar algunos
de los parámetros importantes de las comunicaciones. Algunos de ellos como el puerto serie
empleado para las comunicaciones por el bus de campo y la red local son fijos. Esta pantalla
varía según la estación se quiera configurar como Workstation o como Front-End. En el caso
de que una estación esté configurada como Front-End el nº de plcs es distinto a cero ,por lo
que se deduce que dicha estación estará conectada mediante un bus de campo con uno o
varios procesadores locales. Sólo las estaciones Front-End permiten cambiar la velocidad de
transmisión empleada en el bus de campo.
El campo Frame window varía automáticamente según el tamaño de los buffers empleados
para recibir y transmitir datos.El buffer de salida ha de ser menor al de entrada ya que no
cuenta con los bytes de protocolo incluidos en la trama, por lo que la cantidad real de datos
transmitidos son la cantidad indicada más los bytes de protocolo.Los buffers se pueden
dimensionar según las necesidades pero han de tenerse en cuenta las interrelaciones entre las
estaciones.La velocidad de transmisión está configurada por defecto al máximo valor 115200
Baudios ,si se varía este parametro se ha de establecer el mismo en las demás estaciones.La
dirección de la estación puede estar comprendida entre 1 y 32 ,asimismo el número de
procesadores locales ha de estar entre 0 y 32 según la versión instalada.
Para modificar los parametros se puede realizar mediante el ratón pulsando el botón izquierdo
en las flechas de incremento/decremento o mediante el tabulador para pasar de un parámetro
a otro y las teclas '+' y '-' para variar los valores. En el caso de la dirección de la estación ,para
aumentar o disminuir más rápido pulsar la tecla ALT y la tecla correspondiente de subir '+' o
bajar '-'.Para iniciar el programa de red local basta con pulsar una tecla no definida o el botón
derecho del ratón.
399
PROGRAMA PRINCIPAL (STATION):
PÁGINA DE INICIO: Esta página visualiza el estado de la red local, en la parte superior
podremos observar las estaciones tanto Workstations como Front-Ends que estén conectadas
a la red y mediante un simple código de colores su estado: azul brillante señaliza que es la
propia estación local ,azul oscuro simboliza otra estación distinta a la local, gris cuando la
estación local no tiene permiso todavía para solicitar información a dicha estación y negro
cuando dicha estación está en trámites de salir o ya salió del anillo lógico (si salió de una forma
correcta desaparecerá al siguiente paso de testigo). Podemos acceder a la información de la
estación deseada pulsando con el botón izquierdo del ratón encima del icono de esta ,las
direcciones de las estaciones no están directamente relacionadas con su posición en el
esquema. En la parte central se recoge la principal información de la estación que esté activa
,al inicio se refiere a la propia estación local: tipo de CPU (nos informa de si la máquina es
rápida 486 o lenta 386 en la ejecución del código del programa), tamaño de la memoria RAM
,versión del programa instalado, dirección de la estación, puerto de comunicaciones empleado
por la red ,ventana de transmisión empleada ,velocidad de transmisión ,tipo de red local , tipo
de comunicaciones y transmisión empleados y por último el número de procesadores locales a
los que está conectado (en este caso Workstation, siempre es 0). Por último tenemos una
ventana en la parte inferior que nos informa del estado del token ,el estado de la estación
(servicios proporcionados) y unos mensajes de control y/o información de interés y para
finalizar queda un botón en la parte inferior derecha con el que accedemos al editor de textos
(para ello la estación inicia un protocolo de desconexión lógica de la red ,por lo que al salir del
editor la estación tendrá que volverse a unir al anillo lógico.
Cada vez que solicitemos una determinada información aparecerá un mensaje "Local Query"
que támbien aparece cuando recibimos ordenes externas.Para abandonar el programa
pulsaremos el botón izquierdo del ratón encima del recuadro de "Station Access" y cuando
estemos en el editor repetimos esta misma acción sobre el botón que pone "EXIT". Si
deseamos limpiar la pantalla (por ejemplo después de aparecer un mensaje de aviso) basta
con pulsar el botón derecho del ratón. Esta operación sólo se puede realizar cuando este
presente la visualización de la red global ,no en las siguientes páginas ;ocurre lo mismo en la
versión de los Front-Ends.
PÁGINA DEL EDITOR: Esta pantalla nos muestra un pequeño editor de textos,en la ventana
principal podemos escribir un documento de texto que cómo máximo puede alcanzar la señal
dibujada en el borde inferior derecho (|>). En la parte superior derecha se nos indica la hora y
fecha actualizadas mientras que en la parte inferior nos muestra el nombre del archivo activo y
su extensión en bytes. Dispone de tres botones de comandos: salida del programa principal
de comunicaciones (EXIT) ,apertura de un fichero de texto (OPEN) y envio del fichero de
texto activo (SEND). Para escribir basta con pulsar las teclas de ordenador y para borrar un
carácter la tecla RETROCESO. Para salir del editor basta con pulsar la tecla ESC.Por defecto
arranca con el documento WORD.TXT que se inicializa siempre al llamar al editor. Las
ventanas de avisos aparecen para confirmar comandos seleccionados o al finalizar la sesión
del editor.
PÁGINA DEL BUSCADOR DE ARCHIVOS: Permite al usuario buscar un archivo de texto para
modificar y/o enviar a otra estación.Para pasar página pulsar la tecla ENTER.Si el archivo no
existe o no tiene la terminación .TXT solicita de nuevo otro nombre, si tecleamos el nombre del
archivo WORD.TXT que por defecto aparece en el editor ello conlleva la actualización y pérdida
del texto que se hubiese iniciado.Si el archivo de texto es demasiado extenso avisará de tal
evento y se colocará al inicio ,por el contrario aparecerá el archivo solicitado y se situará al final
de este.Al salir del editor para regresar al programa principal de comunicaciones se nos pedirá
si deseamos enviar el documento activo y si deseamos guardarlo. Esta última opción ha de ser
respondida afirmativamente si el fichero activo ha sido modificado verdaderamente. Si lo único
que se ha realizado es la carga de un archivo de texto teclear 'N' como respuesta a dicha
pregunta.
400
PÁGINA DE EXPLORACIÓN DEL BUS: Si solicitamos la información de una determinada
estación y resulta que esta actua como Front-End podremos ver el bus de campo al que se
encuentra conectada. La pantalla principal cambia y aparece la información general de la
estación solicitada ,además vemos que el botón de la parte inferior derecha ha cambiado y
ahora se refiere a "Listen Mode" ,nos servirá en caso de querer que dicha estación se
desconecte lógicamente del anillo de manera remota. La estación que reciba tal mandato
visualizará un mensaje de aviso y si desea volver a conectarse sólo hay que volver a pulsar
una tecla desde dicho terminal ,la opción de hacerlo remotamente no ha sido programada. Para
acceder a la información de cada procesador de la estación seleccionada basta con pulsar
encima el botón izquierdo del ratón e inmediatamente se pasará a la página que se explica más
adelante. Si no deseamos solicitar más datos de la estación elegida pulsando el botón derecho
del ratón volvemos a la pantalla inicial de la propia estación.
PÁGINA DE EXPLORACIÓN DEL CONTROLADOR SELECCIONADO: Cuando accedemos a
un procesador local aparece esta pantalla con la información principal recogida de este. El
botón superior de la parte izquierda ( "Set Now" )nos permite actualizar la información
visualizada, mientras que el de la parte derecha ( "Listen Mode" )nos permite hacer pasar a
dicho controlador a un modo de "solo escucha" o sacarle de dicho estado. La información que
refleja esta página es la siguiente :
- (ID) identificación del procesador local .
- (ADR) dirección configurada en el procesador.
- (Listen Mode) a ' 0' si no se encuentra en modo de "solo escucha" es modificable por el
usuario.
- (DI) entradas digitales.
- (DO) salidas digitales ,modificable por el usuario basta con pulsar el botón izquierdo encima
de la salida digital deseada.
- (AI) entradas analógicas ,pulsando el botón izquierdo del ratón encima del simbolo ' ^ '
pasaremos a una página de visualización continua de dicha señal.
- (Status Relays) Relés de estados ,por defecto nos avisan de los siguientes eventos :
manual/automático , bypass (señal puenteada) y alarma por manipulación del chasis del
armario donde se halle dicho equipo.
- (Extended Memory Registers) Registros de memoria extendida ,en total son 12 registros de
256 bytes cada uno. Pulsando sobre el icono ' > ' accedemos consecutivamente a estos ,al
llegar al último pasa directamente al primero si pulsamos otra vez. La actualización de los
registros de memoria extendida lleva consigo una actualización de todos los datos visualizados.
en la barra inferior se muestra el registro de memoria extendida actual.
- (ROM) Capacidad de la memoria de programa externa en Kb.
- (RAM) Capacidad de la memoria de datos externa en Kb.
- (SOFTWARE VERSION) Version del programa Modbus instalado en el procesador local.
- (BUS TYPE) Tipo de bus ,en nuestro caso Modbus = 39
- (BAUDRATE) Velocidad de transmisión de los datos por el bus.
- (FRAMES RECEIVED) Nº de solicitudes recibidas.
- (FRAMES TRANSMITED) Nº de respuestas enviadas.
- (FRAMES ACCEPTED) Nº de mensajes correctos recibidos.
Para volver a la página anterior de visualización de la red local y el bus de campo ,bastará con
pulsar el botón derecho del ratón. Para saber si las peticiones solicitadas están siendo
atendidas los rótulos correspondientes se aparecerán en verde ,excepto en solicitudes de
lectura de registros de memoria extendida que se verá incrementado el número que aparece en
la barra inferior de dicha ventana y en las entradas analógicas que pasaremos a la página
correspondiente.
401
PáGINA DE HISTóRICOS DE LA SEñAL ANALóGICA SELECCIONADA: En esta pantalla
podremos ver la información actualizada de una determinada señal analógica que hayamos
seleccionado previamente. El rango de dicha señal estará comprendido entre 0 y 5 V que
posee el convertidor A/D del procesador local (en nuestro caso el equipo es un SAB80c537).En
color amarillo se marca el valor base de 0 V y en color verde se muestra la señal analógica
leída. En la parte inferior izquierda nos muestra la dirección del procesador local y la entrada
analógica seleccionada ,mientras que en la parte derecha tenemos un botón que nos permite
grabar los valores leídos en un intervalo en un documento de historicos y que posteriormente
podremos imprimir o guardar en disquette ,basta con pulsar el botón izquierdo del ratón para
activar o desactivar esta operación. Si deseamos volver a la página anterior de información
general del procesador basta con pulsar el botón derecho del ratón. Cuando regresemos a la
anterior página se enviará una solicitud de actualización de datos del procesador y el número
de registros de memoria extendida se inicializará a 1.
MENSAJES DE ERRORES Y AVISOS: El programa avisa con mensajes de errores
detectados o estados de excepción ,estos son los mensajes visualizados:
-"BUS ERROR" ,aparece cuando solicitemos datos de un procesador concreto al Front-End
respectivo y este no pueda comunicarse o reciba una respuesta incorrecta.
-"LISTEN MODE" nos avisa que otra estación nos mandó salir del anillo lógico.
Los anteriores mensajes permanecen en pantalla hasta que el usuario no limpie la pantalla o
pase a otra ,por considerarse de gran importancia su reconocimiento por este.
-"EMPTY FILE" si queremos enviar un fichero vacio o inexistente.
-"FILE DISC" el programa avisa que no se envia el archivo por culpa del error mencionado
anteriormente.
-"MAC OV" y "LLC OV" aparecen si se solicita enviar una trama cuando existe otra en progreso
de realizar la misma función.
-"EXT. WARNING" surge cuando la estación recibe una solicitud de tipo SIN CONEXIóN y SIN
CONFIRMACIóN.
-"EXT. COMMAND" se refiere a la recepción de una solicitud de tipo SIN CONEXIóN pero CON
CONFIRMACIóN.
-"EXT. FILE" nos avisa de la recepción de un archivo empleando el tipo CON CONEXIÓN y
CON CONFIRMACIÓN.
-"EXT. QUERY" informa de la recepción de una solicitud de información externa.
-"LOCAL RESET" avisa al usuario que se va a realizar un reinicio del servicio en curso.
-"LOCAL DISC" informa al usuario que el servicio que se estaba atendiendo va a abandonarse
por detectar algún fallo grave.
-"LOCAL QUERY" petición de una nueva orden o servicio.
402
2.4.2 -Manual del programa de los Front-Ends (Estaciones de
Enlace)
Previamente a arrancar el programa de red ,se ha de cargar el programa MODBUS.S51 en la
memoria los microcontroladores SAB80C537 ,mediante el kit de desarrollo de ALTAIR
(disponible en un disquette de 1'44 Mbytes que se adjunta con el programa de red). Para más
información referirse al apartado 2.5 Programas de Ayuda y Apoyo.
PROGRAMA PRINCIPAL (FRONTEND):
PÁGINA DE INICIO: Muy similar a la de las Workstations, permite visualizar el estado de la red
en la parte superior de la pantalla y emplea el mismo código de colores que la anterior ,támbien
permite acceder a la información general de otras estaciones. La parte central támbien tiene las
mismas carácterísticas que la de las Workstations. Así como la ventana de estados y mensajes
.Lo más diferenciador es que aparece ya el bus de campo al que está conectado este equipo
,en el se ven los procesadores locales (no existe ningún código de color establecido) y desde el
que se accede a la información de cada procesador seleccionado (el orden de aparición se
corresponde a la dirección establecida en cada uno de ellos).El mesaje correspondiente a cada
solicitud es el mismo que con las Workstations.El botón de la parte inferior derecha tiene la
misma misión que en la de la anterior (acceso al editor de textos y/o envios de documentos de
texto) mientras que el de la izquierda nos posibilita ejecutar otro programa denominado
OSCILOS.EXE para testear los procesadores del bus de campo en caso de necesitarse (esta
opción sólo en casos extremos en que se detecten sucesivos fallos en el bus de campo ,antes
de llamarlo se efectuará un protocolo de desconexión lógica de la red).Para más información
sobre dicho programa de ayuda ver el apartado 2.5 de esta memória de cálculo.
La función de limpiado de la pantalla es la misma que en la anterior versión para Workstation.
PÁGINA DEL PROGRAMA SECUNDARIO DE TEST DEL BUS DE CAMPO: permite testear
el estado de los procesadores de campo requiere conocimientos sobre el protocolo MODBUS
,para ver más especificaciones acudir al apartado 2.5 Programas de Ayuda y Apoyo. Para
información sobre las teclas de función durante la ejecución pulsar F1. En la pantalla principal
se puede ver el nivel de la señal RTS del puerto serie activo (dicha señal se emplea para
habilitar los transmisores RS485).También podemos ver los puertos seleccionados para las
comunicaciones y la velocidad de transmisión de los datos; estos parametros vienen
configurados por defecto adaptados a los programas de las comunicaciones. La ventana
superior se emplea para visualizar los datos recibidos. El programa permite también grabar los
datos recibidos en un fichero de texto ,que se puede leer desde el mismo programa o borrarlo
si así desea el usuairo .Además se permite al usuario modificar la luminosidad del panel
visualizador de datos recibidos.
PÁGINA DE EXPLORACIÓN DEL CONTROLADOR SELECCIONADO: Nos proporciona toda
la información recogida del procesador local ,en esta versión no se pueden mandar todas las
solicitudes de la versión Workstation al procesador local , únicamente están activos el botón de
actualización ( "Set Now" ) y el de avance de registros de memoria extendida ( ' >' ). Si
deseamos volver a la página anterior basta con pulsar el botón derecho del ratón.
A diferencia de la anterior versión ,se permite acceder a la memoria SRAM del
procesador,basta con pulsar el botón izquierdo del ratón encima del texto en resaltado en verde
"SRAM 65256",así accedemos a la página que se explica a continuación.
PÁGINA DE CARÁCTERÍSTICAS MODBUS DEL CONTROLADOR SELECCIONADO:
Permite visualizar los contadores de las comunicaciones (MODBUS STATUS AREA) y la zona
de memoria donde se guardan las especificaciones y características principales del controlador
así como los parámetros de configración de este (dirección y velocidad de transmisión).El
botón de la parte inferior derecha se emplea para actualizar las variables que aparecen en
pantalla (*Nota: después de cada lectura de contadores estos se resetean). Si deseamos volver
403
a la página anterior basta con pulsar el botón derecho del ratón. Para más detalles sobre las
posiciones de memoria referidas consultar la tabla siguiente:
MENSAJES DE ERRORES Y AVISOS: Son los mismos que para la versión Workstation pero
incluyen además en la ventana de control y avisos el mensaje "Bus Error" advirtiendo al usuario
de un fallo en las comunicaciones ,bien por falta de respuesta ,trama dañada o por respuesta
devuelta a una excepción Modbus. Para más información se puede revisar el documento de
texto "OUTPUT.DEP" donde se guardan las tramas de solicitudes a los procesadores y
"BUSIN.DEP" que es donde se guardan las respuestas de estos mismos.
2.4.3 -Listado de ficheros empleados por los programas
A fin de llevar a cabo una buena depuración de los programas de la red local, se han
establecido unos ficheros de ayuda o soporte al programador y que al usuario con
conocimientos de programación le pueden resultar útiles; estos son los ficheros de texto de los
que se habla:
- PLCFILE.DAT fichero temporal donde se almacenan los datos recogidos del procesador local
actual.
- RAM.IMG fichero temporal con los datos de los registros de memoria extendida del
procesador local actual.
-INPUT.DEP fichero de texto donde se almacenan todas las tramas recibidas desde que se
carga el programa en memoria.
-TEST.CFG fichero donde se guarda un mensaje de test con el tipo de CPU (rápida 486 o lenta
386) asignado a la estación.
-XID.CFG fichero que contiene el mensaje con la longitud de la ventana de transmisión
empleada por la estación.
-ACS.CFG fichero donde se almacena temporalmente la copia de otro mensaje recibido en tipo
con reconocimiento y sin conexión.
-EPROM.CFG fichero que almacena los comandos solicitados por el usuario.
-SRAM.CFG fichero de apoyo para modificaciones del anterior.
-RAM.CFG fichero que almacena la última operación realizada por la estación que se quedo sin
finalizar en el modo CMS (con conexión) durante la recepción de un fichero de texto.
-COPIA.CFG fichero de apoyo del anterior para modificaciones.
-ROM.CFG fichero que almacena la última operación realizada por la estación ,que se quedo
sin finalizar durante la transmisión. No necesita fichero de apoyo para modificaciones por que
no necesita realizar ninguna.
-WORKST.DAT fichero donde se almacena temporalmente la información local
estaciones de la red para transmitirla a otras.
de las
- STATION.DAT contiene la información recogida de otra estación.
-HISTORY.DAT fichero creado por cada estación al arrancar el programa de red con los datos
principales de esta.
404
-OUTPUT.DEP fichero donde se copian los mensajes Modbus enviados a través del bus de
campo.
-BUSIN.DEP fichero donde se guarda una copia de los mensajes recibidos por el bus de
campo.
-CONFIG.CFG fichero de configuración de la estación creado al inicio de la instalación del
programa de red local por el programa COMSETUP.EXE.
-HISTORIC.DAT fichero temporal donde se guardan los valores de las entradas analógicas
seleccionadas para crear una base de históricos. Puede ser impreso o guardado en disquet por
el programa GRABA.EXE
-UCSPLC.TXT fichero con el mensaje de petición de datos de la estación seleccionada.
-ACSPLC.TXT fichero de texto con la solicitud de información general del procesador local
seleccionado.
-ACSDO.TXT fichero con el mensaje de solicitud de cambio de salidas digitales
-ACSAI.TXT fichero con el mensaje de solicitud de lectura continua del valor analógico
seleccionado.
-ACSMODE.TXT fichero que contiene la solicitud de cambio de modo "solo escucha" para los
procesadores locales.
-OFFMODE.TXT fichero con el mensaje de abandonar el anillo lógico para otra estación.
-BUSERR.TXT fichero con el mensaje de error encontrado en el bus de campo para informar a
la estación solicitante.
-MESANGER.CFG fichero de texto que almacena la petición creada en el programa
WORD.EXE para envío de archivos de texto.
-INPUT.DAT fichero de texto empleado por el programa OSCILOS.EXE para almacenar los
datos recibidos en formato ASCII.
-DATOSIN.DEP fichero de datos recibidos por el programa OSCILOS.EXE en formato
hexadecimal.
-ENTRADA.DEP fichero de texto con los datos recibidos por el programa analizador de la red
ANALIZA.EXE.
-WORD.TXT fichero de texto temporal empleado por el programa WORD.EXE para escribir un
documento de texto.
-TEXTO fichero de texto temporal empleado como copia para modificaciones por el programa
WORD.EXE.
Todos estos ficheros pueden ser modificados por el usuario incluso ser borrados por que se
crean de nuevo cada vez que se arranque el programa, sólo son importantes para depuración
y si deseamos guardar los datos recogidos de otras estaciones.
405
2.5 -Programas de ayuda y apoyo
Esta sección viene dividida en dos partes: por una parte tenemos los programas de apoyo que
emplea el software de la red local (tanto Workstations como Front-Ends) y por la otra están
unos programas desarrollados para la depuración del software empleado en este proyecto y
para comprobar el estado de los puertos serie de los PCs y los microcontroladores ,así como
otras tareas más específicas. Sólo se explica de manera general como actuan ,el código de
programa en Turbo C y en lenguaje ensamblador para el 8051 y su família se incluyen al final
de este apartado. Además se incluye unos breves pasos a realizar para cargar en la memoria
de los microcontroladores SAB80C537 el programa de comunicaciones MODBUS.S51
,empleando el kit de desarrollo de Altair.
MANUAL DE AYUDA PARA ALTAIR
Para cargar el programa MODBUS.S51 en la memoria de los microcontroladores se han de
seguir los siguientes pasos:
1 - Conecte el puerto serie 1 del PC (habitualmente el de 9 pines) con el puerto serie 1 del
microcontrolador (el más cercano de 9 pines a la CPU) mediante un cable NULL MODEM
(pines 2 unidos a los pines 3 del conector contrario y los pines 5 con su homónimo en el otro
conector).
2 - Ejecute el programa EDITOR51.EXE disponible en el directorio A:\ALTAIR
3 - Pulse las teclas ALT+ A Y luego pulse la tecla A ,seguidamente elija el programa
MODBUS.S51
4 - Una vez tenga en pantalla el archivo mencionado ,pulse la tecla ALT+U y después la tecla J
5 - El programa a continuación compilará el archivo y al finalizar le preguntará si desea acceder
al terminal de comunicaciones ,pulse la tecla Y .
6 - Realizado el paso anterior el archivo será cargado en la memoria del microcontrolador,para
cerciorarse de que se ha hecho de forma correcta ,el led de la placa de este ha de encenderse
y apargarse en un breve espacio de tiempo ,por el contrario si está intermitente habrá que
realizar otra vez el paso 4. Para volver al sistema hay que pulsar dos veces la tecla ESC.
Posibles problemas que pueden surgir:
- El archivo MODBUS.S51 tenga definidas las librerias REG517.DEF y CONFIG.DEF en un
directorio erróneo. Modificque el directorio definido en el programa por el cual se hallen
realmente.
- Al transferir el programa al microcontrolador (acceso al terminal de comunicaciones) el
programa de desarrollo Altair notifique que no se pudo enviar. Realice un reset con el pulsador
de color BLANCO de la placa y intente el paso 4 otra vez. Si no obtiene ningún resultado
acceda al menu de configuración de dicho programa de desarrollo pulsando las teclas ALT+U
y seguidamente la tecla 0. Cambie el puerto serie de transmisión (COM1 o COM2) pulsando la
tecla S seguida de la tecla de flecha arriba o abajo y para aceptar pulse la tecla INTRO.
406
PROGRAMAS DE APOYO
- OSCILOS.C
Este programa permite de una manera sencilla enviar órdenes a los microprocesadores
SAB80C537 que contengan el programa MODBUS.S51 instalado. Las tareas que realiza son
las siguientes:
- Envio de tramas de datos (pulsando F2 permite entrar los caracteres de la trama
(comprendidos entre [0..255]) seguidos por comas ,excepto el byte final que ha de ser seguido
por el carácter ENTER).
- Cambio del tono de luminosidad del panel visualizador pulsando F8.
- Recepción y visualización de bytes.
- Grabación de bytes recibidos en un fichero de texto (pulsar F9),para visualizarlo pulse F10 y
si desea borrarlo pulse F11.
- Cambio del nivel de la señal RTS (pulsar F7) .
- Intercambio del puerto de recepción (pulsar F5).
- Variación de la velocidad de transmisión de los puertos de recepción y transmisión (pulsar
F6).
- Modo Eco (test) o Normal (Analizador de Red) ,la tecla F3 activa o desactiva el eco (pulsar
F8).
El usuario deberá tener a mano el manual de instrucciones del protocolo Modbus ya que este
programa sólo envia bytes de datos al procesador local.Para más ayuda pulsar la tecla [F1] al
ejecutar este programa.
(*NOTA el número máximo de bytes por cada trama enviada es de 69 por aspectos visuales
,pero en la práctica se puede llegar a tramas de hasta 99 bytes de datos).
- COMSETUP.C
Este programa se emplea para configurar la estación con todos sus parámetros fundamentales:
la red local basará su las comunicaciones por el puerto serie 0 ,mientras que el bus de campo
utilizará el puerto serie 1 para las suyas ,esta situación será fija para las Workstations y los
Front-Ends,la velocidad de transmisión está prefijada a 115200 baudios y puede ser variada
por el usuario,la ventana de respuesta está establecida en 10 y el espacio reservado para las
tramas de entrada y salida se ha inicializado a 960 y 1000 bytes; la dirección de la estación
podrá estar comprendida entre 1 y 32 y el nº de plcs entre 0 y 32. Para los Front-End (que
sirven de enlace entre la red y el bus) la velocidad de transmisión por el bus está establecida
en 9600 baudios. Cualquier cambio que se realice en los parámetros principales de las
comunicaciones afectarán directamente a ellas ,se recomienda dejar los valores por defecto.
Este programa cambia su configuración según sea empleado para una Workstation o para un
Front-End (en el primer caso el usuario no puede modificar el número de plcs que es nulo).
Para manejar el programa bastan las teclas TAB para moverse por las diversas variables a
modificar , las teclas '+' y '-' para modificar los valores preestablcidos y por último la tecla ALT
en combinación con las anteriores para aumentar la constante de variación deseada.Todo esto
se puede realizar directamente con el ratón del PC ,pulsándo encima del lugar idóneo.
- PRESENTA.C
Como su propio nombre indica sirve de pantalla de presentación del programa de red
local,tanto para la versión Workstation como para la Front-End. Para salir basta con pulsar una
tecla o un botón del ratón del PC.
- INSTALL.C
Permite al usuario instalar los programas de red y sus aplicaciones en el directorio
escogido,para la desinstalación basta con ejecutar el archivo UNINST.BAT.
407
- WORD.C
Este programa trata de semejarse a un procesador de textos con capacidades muy limitadas
(edición de un mensaje de hasta 928 caracteres ,visualización de documentos de texto
existentes ,configuración de envios de documentos de texto y configuración de la salida del
programa principal de la red local. Se maneja principalmente con el ratón para los comandos y
con el teclado para redactar escritos. Para abandonar el programa de edición basta con pulsar
la tecla ESC. En la pantalla principal podemos ver la fecha y la hora actualizadas ,una ventana
de escritorio ,el nombre y tamaño del documento de texto activo y por último los tres botones
de mandatos ( Salida del programa principal <EXIT>, Abrir un nuevo documento de texto
<OPEN> y Envio del documento activo (SEND).
Con el primer botón abandonamos el programa principal de comunicaciones que esté
ejecutándose (ya sea el de la Workstation o el del Front-End) ,con el segundo accedemos a
una pantalla de visualización de ficheros de texto donde podemos ver su nombre y extensión.
Para pasar de página pulsar la tecla ENTER. Al llegar a la última página o pulsar otra tecla
distinta de la citada aparecerá el mensaje "Filename" ,solicitándo la entrada del fichero a
visualizar .Si el fichero no existe o es el mismo que aparece activo al comienzo por defecto nos
deja la opción de volver al comienzo de la lista de archivos.Si deseamos volver a la página de
escritorio basta con pulsar la tecla ENTER cuando aparezca de nuevo el mensaje comentado
anteriormente (esto hace que el mensaje que teníamos activo se borre). Si el fichero solicitado
no cabe en el escritorio aparecerá un mensaje advirtiéndolo ,en este caso si se modifica se
sobreescribirán los datos,en caso contrario se modificará el archivo a partir del final .Por último
el tercer botón nos permite enviar el documento de texto activo a otra estación ,da igual si es
Workstation o Front-End. Al pulsar este botón aparecé un mensaje de confirmación de dicha
acción (pulsar la tecla 'y','Y' o ENTER para acceptar) y seguidamente nos solicita la dirección
de la estación a la que queremos enviar el documento. Si el documento de texto se ha
modificado por teclado ,es necesario contestar 'y' al mensaje de final de salvar el actual fichero
de texto.
(*NOTA los archivos de texto que pueden ser enviados han de tener la extensión .TXT )
PROGRAMAS DE AYUDA
- ANALIZA.C
Este programa permite visualizar los mensajes que se transmiten por la red local ,además de
poder almacenar las tramas recibidas.Puede ser utilizado como analizador de la red local o
para realizar puebas en dicha red. Para más información acudir a la opción F1 del
programa.Proporciona mejor información que el programa OSCILOS.C que es de carácter más
general.
- MUXAD7.S51
Este programa permite al usuario leer los valores analógicos existentes en el puerto 7 del
microcontrolador SAB80C537. Para cargarlo en la eprom es necesario disponer del kit de
desarrollo de Altair.Para ocupar menos espacio en disco aprovecha la misma librería de avisos
que el programa principal MODBUS.S51.El programa envia por el puerto serie 1 el valor
analógico de la entrada solicitada si anteriormente se le envia dicha orden por el mismo puerto
(el código de activación es el valor decimal 0..7 según la entrada analógica deseada a leer). La
respuesta que envia es el valor analógico leido y convertido en formato digital
,seguido del valor en Voltios más dos decimales.
- REPETIDO.S51
Este programa permite al usuario enviar datos por uno de los puertos serie del
microcontrolador SAB80C537 y recibirlos por el otro. Soporta los estándares RS232 y RS485.
408
- TARJETA.C
Mediante este sencillo programa podremos testear el estado de los puertos ,conectándolos
entre ellos mediante un cable "Null Modem" o bien conectándo las tarjetas convertidoras
RS485 en cada puerto ,después alimentándolas a 12 V y conectando por último cada polo de
salida de dichas tarjetas con su homónimo. El programa envia datos desde un puerto al otro
alternativamente. En la pantalla principal se muestra el puerto activo ,es decir el transmisor ;
también se ve el dato transmitido por dicho puerto y el dato que se recibe por el otro puerto. Si
el dado transmitido y el recibido no concuerdan entonces los puertos tienen algún tipo de error
físico. Entre envio y recibo existe un retardo programado de 1 seg y entre cada envio
alternativo también existe dicho retardo. La velocidad de transmisión está fijada a 9600
Baudios.
2.5.1 - Código de programación en Turbo C y lenguaje
ensamblador de los programas de ayuda y apoyo
El código turboC de los programas anteriormente comentados acompañan a este documento
en forma de un disquette de 1'44 Mbytes disponible para el usuario o programador interesados.
Se encuentran en el directorio A:\CODIGOC. El código ensamblador de los programas para el
SAB80C537 se encuentra en el directorio A:\ALTAIR\DRIVERS
409
3 PLANOS
3.1 - Esquema y layout de la tarjeta convertidora
3.2 - Plano de la red local y el bus de campo
3.3 - Esquema de conexionado
3.4 - Esquema y layout de la tarjeta de expansión
410
411
412
PRESUPUESTO
Y
PLIEGO DE CONDICIONES
FECHA: 1/ 1/ 2001
REALIZADO POR: Carlos Blanco Morcillo
SITUACIÓN: UNIVERSIDAD ROVIRA I VIRGILI
TARRAGONA
413
4 PRESUPUESTO
4.1 - Mediciones
4.2 - Cuadro de precios nº 1
4.3 - Cuadro de precios nº 2
4.4 - Presupuesto
4.5 - Resumen del presupuesto
414
4.1 Mediciones
Capítulo 1
Nº
Orden
Un.
1
2
m
3
Instalación del bus de campo
Designación
Nº unidades
Total parcial
Total
RS186-3082
31
1
31
ERN04A
1
1000
1000
RS186-3133
61
1
61
4
m
RS123-579
1
1000
1000
5
m
CPT16
32
1
32
6
L1270
124
1
124
7
AMR
31
1
31
8
PE732
62
1
62
9
RS501-547
31
1
31
10
SP121A-R2
32
1
32
Capítulo 2
Designación
Nº unidades
Total parcial
Total
TC485
32
1
32
ERN04A
1
500
500
RS210-5804
32
1
32
L3191
1
500
500
5
L1270
128
1
128
6
RS186-3082
31
1
31
7
L2727
64
1
64
8
L2730
1
1
1
9
SP600A
6
1
6
10
PSDD 4/25 1-30
26
1
26
Designación
Nº unidades
Total parcial
Total
11
RS599-768
1
500
500
12
L1655
26
1
26
Nº
Orden
Un.
Instalación de la red local
1
2
m
3
4
Nº
Orden
m
Un.
415
4.2 Cuadro de precios nº 1
- JUSTIFICACIÓN DE PRECIOS SIMPLES -
4.2.1 Mano de obra
Oficial 1ª :
- electricista
doscientas cincuenta
- electrónico
doscientas cincuenta
- montador
ciento setenta
2250
pta/h
Dos
mil
2250
pta/h
Dos
mil
2170
pta/h
Dos
mil
Ayudante de:
- electricista.
novecientas
- montador.
mil ciento veinte
1900 pta/h Mil
1820 pta/h Dos
4.2.2 Materiales
-Placa de pared con conector RJ11 referencia RS210-5804. 682pta/un Seiscientas ochenta y dos
otra opción posible:
-Base de pared para RJ11 ,6 vías referencia L1286.
cincuenta
750pta/un
Setecientas
-Adaptador de 3 vías para conectores tipo RJ11 referencia RS186-3082, material de resina
de ABS UL94V-O ,contactos en Au sobre Ni.
770pta/un Setecientas setenta
otra opción posible:
-Adaptador en T para RJ11 ,1 clavija y 2 bases referencia L1288 de MISCO. 350 pta/un
Trescientas cincuenta
-Acopladores apantallados para RJ11 material PBT ,contactos chapado 30μ de Au sobre Ni.
Referencia RS186-3133.
490pta/un
Cuatrocientas
noventa
otra opción posible:
-Acopladores para RJ11 ,6 vías referencia L2518 de Misco.
cincuenta
2
550pta/u
Quinientas
-Cubrecables Misco de 8x14 mm de goma no tóxica y combustión retardada referencia L3191.
2300pta/m Dos Mil trescientas
otra opción posible:
416
-Cubrecables de humos no tóxicos ,cumple la norma BS478 parte 7 ,clase 3.Referencia RS392214 de RS.
3200pta/m Tres Mil doscientas
-Cable para red STP 7x32 AWG baja capacidad y apantallado ref. ERN04A de Black Box.
175pta/m Ciento setenta y cinco
otra opción posible:
-Cable 24AWG (7x32) de cobre estañado y apantallado con aluminio individualmente de 4 pares
referencia L1869 de MISCO.
180pta/m Ciento ochenta
-Cable para red UTP 7x30 AWG ref. ECN04A de Black Box.
y ocho
138pta/m Ciento treinta
-Bandejas (racks) de acero de 75 mm para cables ,con reborde de retorno y accesorios. Material
en acero dulce con galvanizado posterior, conforme a la norma B5729. Referencia RS 123-579.
1660pta/m Mil seiscientas sesenta
2
-Conductor unipolar de Cu de puesta a tierra de 16mm .
121pta/m Ciento veintiuna
-Arquetas metálica para registros.
2300pta/un Dos Mil trescientas
-Conectores RJ11 6 vías referencia L1270 de MISCO.
800pta/un Ochocientas
-Conectores modulares IDC hembra RJ11 6 vías referencia L2727 de MISCO. 650pta/un
Seiscientas cincuenta
-Paneles de conexión 32 posiciones modular para montaje en rack. Referencia L2730 de MISCO.
5700pta/un Cinco Mil setecientas
-Dispositivo protector para red de datos ref. SP600A de Black Box . 9720pta/un Nueve Mil
setecientas veinte
-Dispositivo protector para equipos de red ,con ref. PSDD 4/25 1-30 de Procainsa 15600pta/un
Quince Mil seiscientas
-Canal PVC,cubrecable 10x20mm referencia RS599-768.
140pta/m
Ciento
cuarenta
-Caja PVC con apantallamiento contra RF ,referencia RS501-547 de 100x50mm. 584pta/un
Quinientas Ochenta y cuatro
-Prensa estopas 7x32 AWG
ochenta
180pta/un
Ciento
-Dispositivo protector para red de datos ref. SP121A-R2 de Black Box. 10250pta/un Diez Mil
doscientas cincuenta
-Regleta 2 polos.
Setenta y cinco
75pta/un
-Conector macho 4 pines para conectar alimentación PC.
-Resistencia 82
RS148-231.
70 pta/un Setenta
,1/4 W de película de carbón.Cumple la DIN44051 y CECC40100. Referencia
10pta/un Diez
-Condensadores electrolíticos 1μF ,25 V referencia RS116-896
20pta/un Veinte
-Integrado SN75176 de Texas referencia RS630-910 ,cumple la EIA RS485 ,CCITT V.11 y la
X.27.Encapsulado DIL 8 pines (1 emisor y 1 receptor). 393 pta/un Trescientas noventa y tres
417
-Integrado MAX232 de Maxim protegido contra ESD de hasta 15 KV.Referecia RS225-8510.
Encapsulado DIL 16 pines.(2 receptores y 2 emisores). 730pta/un Setecientas treinta
-Soporte (zócalo) para circuito integrado de 16 pines,especial para soldadura por dos
caras.Zócalo DIL de contactos en Au sobre Cu al Be Niquelado ,con envuelta exterior de latón,7'2
mm paso y pin torneado.Referencia RS197-2647. 980 pta/un Novecientas ochenta
-Soporte (zócalo) para circuito integrado de 8 pines, para soldadura por dos caras.Zócalo DIL de
contactos en Au sobre Cu al Be Niquelado ,con envuelta exterior de latón ,7'2 mm paso y pin
torneado.Referencia RS197-2669. 980 pta/un Novecientas ochenta
-Miniinterruptor DIL 16 en línea 8SPST ,referencia RS337-560.
-Pulsador para PCB ,color negro referencia RS334-915.
cuatro
300pta/un Trescientas
164pta/un
Ciento sesenta y
-placa para Circuito Impreso fotoresist positivo de 14x17cm. (da para 4 tarjetas) 840pta/un
Ochocientas cuarenta
-Conector 10HH1C0 10 pines para
PCB (cable plano).
70pta/un Setenta
4.2.3 Maquinaria
- Camión pluma para transporte de Bobinas de cable.
Material a aportar por el Instalador:
batería incorporada.
10.000pta/porte Diezmil
Analizador de redes locales, Fluke DSP-1001SR con
418
4.3 Cuadro de precios nº 2
- JUSTIFICACION DE PRECIOS Nº
Descripción
Precio
1
Fabricación tarjetas referencia TC485
6731
Nombre
Nº
Precio
Parcial
Importe
Mano de
obra
Oficial 1ª
electrónico
'271
2250
609'5
609'5
Material
Resistencia
50 .
Conector 4 pines.
Placa CI
resist.+.
Miniinterruptor DIL
16.
Zócalo DIL
16.
Zócalo DIL 8.
Condensador
polarizado
1μF ,25V.
2
10
20
1
70
70
2
210
420
1
300
300
1
980
980
2
980
1960
5
20
100
2
1
2
393
730
75
786
730
150
1
2
164
70
164
140
1
1
50
120
50
120
-----5990
CI SN75176.
CI MAX232. Regleta
2 polos.
Pulsador
Conector
10 pines
Diodo 1N4001
Regulador
μA7805
5990
Coste directo
6599'5
Gastos indirectos
131'99
Coste de ejecución
material
6731'49
(* Nota los gastos indirectos se consideran un 2% del coste directo ).
419
Nº
Descripción
2
Cable para red UTP 7x30 AWG
Box colocado.
Mano de
obra
Material
Precio
ref. ECN04A de Black
227
Nombre
Nº
Precio
Parcial
Oficial 1ª
Eléctrico
Ayudante
Eléctrico
'025
2250
56'25
'015
1900
28'5
----84'75
84'75
138
138
Cable UTP
1'00
138
Importe
Coste directo
222'75
Gastos indirectos
4'445
Coste de ejecución
material
227'205
Nº
Descripción
Precio
3
Cable para red STP 7x32 AWG ,de baja capacidad y
apantallado ref. ERN04A de Black Box colocado.
497
Mano de
obra
Material
Nombre
Nº
Precio
Parcial
Oficial 1ª
Eléctrico
Ayudante
Eléctrico
'035
2250
70'75
'035
1900
66'5
----137'25
137'25
175
175
Cable STP
1'00
175
Importe
Coste directo
487'25
Gastos indirectos
9'745
Coste de ejecución
material
496'99
420
Nº
Descripción
4
Conductor unipolar de Cu de puesta a tierra de 16mm
referencia CPT16
Mano de
obra
Material
Precio
2
Nombre
Nº
Precio
Parcial
Oficial 1ª
Eléctrico
Ayudante
Eléctrico
'015
2250
33'75
'015
1900
28'5
----62'25
62'25
121
121
Conductor de puesta
a tierra
1'00
Nº
Descripción
5
Caja con "roseta" de 32x45mm
Mano de
obra
Material
187
121
Importe
Coste directo
183'25
Gastos indirectos
3'665
Coste de ejecución
material
186'915
Precio
referencia RS210-5804.
497
Nombre
Nº
Precio
Parcial
Oficial 1ª
Eléctrico
Ayudante
Eléctrico
'035
2250
70'75
'035
1900
66'5
----137'25
137'25
682
682
Roseta de
32x45mm para RJ11
1'00
682
Importe
Coste directo
487'25
Gastos indirectos
9'745
Coste de ejecución
material
496'99
421
Nº
Descripción
Precio
6
Adaptador de 3 vías para conectores
tipo RJ11 referencia RS186-3082,
material de resina de ABS UL94V-O
,contactos en Au sobre Ni.
837
Mano de
obra
Material
Nombre
Nº
Precio
Parcial
Oficial 1ª
Montador
Ayudante
Montador
'015
2170
32'55
'010
1820
18'2
----50'75
50'75
770
770
Adaptador de 3 vías
para conectores
tipo RJ11
1'00
770
Importe
Coste directo
820'75
Gastos indirectos
16'415
Coste de ejecución
material
837'165
Nº
Descripción
Precio
7
Acopladores apantallados para RJ11
material PBT ,contactos chapado 30μ de
Au sobre Ni.Referencia RS186-3133.
586
Mano de
obra
Material
Nombre
Nº
Precio
Parcial
Oficial 1ª
Eléctrico
Ayudante
Eléctrico
'025
2250
56'25
'015
1900
28'5
----84'75
84'75
490
490
Acopladores
apantallados para
RJ11
1'00
490
Importe
Coste directo
574'75
Gastos indirectos
11'495
Coste de ejecución
material
586'245
422
Nº
Descripción
Precio
8
Bandejas (racks) de acero de 75 mm
para cables ,con reborde de retorno y
accesorios. Material en acero dulce
con galvanizado posterior, conforme
a la norma B5729. Referencia RS 123-579.
3118
Mano de
obra
Material
Nombre
Nº
Precio
Parcial
Oficial 1ª
Montador
Ayudante
Montador
'35
2170
759'5
'35
1820
637'0
----1396'5
1396'5
1660
1660
Bandejas de acero
para cables
1'00
1660
Importe
Coste directo
3056'5
Gastos indirectos
61'13
Coste de ejecución
material
3117'63
Nº
Descripción
Precio
9
Adaptador IBM AT 9H/25M referencia L1655 de MISCO.
970
Mano de
obra
Material
Nombre
Nº
Precio
Parcial
Oficial 1ª
Eléctrico
Ayudante
Eléctrico
'005
2250
11'25
'005
1900
9'5
----20'75
20'75
930
930
Adaptador 9H/25M
1'00
930
Importe
Coste directo
950'75
Gastos indirectos
19'015
Coste de ejecución
material
969'76
423
Nº
Descripción
Precio
10
Arquetas metálica para registros referencia AMR
2429
Mano de
obra
Material
Nombre
Nº
Precio
Parcial
Oficial 1ª
Montador
Ayudante
Montador
'025
2170
54'25
'015
1820
27'3
----81'55
81'55
2300
2300
Arquetas metálica
para registros
Nº
Descripción
11
Conectores RJ11 6 vías
Mano de
obra
Material
1'00
2300
Importe
Coste directo
2381'55
Gastos indirectos
47'631
Coste de ejecución
material
2429'181
Precio
referencia L1270 de MISCO.
879
Nombre
Nº
Precio
Parcial
Oficial 1ª
Eléctrico
Ayudante
Eléctrico
'015
2250
33'75
'015
1900
28'5
----62'25
62'25
800
800
Conectores RJ11 6
vías
1'00
800
Importe
Coste directo
862'25
Gastos indirectos
17'245
Coste de ejecución
material
879'495
424
Nº
Descripción
12
Conectores modulares IDC hembra
referencia L2727 de MISCO.
Mano de
obra
Material
Precio
726
RJ11 6 vías
Nombre
Nº
Precio
Parcial
Oficial 1ª
Eléctrico
Ayudante
Eléctrico
'015
2250
33'75
'015
1900
28'5
----62'25
62'25
650
650
Conectores
modulares
IDC RJ11
1'00
650
Importe
Coste directo
712'25
Gastos indirectos
14'245
Coste de ejecución
material
726'495
Nº
Descripción
Precio
13
Paneles de conexión 32 posiciones
modular para montaje en rack.
Referencia L2730 de
MISCO.
5956
Mano de
obra
Material
Nombre
Nº
Precio
Parcial
Oficial 1ª
Montador
Ayudante
Montador
'035
2170
75'95
'035
1820
63'7
----139'65
139'65
5700
5700
Paneles para
montaje en rack.
1'00
5700
Importe
Coste directo
5839'65
Gastos indirectos
116'793
Coste de ejecución
material
5956'443
425
Nº
Descripción
14
Dispositivo protector para red
Black
Box.
Mano de
obra
Material
Precio
de datos ref. SP600A de
10062
Nombre
Nº
Precio
Parcial
Oficial 1ª
Eléctrico
Ayudante
Eléctrico
'035
2250
78'75
'035
1900
66'5
----145'25
145'25
9720
9720
Dispositivo protector
para red
1'00
9720
Importe
Coste directo
9865'25
Gastos indirectos
197'305
Coste de ejecución
material
10062'55
Nº
Descripción
Precio
15
Dispositivo protector para equipos de red ,con ref. PSDD 4/25
1-30 de Procainsa.
16060
Mano de
obra
Material
Nombre
Nº
Precio
Parcial
Oficial 1ª
Eléctrico
Ayudante
Eléctrico
'035
2250
78'75
'035
1900
66'5
----145'25
145'25
15600
15600
Dispositivo protector
para equipos de red
1'00
15600
Importe
Coste directo
15745'25
Gastos indirectos
314'905
Coste de ejecución
material
16060'15
426
Nº
Descripción
Precio
16
Canal PVC,cubrecable 10x20mm
referencia RS599-768.
194
Mano de
obra
Material
Nombre
Nº
Precio
Parcial
Oficial 1ª
Montador
Ayudante
Montador
'015
2170
32'55
'010
1820
18'2
----50'75
50'75
140
140
Canal PVC,
cubrecable
1'00
140
Importe
Coste directo
190'75
Gastos indirectos
3'815
Coste de ejecución
material
194'56
Nº
Descripción
Precio
17
Prensa estopas 7x32 AWG ref. PE732
197
Mano de
obra
Material
Nombre
Nº
Precio
Parcial
Oficial 1ª
Eléctrico
Ayudante
Eléctrico
'005
2250
11'25
'001
1900
1'9
----13'15
13'15
180
180
Prensa estopas 7x32
AWG
1'00
180
Importe
Coste directo
193'15
Gastos indirectos
3'863
Coste de ejecución
material
197'013
427
Nº
Descripción
Precio
18
Dispositivo protector para red de
datos ref. SP121A-R2 de Black Box
10560
Mano de
obra
Material
Nombre
Nº
Precio
Parcial
Oficial 1ª
Eléctrico
Ayudante
Eléctrico
'025
2250
56'25
'025
1900
47'5
----103'75
103'75
10250
10250
Dispositivo protector
para red
1'00
10250
Importe
Coste directo
10353'75
Gastos indirectos
207'075
Coste de ejecución
material
10560'82
Nº
Descripción
Precio
19
Cajas de PVC y apantalladas contra RF
referencia RS501-547
649
Mano de
obra
Material
Nombre
Nº
Precio
Parcial
Oficial 1ª
Eléctrico
Ayudante
Eléctrico
'015
2250
33'75
'010
1900
19
----52'75
52'75
584
584
Cajas PVC
apantalladas
1'00
584
Importe
Coste directo
636'75
Gastos indirectos
12'735
Coste de ejecución
material
649'48
428
Nº
Descripción
20
Cubrecables Misco de 8x14 mm
de goma no tóxica y
combustión
retardada colocado.Referencia L3191
Mano de
obra
Material
Precio
2
2488
Nombre
Nº
Precio
Parcial
Oficial 1ª
Montador
Ayudante
Montador
'035
2170
75'95
'035
1820
63'7
----139'65
139'65
2300
2300
Cubrecables de
goma no
tóxica y combustión
retardada.
1'00
2300
Importe
Coste directo
2439'65
Gastos indirectos
48'793
Coste de ejecución
material
2488'44
429
4.4 Presupuesto
Capítulo 1
Nº
un
1
2
m
3
Instalación del bus de campo
Ref.
Nºun
RS1863082
31
ERN04A
1
RS1863133
61
L
A
1000
H
Total
unit.
TOTAL
837
25947
497
497000
586
35746
4
m
RS123579
1
1000
3118
3118000
5
m
CPT16
1
32
187
5984
6
L1270
124
879
108996
7
AMR
31
2429
75299
8
PE732
62
197
12214
9
RS501547
31
649
20119
10
SP121AR2
32
10560
337920
TOTAL CAPITULO: 4.237.225 pta
430
Capítulo 2
Nº
un
Instalación de la red local.
Ref.
Nºun
Total
unit.
TOTAL
TC485
32
6731
215392
ECN04A
1
227
113500
RS2105804
32
497
15904
L3191
1
2488
1244000
5
L1270
128
879
112512
6
RS1863082
31
837
25947
7
L2727
64
726
46464
8
L2730
1
5956
5956
9
SP600A
*6
10062
60372
10
PSDD
4/25
1-30
*26
16060
417560
RS599768
1
194
97000
L1655
*26
970
25220
1
2
m
3
4
11
m
m
12
L
A
H
500
500
500
TOTAL CAPITULO: 2.379.827 pta
(*NOTA: de los equipos de la red local 26 son PCs y 6 son
Front-Ends)
Capítulo 3
Programación del sistema
898 horas de programación x (2250x 0'010)pta/h = 20200
TOTAL CAPITULO: 20.200 pta
(*NOTA: en este capítulo se incluye la programación tanto de los PCs de la red local como
de los microcontroladores del bus de campo)
431
4.5 Resumen del presupuesto
CAPITULO 1
4.237.225 pta
CAPITULO 2
2.379.827 pta
CAPITULO 3
20.200 pta
--------------------------------
Total Capítulos
6.637.252 pta
+
Gastos Generales
862.842'7 pta
13%
+
Beneficios
331.862'6 pta
6%
--------------------------------7.831.957'3 pta
I.V.A. +
16%
1.253.113'2 pta
--------------------------------TOTAL FINAL
9.085.070'5 pta
Al final el PRESUPUESTO asciende a la cantidad de NUEVE MILLONES OCHENTA Y CINCO
MIL SETENTA Pesetas.
Fecha: 1-1-2001
Firmado:
432
5 PLIEGO DE CONDICIONES
5.1 - Pliego de condiciones
generales de índole legal
5.2 - Pliego de condiciones
generales de índole
facultativa
5.3 - Pliego de condiciones
generales de índole económica
5.4 - Pliego de condiciones
generales de índole técnica
433
5.1 Pliego de condiciones generales de índole legal
5.1.1 Condiciones Generales
El contrato de instalación se formalizará mediante un documento privado por deseo expreso de la
empresa solicitante de la obra. Todos los apartados de este Pliego de condiciones, los apartados
de planos y demás documentos del proyecto deberán ser adheridos íntegramente al contrato, es
por ello que tanto la Propiedad como el Constructor o Instalador deberán firmar al pie del presente
Pliego y demás documentos del proyecto como afirmación de su conocimiento y aprobación de
este. No se podrá modificar en parte o en su totalidad ninguna de las condiciones generales o
particulares sin la aprobación de la Dirección.
5.1.2 Responsabilidades
5.1.2.1 Responsabilidad general del Instalador
Es responsable de la ejecución de las obras en las condiciones que se han establecido en el
proyecto y en el contrato.
5.1.2.2 Accidentes de trabajo
El Constructor o Instalador de la red y el bus de campo se atendrá a las disposiciones vigentes
sobre prevención de riesgos laborales ,siendo el único
responsable de su incumplimiento.
5.1.2.3 Daños a terceros
También es responsable de los daños causados a terceros por negligencia ,inexperiencia o
empleo de
métodos de trabajo inadecuados. De existir procedimientos de trabajo ya
establecidos en la Propiedad deberán ser conocidos ,cumplidos y respetados por los trabajadores
del Constructor e Instalador.
5.1.2.4 Reglamentación laboral
El Constructor o Instalador será el único responsable del incumplimiento de la Reglamentación
Laboral vigente.
5.1.3 Rescisión del Contrato
Se consideran causas para una rescisión de contrato:
- Alteración del contrato por : modificación del proyecto en un 25% de su valor contratado o
modificaciones de unidades de obra en número superior al 40%.
- El no respeto de los plazos de inicio estipulados por el pliego de condiciones o la terminación del
plazo de ejecución sin haber completado la obra.
- La muerte , incapacitación o quiebra del Constructor o Instalador de la red local y el bus de
campo.
- Mala fe en la ejecución de trabajos.
- Abandono de la obra sin causa justificada.
434
5.2 Pliego de condiciones generales de índole
facultativa
Las distintas partes en que se divide la obra son:
Compra de todos los materiales, componentes y herramientas para la instalación.
Fabricación de las tarjetas convertidoras.
Comprobación del correcto funcionamiento de estas.
Montaje y cableado de la instalación.
Programación de los equipos a usar.
Puesta en marcha y funcionamiento.
Mantenimiento para el correcto funcionamiento de todo el sistema.
El montador o constructor de las instalaciones deberá cumplir la normativa eléctrica y electrónica
(RBT e ITC del RBT),normas de homologación y las especificaciones técnicas de electrónica e
Informática.
5.2.1 Obligaciones y derechos del Constructor
El Constructor o un Representante suyo han de residir en la localidad donde se realice la obra.
Deberán asimismo presentarse en la obra si así lo requiriera la Dirección. Se deberá instalar una
oficina para consultas necesarias a cargo del Constructor ,en dicha oficina de obra existirá un libro
de ordenes en el que se escribirán las que la Dirección estime necesario darle al Constructor ,sin
perjuicio de las que le dé por oficio cuando lo crea necesario y que tendrá que firmar el enterado.
La interpretación técnica de los documentos compete a la Dirección. Es obligación del Constructor
dirigir a éste cualquier duda ,aclaración o contradicción que surgiere durante la ejecución de las
instalaciones por causa del proyecto o circunstancias ajenas. El Constructor se hace responsable
de cualquier error de ejecución motivado por la omisión de esta obligación y consecuentemente
deberá rehacer a su costa los trabajos que no correspondan a la correcta interpretación del
proyecto.
El Constructor tendrá al frente de la obra un encargado con autoridad y conocimientos acreditados
y suficientes para la ejecución del tipo de instalación a realizar. Este encargado recibirá
instrucciones de la Dirección en cuanto a la forma y métodos de trabajo.
5.2.2 Obligaciones de las obras y su ejecución
El comienzo de las obras se hará en el plazo que figure en el contrato o en las condiciones
particulares. En su defecto ,se realizará a los quince días de la adjudicación de la misma o firma
del contrato. Asimismo la instalación se ejecutará en el plazo que se convenga en el contrato o en
su defecto en el que figura en las condiciones particulares de este pliego.
El constructor notificará por escrito o personalmente la fecha de inicio de la instalación y con
antelación suficiente la fecha para inspecciones finales de las partes de la instalación que deban
quedar ocultas. También está obligado a realizar las obras que se le encarguen resultantes de
modificaciones en el proyecto siempre que la valoración total no altere en más o en menos el 25%
del valor contratado. La valoración de las mismas se hará de acuerdo con lo establecido en el
Pliego de Condiciones Generales de índole económica, sobre precios contradictorios.
El Constructor tiene la obligación de realizar todas las obras complementarias que sean
indispensables para ejecutar cualesquiera de las unidades o elementos de obra especificados en
cualquiera de los documentos del proyecto ,aunque no figuren explícitamente mencionadas. Todo
ello sin aumento del importe contratado. Cuando el Constructor haya efectuado cualquier elemento
de la instalación que no se ajuste a lo especificado en el proyecto ,la Dirección podrá aceptarlo o
435
rechazarlo; en el primer caso ,ésta fijará el precio que crea justo con arreglo a las diferencias que
hubiera ,viniendo el Contratista a aceptar dicha valoración. En el segundo caso deshará y
reconstruirá a sus expensas toda la parte mal
ejecutada sin que ello sea motivo de prórroga en
el plazo de ejecución.
5.2.3 Recepción de las obras
Una vez terminada la instalación ,tendrá lugar la recepción provisional y a tal efecto se practicará
en
ellas un detenido reconocimiento por la Dirección y Propietario en presencia del
Contratista ,levantado el acta y empezando desde este día a correr el plazo de garantía si las
instalaciones se hallasen en estado de ser admitidas. En caso contrario se hará constar en acta y
se darán al Contratista las oportunas instrucciones para remediar los defectos observados ,fijando
un plazo para subsanarlas ,expirado el cual se efectuará un nuevo reconocimiento a fin de
proceder a la recepción provisional de la instalación.
El plazo de garantía será de un año contando desde la fecha en que la recepción provisional se
verifique, quedando durante ese plazo la conservación de las instalaciones y arreglo de
desperfectos a cargo del Contratista.
La recepción definitiva será después de transcurrido el plazo de garantía ,cesando la
responsabilidad del Contratista de reparar a su cargo aquellos defectos por mal uso , a no ser que
sean producto de defectos deficientes y ocultados por este.
436
5.3 Pliego de condiciones generales de índole
económica
Obligaciones del constructor
En el contrato se establecerá la fianza que el instalador deberá depositar en garantía del
cumplimiento del mismo ,o se convendrá en una retención sobre los pagos que se hayan de
realizar a cuenta de obra ejecutada. De no quedar concretado este punto se establecerá como
garantía una retención del 10% sobre los pagos citados. La susodicha se abonará al constructor
en un plazo no superior a 30 días una vez firmada el acta de recepción definitiva de la instalación.
Las indemnizaciones por retrasos en la instalación serán las que se fijan en el contrato.
El presupuesto del presente proyecto será válido por un período de tres ,meses. La instalación
tanto en el aspecto físico como de programación dispone de una garantía de un año ,durante la
cual el fabricante sólo realizará reparaciones debido a posibles fallos en la fabricación, instalación
o desajustes en esta. Estas reparaciones se llevarán a cabo de forma gratuita para el contratista.
El instalador estará obligado a asegurar la instalación contratada durante el tiempo que dure su
ejecución. La garantía no cubre desperfectos ocasionados a la instalación por uso indebido de la
misma. El instalador deberá realizar ante el contratista una demostración del perfecto
funcionamiento de la instalación, y asesorarle sobre el manejo y el mantenimiento de estas.
En caso de tenerse que realizar unidades de obra cuyo precio no figure en el contrato o proyecto
,se fijará su precio contradictoriamente entre la Dirección y el Constructor antes del inicio de los
trabajos, tomando como base de cálculo los valores de materiales y mano de obra determinados
en el cuadro de precios de aplicación en la instalación.
Obligaciones y derechos del contratista
El contratista deberá abonar al fabricante una entrada del 30% del importe total en el momento de
recibir el equipo. El resto se abonará en un plazo no superior a los tres meses desde la recepción
provisional. Tendrá derecho a sacar copias ,a su costa de los planos
,pliegos de condiciones
y demás documentos de la contrata.
437
5.4 Pliego de condiciones generales de índole técnica
Las características de los componentes de las tarjetas convertidoras se encuentran en el apartado
de anexos de la memoria descriptiva. Los materiales empleados son fáciles
de encontrar en el mercado y el instalador puede en caso de no encontrarlos en el mercado
,sustituirlos por otros de similares características y precio. La mayoría de los
materiales son de calidad adaptada a las necesidades de la instalación.
Para las tarjetas convertidoras o interface para RS232 a RS485 ,estarán fabricadas en placas de
CI de fibra de vidrio y las pistas tendrán una capa de estaño aplicada para facilitar la soldadura de
componentes, todos los integrados estarán colocados en soportes para su fácil sustitución en caso
necesario de avería. Para su manipulación se han de respetar todas las medidas necesarias
,para evitar daños en los componentes por causa de descargas electrostáticas. Sólo personal
autorizado y cualificado puede manipular dichos equipos.
La instalación ha de ser sometida a pruebas de fallo de las comunicaciones ,distinto tipo de tráfico
y funcionamiento continuo de 12 h para observar si hay anomalías en su comportamiento. Deben
respetarse eso si las condiciones ambientales y de trabajo para las que ha sido fabricada.
Las puestas a tierra no se aceptarán si la fijación de la barra es deficiente ,si la sección del
conductor
desnudo es inferior a lo especificado en la Documentación Técnica o si la
conexión del conductor con la barra de puesta a tierra y con el punto de puesta a tierra tiene
deficiencias en la soldadura.
Cableado de la red local y bus de campo no se aceptará si presenta algún tipo de rotura o
desgaste que pueda provocar accidentes o fallos en las comunicaciones.
438
Descargar