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