'############################################################################## ' BirdView Stand 10.06.2012 ' -------- Version 1.4 ' ' Steuerprogramm der Zentralsteuerung für einen mit Kameras überwachten ' Nistkasten ' ' Das Steuerprogramm verfügt über die folgenden einzelnen Funktions- und ' Teilkomponenten: ' - Mikrocontroller ATmega32 (inkl. ISP, RS232 und Reset) ' - 16 MHz externer Clock ' - LED-Anzeigen für Funktions- und Zustandsanzeigen ' - Unterstützung von Eingabetasten zur manuellen Steuerung ' - Funktions- und Debug-Steuerung über RS232 ' - Ethernet-Anbindung mittels ENC28J60 von MicroChip ' - Umsetzung von Etnernetfunktionen wie TCP, DHCP, PING, ARP, UDP, ... ' - Steuerkonsole über RS232 und TCP z.B. mit Putty ' - Reset-Notfunktion mittels UDP-Kommando ' - Steuerung der Kamera-Versorgungsspannungen für Kamera 1 und 2 ' - Steuerung der Hintergundbeleuchtung mittels PWM ' - Helligkeitsmessung über LDR ' - Umschaltung der Videoquellen mitels Video-Multiplexer ' - Steuerung eines Relais zum Anschluss externer Verbraucher ' ' ' Kurzbeschreibung: ' ================= ' Das Steuerprogramm übernimmt die Steuerung der Kameras und der vorhandenen ' Elektronik. Hierzu gibt es einen Automatikbetrieb der entweder Zeitgesteuert ' oder über Lichtmessung der Lichtverhältnisse im Brutkasten zwischen einer ' Farbkamera oder einer SW-Kamera mit IR-Hintergrundbeleuchtung umschaltet. ' Neben der Automatik wurde auch eine manuelle Steuerung implementiert welche ' es ermöglicht die Videoeingänge explizit auszuwählen und die notwendigen ' Spannungen zu schalten. ' Die manuelle Steuerung kann entweder über Tasten oder via Kommandos üebr eine ' TCP-Verbindung oder RS232-Verbindung erfolgen. ' Betriebsdaten werden persistent im EEPROM des ATmegas gespeichert. ' Die IR-Hintergrundbeleuchtung ist mittels PWM vo Controller aus steuerbar. ' Neben festen IP- und Port-Einstellungen bietet die Steuerung auch die ' Möglichkeit via DHCP dynamische Adressen zu verwenden. ' Betriebsdateninformationen werden beim StartUp automatisch ausgegeben. ' '############################################################################## '------------------------------------------------------------------------------ ' Allgemeine Zusatzinformatonen zu Programmbeginn '------------------------------------------------------------------------------ ' [1] Unterstriche ' Bei BASCOM können bei Binärdefinitionen Unterstriche zur besseren Lesbarkeit ' des Codes verwendet werden. z.B. &B000_11111 ' [2] Übersicht SPI Instruction set für den ENC28J60 Ethernetcontroller: ' +-----------------------------------+--------+----------+----------+ ' | Instruction | Opcode | Argument | Data | ' +-----------------------------------+--------+----------+----------+ ' | Read Control Register | 000 | aaaaa | N/A | ' | Read Buffer Memory | 001 | 11010 | N/A | ' | Write Control Register | 010 | aaaaa | dddddddd | ' | Write Buffer Memory | 011 | 11010 | dddddddd | ' | Bit Field Set | 100 | aaaaa | dddddddd | ' | Bit Field Clear | 101 | aaaaa | dddddddd | ' | System Reset Command (soft reset) | 111 | 11111 | N/A | ' +-----------------------------------+--------+----------+----------+ ' a = address d = data       ' [3] Festlegungen für Register und Speicherbänke ' Zur Speicherplatzoptimierung und zur Vereinfachung des Programmcodes werden ' wie im MCS-Forum zur Ethernetcontrollerprogrammierung vorgeschlagen folgende ' Konventionen verwendet und im Include-File abgebildet: ' a) Für die Adressierung der Controller Register werden nur 5 Bits eines Bytes benötigt. ' b) 2 Bits des Bytes werden zur Bank-Asuwahl der Registerbank verwendet. ' c) Ein verbleibendes Bit wird zur Unterscheidung zwischen Ethernet-, MAC- and Phy-registers verwendet. ' Z.B.: EPAUSL = 18h in Bank 3 ' 00011000 OR 11000000 = 11011000 in Include-File zur Verwendung in Subroutinen ' [4] NTP ' Das hier im Programm und Ben's Tutorial verwendete Verfahren zum Empfang ' von Zeitinformationen entspricht nicht dem NTP-Protokoll über Port 123 sondern ' entstammt dem in der Zwischenzeit antiquirierten Time Protokoll mittels Port 37. ' [5] DHCP ' Eine DHCP-Anfrage läuft nach folgender 4-stufiger Sequence ab: ' DHCP Client (Controller) DHCP Server (Router) ' *------------ DHCP Discover ------->> ' <<----------- DHCP Offer --------* ' *------------ DHCP Request ------->> ' <<----------- DHCP Ack --------* '------------------------------------------------------------------------------ ' Compilerinstruktionen und Compilerdirektiven '------------------------------------------------------------------------------ $regfile = "m32def.dat" ' Definitionsdatei für ATmega32 laden $crystal = 16000000 ' Quarzfrequenz für 16 MHz festlegen $hwstack = 128 ' HW-Stack auf 64 Bytes erweitern $swstack = 128 ' SW-Stack auf 64 Bytes erweitern $framesize = 128 ' Framesize auf 64 Byte festlegen ' Serielle Schnittstelle wird für Tracedatenausgabe verwendet $baud = 38400 ' Baudrate für RS232 auf 38400 Bauf festlegen ' Include-File mit allen Registern, Bänken usw. des Ethernet Controller ENC28J60 laden $include "enc28j60.inc" ' Benötigte Libraries einbinden $lib "tcpip.lbx" ' ---- Systemkonstante für Projektsteuerung ----- Const Compiler_flag = 1 ' 1 = Compilat für Zielumgebung, 0 = Compilat für EVA-Board '------------------------------------------------------------------------------ ' Definition von Ressourcen '------------------------------------------------------------------------------ ' ----- LED's ----- ' LED für Betriebsmodi Mode_led_pin Alias Pinc.2 ' GPIO für Betriebsmodi (für DDR oder Input) Mode_led Alias Portc.2 ' GPIO für Betriebsmodi (für Output oder Pullup) ' LED für Video LED's für Kanalauswahl Video2_led_pin Alias Pinc.4 ' GPIO für Videkanal 2 (für DDR oder Input) Video2_led Alias Portc.4 ' GPIO für Videkanal 2 (für Output oder Pullup) Video1_led_pin Alias Pinc.3 ' GPIO für Videkanal 1 (für DDR oder Input) Video1_led Alias Portc.3 ' GPIO für Videkanal 1 (für Output oder Pullup) ' LED für Hintergrundbeleuchtung Ir_led_pin Alias Pinc.5 ' GPIO für Betrieb Hintergrundbeleuchtung (für DDR oder Input) Ir_led Alias Portc.5 ' GPIO für Betrieb Hintergrundbeleuchtung (für Output oder Pullup) ' LED für Processing Proc_led_pin Alias Pinc.6 ' GPIO für Proc-LED (für DDR oder Input) Proc_led Alias Portc.6 ' GPIO für Proc-LED (für Output oder Pullup) ' LED für Alive Alive_led_pin Alias Pinc.7 ' GPIO für Alive-LED (für DDR oder Input) Alive_led Alias Portc.7 ' GPIO für Alive-LED (für Output oder Pullup) ' ----- Ethernet ENC28J60 ----- Enc28j60_cs_pin Alias Pinb.4 ' GPIO für Chipselect des ENC28J60 (für DDR oder Input) Enc28j60_cs Alias Portb.4 ' GPIO für Chipselect des ENC28J60 (für Output oder Pullup) ' ----- Ausgänge für Schaltstufen ----- ' Spannungsversorgung Kamera 1 Pwr_cam1_pin Alias Pina.5 ' GPIO für Steuerleitung Power Kamera 1 (für DDR oder Input) Pwr_cam1 Alias Porta.5 ' GPIO für Steuerleitung Power Kamera 1 (für Output oder Pullup) ' Spannungsversorgung Kamera 2 Pwr_cam2_pin Alias Pina.6 ' GPIO für Steuerleitung Power Kamera 2 (für DDR oder Input) Pwr_cam2 Alias Porta.6 ' GPIO für Steuerleitung Power Kamera 2 (für Output oder Pullup) ' Relaisstufe Relais_pin Alias Pina.7 ' GPIO für Steuerleitung Relais (für DDR oder Input) Relais Alias Porta.7 ' GPIO für Steuerleitung Relais (für Output oder Pullup) ' IR Hintergrundbeleuchtung ' Hintergrundbeleuchtung wird normal über OC2 und PWM gesteuert. Für den Fall das IR-Aus und IR-Ein sauber umgesetzt werden ' soll so muss PIN als Output konfiguriert werden. Ir_gpio_pin Alias Pind.7 ' GPIO für IR Hintergrundbeleuchtung (für DDR oder Input) Ir_gpio Alias Portd.7 ' GPIO für IR Hintergrundbeleuchtung (für Output oder Pullup) ' ----- Ausgänge Videmultiplexer ---- ' Videoselect Video_select_pin Alias Pinc.0 ' GPIO für Videoselect (für DDR oder Input) Video_select Alias Portc.0 ' GPIO für Videoselect (für Output oder Pullup) ' ----- Eingänge für Taster ----- #if Compiler_flag = 1 ' Reale Umgebung auf Zielhardware Key_1_pin Alias Pinb.0 ' GPIO für Taste 1 (für DDR oder Input) Key_1 Alias Portb.0 ' GPIO für Taste 1 (für Output oder Pullup) Key_2_pin Alias Pinb.1 ' GPIO für Taste 2 (für DDR oder Input) Key_2 Alias Portb.1 ' GPIO für Taste 2 (für Output oder Pullup) Key_3_pin Alias Pinb.2 ' GPIO für Taste 3 (für DDR oder Input) Key_3 Alias Portb.2 ' GPIO für Taste 3 (für Output oder Pullup) #else ' Testumgebung Key_1_pin Alias Pind.4 ' GPIO für Taste 1 (für DDR oder Input) Key_1 Alias Portd.4 ' GPIO für Taste 1 (für Output oder Pullup) Key_2_pin Alias Pind.5 ' GPIO für Taste 2 (für DDR oder Input) Key_2 Alias Portd.5 ' GPIO für Taste 2 (für Output oder Pullup) Key_3_pin Alias Pind.6 ' GPIO für Taste 3 (für DDR oder Input) Key_3 Alias Portd.6 ' GPIO für Taste 3 (für Output oder Pullup) #endif '------------------------------------------------------------------------------ ' Definition von Konstaten '------------------------------------------------------------------------------ ' ----- Systemkonstanten für Debugging und Tracing ----- Const Eeprom_testmodus = 0 ' Flag steuert ob bei EEPROM-Funktionen Trace ausgegeben werden soll Const Enc28j60_testmodus = 0 ' Flag steuert ob allgemeine Traces zum Ethernetcontroller ausgegeben werden sollen Const Enc28j60_testchiprevision = 1 ' Flag steuert ob Ethernet-Chip-Version ausgelesen und ausgegeben werden soll Const Enc28j60_testreceive = 0 ' Flag steuert ob in Ethernet-Receive-Routine Traces geschrieben werden sollen Const Enc28j60_dhcp_output = 0 ' Flag steuert ob bei HCP Traces ausgegeben werden Const Enc28j60_tcptrace = 0 ' Flag steuert ob in Verbindung mit TCP Traces ausgegeben werden sollen Const Enc28j60_udp_output = 0 ' Flag steuert, ob in Verbindung mit UDP-Paketen Traces ausgegeben werden sollen Const Enc28j60_tcp_output = 0 ' Flag steuert, ob in Verbindung mit TCP-Console Traces ausgegeben werden sollen Const Consol_trace = 0 ' Flag ob in Verbindung mit der Eingabe von Kommandos Traces ausgegeben werden sollen Const Light_trace = 0 ' Flag ob bei Helligkeitsmessung Traces ausgegeben werden sollen Const Control_trace = 0 ' Flag für Traceausgaben der Steuerungsaufgaben Const Control_key_trace = 0 ' Flag für Traceausgaben der Tastaturfunktionen Const Ir_testmodus = 0 ' Flag ob in Verbindung mit Hintergrundbeleuchtung Traces geschrieben werden sollen ' ----- Allgemeine Systemkonstanten ----- ' Boolsche Konstanten Const False = 0 ' Boolscher Wert für FALSE Const True = 1 ' Boolscher Wert für TRUE ' Boolsche Konstanten Const Aus = 0 ' Boolscher Wert für AUS Const Ein = 1 ' Boolscher Wert für EIN ' PullUp-Einstellen für Controller Const Pullup_aus = 0 ' Wert um PullUp auszuschalten Const Pullup_ein = 1 ' Wert um PullUp einzuschalten ' Zeitvorgabe für Sekunden-Timer Const Timervorgabe = 3036 ' Timer von 1 Sekunden (SekundenTick) ' ----- Systemkonstanten für die LED-Steuerung ----- ' Boolsche Konstante für LED-Steuerung Const Led_aus = 0 ' Steuerungswert für LED aus Const Led_ein = 1 ' Steuerungswert für LED ein ' ----- Systemkonstanten für die Relaisstufen ----- ' Boolsche Konstante für Relaissteuerung Const Relais_aus = 0 ' Steuerungswert für Relais aus Const Relais_ein = 1 ' Steuerungswert für Relais ein ' ----- Systemkonstanten für Videomultiplexer ----- ' Konstaten für Kanäle Const Kanal_1 = 1 ' Steuerungswert für Auswahl Kanal 1 Const Kanal_2 = 0 ' Steuerungswert für Auswahl Kanal 2 ' Konstanen für Kameras Const Kamera_1 = 1 ' Steuerungswert für Kamera 1 Const Kamera_2 = 2 ' Steuerungswert für Kamera 2 ' Konstanten für automatisches Umschalten Const Switch_from_cam1_to_cam2 = 1 ' Steuerungswert um von Kamera 1 auf Kamera 2 umzuschalten Const Switch_from_cam2_to_cam1 = 2 ' Steuerungswert um von Kamera 2 auf Kamera 1 umzuschalten Const Switch_idle = 0 ' Steuerungswert für Umschalthandling mit Zustand IDLE Const Switch_powered = 1 ' Steuerungswert für Umschalthandling mit Zustand Spannung geschaltet Const Switch_switched = 2 ' Steuerungswert für Umschalthandling mit Zustand Umschaltung erfolgt Const Switch_delay = 5 ' Zeitverzögerung zwischen Power schalten und Multiplexer schalten ' ----- Systemkonstanten für Consoleneingabe und Meldungstexte ----- Const Versiontext = "BirdView V1.4 vom 10.06.2012{013}{010}ATmega32 / 16 MHz{013}{010}" ' Versionstext Const Source_rs232 = 1 ' Eingabequelle ist/war RS232 Const Source_tcp = 2 ' Eingabequelle ist/war TCP Const Mode_manuell = 0 ' Gerätesteuerung erfolgt manuell Const Mode_licht = 1 ' Gerätesteuerung erfolgt über Licht Const Mode_zeit = 2 ' Gerätesteuerung erfolgt über Zeit Const Sequence_nix = 0 ' Keine Textsequence Const Sequence_status = 1 ' Textsequenz für Statustext Const Sequence_help = 2 ' Textsequenz für Hilfstext Const Sequence_xstatus = 3 ' Textsequenz für XSTATUS für BirdView-PC-Applikation ' ----- Systemkonstanten für Lichtmessung via LDR ----- Const Light_timer_intervall = 300 ' Alle 5 Minuten = 300 Sekunden soll eine Lichtmessung erfolgen ' ----- Systemkonstanten für IR Hintergrundbeleuchtung ----- Const Ir_helligkeit_min = 0 ' minimale Helligkeit Const Ir_helligkeit_max = 255 ' maximale Helligkeit Const Ir_helligkeit_aus = 255 ' Bytewert für Ir-Aus ' ----- Systemkonstanten für Ethernetcontroller ENC28J60 ----- ' Konstante für DHCP-Handling Const Dhcp_aus = 0 ' Steuerungswert für DHCP ausgeschaltet / ausschalten Const Dhcp_ein = 1 ' Steuerungswert für DHCP eingeschaltet / einschalten ' Maximale Ethernet Framelänge Const Max_framelen = 900 ' Sendebuffergröße, aktuell benötigt ca. 850 Bytes ' hier könnte bei Bedarf noch optimiert werden ' Konstanten für das DHCP-Handling Const Dhcp_pack_request = &H01 ' OP Byte: 1=request, 2=reply Const Dhcp_htype10mb = &H01 ' HW Type: 1 = 10 MBit Ethernet Const Dhcp_htype100mb = &H02 ' 2 = Experimental Ethernet Const Dhcp_hlenethernet = &H06 ' Länge der physikalischen Netzadresse in Bytes (z. B. 6 = MAC/Ethernet-Adresse) Const Dhcp_hops = &H00 ' Anzahl der DHCP-Relay-Agents auf dem Datenpfad Const Dhcp_secs = &H00 ' Zeit in Sekunden seit dem Start des Clients Const Dhcp_flags = &H80 ' Z. Zt. wird nur das erste Bit verwendet (zeigt an, ob der Client noch eine gültige ' IP-Adresse hat), die restlichen Bits sind für spätere Protokollerweiterungen reserviert ' Host Name Option - Code 12 ' ========================== ' This option specifies the name of the client. The name may or may ' not be qualified with the local domain name (see section 3.17 for the ' preferred way to retrieve the domain name). See RFC 1035 for ' character set restrictions. ' ' The code for this option is 12, and its minimum length is 1. ' ' Code Len Host Name ' +-----+-----+-----+-----+-----+-----+-----+-----+-- ' | 12 | n | h1 | h2 | h3 | h4 | h5 | h6 | ... ' +-----+-----+-----+-----+-----+-----+-----+-----+-- Const Dhcphostname = 12 ' Requested IP Address - Code 50 ' ============================== ' This option is used in a client request (DHCPDISCOVER) to allow the ' client to request that a particular IP address be assigned. ' ' The code for this option is 50, and its length is 4. ' ' Code Len Address ' +-----+-----+-----+-----+-----+-----+ ' | 50 | 4 | a1 | a2 | a3 | a4 | ' +-----+-----+-----+-----+-----+-----+ Const Dhcprequestipaddress = 50 ' DHCP Message Type - Option-Code 53 ' ================================== ' This option is used to convey the type of the DHCP message. The code ' for this option is 53, and its length is 1. Legal values for this ' option are: ' ' Value Message Type Code Len Type ' ----- ------------ +-----+-----+-----+ ' 1 DHCPDISCOVER | 53 | 1 | 1-9 | ' 2 DHCPOFFER +-----+-----+-----+ ' 3 DHCPREQUEST ' 4 DHCPDECLINE ' 5 DHCPACK ' 6 DHCPNAK ' 7 DHCPRELEASE ' 8 DHCPINFORM Const Dhcpmessagetype = 53 Const Dhcp_opt53_discover = &H01 Const Dhcp_opt53_dhcprequest = &H03 ' Parameter Request List - Option-Code 55 ' ======================================= ' This option is used by a DHCP client to request values for specified ' configuration parameters. The list of requested parameters is ' specified as n octets, where each octet is a valid DHCP option code ' ' The client MAY list the options in order of preference. The DHCP ' server is not required to return the options in the requested order, ' but MUST try to insert the requested options in the order requested ' by the client. ' ' The code for this option is 55. Its minimum length is 1. ' ' Code Len Option Codes ' +-----+-----+-----+-----+--- ' | 55 | n | c1 | c2 | ... ' +-----+-----+-----+-----+--- Const Dhcpparamrequest = 55 ' Subnet Mask ' =========== ' The subnet mask option specifies the client's subnet mask as per RFC 950 [5]. ' ' If both the subnet mask and the router option are specified in a DHCP ' reply, the subnet mask option MUST be first. ' The code for the subnet mask option is 1, and its length is 4 octets. ' ' Code Len Subnet Mask ' +-----+-----+-----+-----+-----+-----+ ' | 1 | 4 | m1 | m2 | m3 | m4 | ' +-----+-----+-----+-----+-----+-----+ Const Subnet_mask = 1 ' Router Option ' ============= ' The router option specifies a list of IP addresses for routers on the ' client's subnet. Routers SHOULD be listed in order of preference. ' ' The code for the router option is 3. The minimum length for the ' router option is 4 octets, and the length MUST always be a multiple of 4. ' ' Code Len Address 1 Address 2 ' +-----+-----+-----+-----+-----+-----+-----+-----+-- ' | 3 | n | a1 | a2 | a3 | a4 | a1 | a2 | ... ' +-----+-----+-----+-----+-----+-----+-----+-----+-- Const Router = 3 ' Domain Name Server Option ' ========================= ' The domain name server option specifies a list of Domain Name System ' (STD 13, RFC 1035 [8]) name servers available to the client. Servers ' SHOULD be listed in order of preference. ' ' The code for the domain name server option is 6. The minimum length ' for this option is 4 octets, and the length MUST always be a multiple of 4. ' ' Code Len Address 1 Address 2 ' +-----+-----+-----+-----+-----+-----+-----+-----+-- ' | 6 | n | a1 | a2 | a3 | a4 | a1 | a2 | ... ' +-----+-----+-----+-----+-----+-----+-----+-----+-- Const Dns = 6 ' End Option ' ========== ' The end option marks the end of valid information in the vendor ' field. Subsequent octets should be filled with pad options. ' ' The code for the end option is 255, and its length is 1 octet. ' ' Code ' +-----+ ' | 255 | ' +-----+ Const Endoption = 255 ' ----- TCP/IP Protokollhandling ----- Const Synflag = 0 ' Synchronize flag Const Finflag = 1 ' Finish flag Const Urg = 5 ' Urgent flag Const _ack = 4 ' Acknowledge flag Const Psh = 3 ' Push flag Const Rst = 2 ' Reset flag Const Syn = 1 ' Synchronisation flag Const Fin = 0 ' Finalisation flag Const Tcp_data = 55 ' Zeiger ab dem die TCP Payload beginnt Const Ip_header_const = 40 ' Konstante gibt die Größe des IP Headers an ' ----- Konstanten für EEProm Datenhandling und persistente Daten ----- ' Version EEPROM-Datenstruktur intern Const Akt_internal_ee_version = &H01 ' Version 1 ' Default-Werte für Persistente Daten Const Default_data_dhcp = &H00 ' DHCP = NEIN ' Default-Werte für eigene IP-Adresse, festgelegt mit 192.168.2.70 Const Default_data_ip_adr_1 = &HC0 ' 0xC0 = 192 Const Default_data_ip_adr_2 = &HA8 ' 0xA8 = 168 Const Default_data_ip_adr_3 = &H02 ' 0x02 = 2 Const Default_data_ip_adr_4 = &H46 ' 0x46 = 70 ' Defaultwert für Subnetzmaske im Netz, festgelegt mit 255.255.255.0 Const Default_data_submask_1 = &HFF ' 0xFF = 255 Const Default_data_submask_2 = &HFF ' 0xFF = 255 Const Default_data_submask_3 = &HFF ' 0xFF = 255 Const Default_data_submask_4 = &H00 ' 0x00 = 0 ' Defaultwert für Gateway (Router), festgelegt mit 192.168.2.1 Const Default_data_gateway_1 = &HC0 ' 0xC0 = 192 Const Default_data_gateway_2 = &HA8 ' 0xA8 = 168 Const Default_data_gateway_3 = &H02 ' 0x02 = 2 Const Default_data_gateway_4 = &H01 ' 0x01 = 1 ' Defaultwert für eigene MAC-Adresse, festgelegt mit 00:BD:3B:33:05:71 Const Default_data_mac_1 = &H00 ' 0x00 Const Default_data_mac_2 = &HBD ' 0xBD Const Default_data_mac_3 = &H3B ' 0x3B Const Default_data_mac_4 = &H33 ' 0x33 Const Default_data_mac_5 = &H05 ' 0x05 Const Default_data_mac_6 = &H71 ' 0x71 ' Defaultwert für MAC-Adresse des Routers, festgelegt mit 84:A8:E4:9B:31:D5 Const Default_data_mac_router_1 = &H84 ' 0x84 Const Default_data_mac_router_2 = &HA8 ' 0xA8 Const Default_data_mac_router_3 = &HE4 ' 0xE4 Const Default_data_mac_router_4 = &H9B ' 0x9B Const Default_data_mac_router_5 = &H31 ' 0x31 Const Default_data_mac_router_6 = &HD5 ' 0xD5 ' Defaultwert für einen NTP-Server, festgelegt mit 192.53.103.108 (ptbtime1.ptb.de) Const Default_data_ntp_1 = &HC0 ' 0xC0 = 192 Const Default_data_ntp_2 = &H35 ' 0x35 = 53 Const Default_data_ntp_3 = &H67 ' 0x67 = 103 Const Default_data_ntp_4 = &H6C ' 0x6C = 108 ' Defaultwert für TCP Portnummer, festgelegt mit 5000 Const Default_data_port = &H1388 ' 0x1388 = 5000 ' Defaultwert für Betriebsmodus, festgelegt mit "automatischer Betrieb Licht" = 1 Const Default_data_runningmode = &H01 ' 0x01 = 1 ' Defaultwert für PWM-Wert der IR-Hintegrundbeleuchtung, festgelegt mit 50 (empirisch ermittelt) Const Default_data_irhelligkeit = &H32 ' 0x32 = 50 ' Defaultwert für untere Grenzhelligkeit, festgelegt mit 400 Const Default_data_ldr_lower = &H190 ' 0x190 = 400 ' Defaultwert für obere Grenzhelligkeit, festgelegt mit 600 Const Default_data_ldr_upper = &H258 ' 0x258 = 600 ' Defaultwert für Schaltzeit bei Timerbetrieb, festgelegt mit 5 Minuten = 300 Const Default_data_videotimer = &H12C ' 0x12C = 300 '------------------------------------------------------------------------------ ' Definition von Variablen und Datentypen '------------------------------------------------------------------------------ ' ----- globale Arbeitsvariablen ----- Dim Temp_byte_1 As Byte ' globale Arbeitsvariable vom Type BYTE Dim Temp_word_1 As Word ' globale Arbeitsvariable vom Type WORD Dim Temp_word_2 As Word ' globale Arbeitsvariable vom Type WORD Dim Temp_word_3 As Word ' globale Arbeitsvariable vom Type WORD Dim Temp_char_1 As String * 1 ' globale Arbeitsvariable vom Type CHAR ' ----- globale Variablen für Timer und Scheduler ----- ' Scheduler-Variable DWord = 0 bis 4294967295. Variable wird sekündlich erhöht ' ==> 4294967295 / 60 Sekunden / 60 Minuten / 24 Stunden / 365 Tage = ca. 136 Jahre Reichweite!! Dim Scheduler_timer_counter As Dword ' globale Scheuler-Variable als Bezugspunkt ' ----- Internes EEPROM Datenstrukturen und persistente Datenhaltung ----- Dim Ee_data_version_intern As Eram Byte At &H0000 ' Speicherstelle für Datenversion Dim Ee_data_dhcp As Eram Byte At &H0001 ' Einstellung ob DHCP verwendet wird oder nicht Dim Ee_data_ip_adr_1 As Eram Byte At &H0002 ' Byte 1 der fest eingestellten eigenen IP-Adresse Dim Ee_data_ip_adr_2 As Eram Byte At &H0003 ' Byte 2 der fest eingestellten eigenen IP-Adresse Dim Ee_data_ip_adr_3 As Eram Byte At &H0004 ' Byte 3 der fest eingestellten eigenen IP-Adresse Dim Ee_data_ip_adr_4 As Eram Byte At &H0005 ' Byte 4 der fest eingestellten eigenen IP-Adresse Dim Ee_data_submask_1 As Eram Byte At &H0006 ' Byte 1 der Subnetzmaske Dim Ee_data_submask_2 As Eram Byte At &H0007 ' Byte 2 der Subnetzmaske Dim Ee_data_submask_3 As Eram Byte At &H0008 ' Byte 3 der Subnetzmaske Dim Ee_data_submask_4 As Eram Byte At &H0009 ' Byte 4 der Subnetzmaske Dim Ee_data_gateway_1 As Eram Byte At &H000A ' Byte 1 der IP-Adresse des Routers Dim Ee_data_gateway_2 As Eram Byte At &H000B ' Byte 2 der IP-Adresse des Routers Dim Ee_data_gateway_3 As Eram Byte At &H000C ' Byte 3 der IP-Adresse des Routers Dim Ee_data_gateway_4 As Eram Byte At &H000D ' Byte 4 der IP-Adresse des Routers Dim Ee_data_mac_1 As Eram Byte At &H000E ' Byte 1 der eigenen MAC-Adresse Dim Ee_data_mac_2 As Eram Byte At &H000F ' Byte 2 der eigenen MAC-Adresse Dim Ee_data_mac_3 As Eram Byte At &H0010 ' Byte 3 der eigenen MAC-Adresse Dim Ee_data_mac_4 As Eram Byte At &H0011 ' Byte 4 der eigenen MAC-Adresse Dim Ee_data_mac_5 As Eram Byte At &H0012 ' Byte 5 der eigenen MAC-Adresse Dim Ee_data_mac_6 As Eram Byte At &H0013 ' Byte 6 der eigenen MAC-Adresse Dim Ee_data_mac_router_1 As Eram Byte At &H0014 ' Byte 1 der Router MAC-Adresse Dim Ee_data_mac_router_2 As Eram Byte At &H0015 ' Byte 2 der Router MAC-Adresse Dim Ee_data_mac_router_3 As Eram Byte At &H0016 ' Byte 3 der Router MAC-Adresse Dim Ee_data_mac_router_4 As Eram Byte At &H0017 ' Byte 4 der Router MAC-Adresse Dim Ee_data_mac_router_5 As Eram Byte At &H0018 ' Byte 5 der Router MAC-Adresse Dim Ee_data_mac_router_6 As Eram Byte At &H0019 ' Byte 6 der Router MAC-Adresse Dim Ee_data_ntp_1 As Eram Byte At &H001A ' Byte 1 der IP-Adresse des NTP-Servers Dim Ee_data_ntp_2 As Eram Byte At &H001B ' Byte 2 der IP-Adresse des NTP-Servers Dim Ee_data_ntp_3 As Eram Byte At &H001C ' Byte 3 der IP-Adresse des NTP-Servers Dim Ee_data_ntp_4 As Eram Byte At &H001D ' Byte 4 der IP-Adresse des NTP-Servers Dim Ee_data_port As Eram Word At &H001E ' Eigene TCP Portnummer für Kommunikations Dim Ee_data_runningmode As Eram Byte At &H0020 ' Einstellung für den Betriebsmodus Dim Ee_data_irhelligkeit As Eram Byte At &H0021 ' PWM Einstellung für Helligkeit IR Hintergrundbeleuchtung Dim Ee_data_ldr_lower As Eram Word At &H0022 ' Einstellung für die untere Helligkeitsgrenze Dim Ee_data_ldr_upper As Eram Word At &H0024 ' Einstellung für die untere Helligkeitsgrenze Dim Ee_data_videotimer As Eram Word At &H0026 ' Schaltzeit in Sekunden in der zwischen Videoquelle 1 und 2 hin- und hergeschaltet wird. ' ----- ENC28J60 Ethernetcontroller ----- ' Arbeitsvariablen für Persistancy Dim Enc28j60_dhcp_flag As Byte ' Globale Variable für DHCP Steuerung Dim Enc28j60_my_ip_adress(4) As Byte ' Globales Datenarray für eigene IP-Adresse Dim Enc28j60_my_ip As Long At Enc28j60_my_ip_adress Overlay ' Globale Variable für eigene IP-Adresse Overlay Dim Enc28j60_subnetmask(4) As Byte ' Globales Datenarray für Subnetzmaske Dim Enc28j60_submask As Long At Enc28j60_subnetmask Overlay ' Globale Variable für Subnetzmaske Overlay Dim Enc28j60_gateway_ip_adress(4) As Byte ' Globales Datenarray für IP-Adresse Gateway Dim Enc28j60_gateway_ip As Long At Enc28j60_gateway_ip_adress Overlay ' Globale Variable für IP-Adresse Gateway Overlay Dim Enc28j60_my_mac_adress(6) As Byte ' Globales Datenarray für eigene MAC-Adresse Dim Enc28j60_router_mac_adress(6) As Byte ' Globales Datenarray für MAC-Adresse des Routers Dim Enc28j60_ntp_ip_adress(4) As Byte ' Globales Datenarray für IP-Adresse des Zeitservers Dim Enc28j60_ntp_ip As Long At Enc28j60_ntp_ip_adress Overlay ' Globale Variable für IP-Adresse des Zeitservers Overlay Dim Enc28j60_tcp_port As Word ' Globale Variable für TCP-Portadresse ' Datenstrukturen für das Senden und Empfangen von Daten Dim Ctrl_array(5) As Byte ' Globales Datenarray zur Control-Kommunikation mit ENC28J60 (Command & Control) Dim Com_array(max_framelen) As Byte ' Globales Datenarray zur Daten-Kommunikation mit ENC28J60 (Daten) ' Für den Zugriff auf den Daten-Kommunikationsbuffer werden nun einige Overlays ' definiert welche einen Strukturieren Zugriff auf die Inhalte ermöglichen -> besseres Handling ' Variablennamen und Overlaystruktur wird 1:1 aus Ben's Tutorial übernommen ' Ethernet packet destination Dim T_enetpacketdest0 As Byte At Com_array Overlay ' Com_array[1] Ethernet-Paket: DestinationMAC-addr. 1 Dim T_enetpacketdest1 As Byte At Com_array + &H01 Overlay ' Com_array[2] Ethernet-Paket: DestinationMAC-addr. 2 Dim T_enetpacketdest2 As Byte At Com_array + &H02 Overlay ' Com_array[3] Ethernet-Paket: DestinationMAC-addr. 3 Dim T_enetpacketdest3 As Byte At Com_array + &H03 Overlay ' Com_array[4] Ethernet-Paket: DestinationMAC-addr. 4 Dim T_enetpacketdest4 As Byte At Com_array + &H04 Overlay ' Com_array[5] Ethernet-Paket: DestinationMAC-addr. 5 Dim T_enetpacketdest5 As Byte At Com_array + &H05 Overlay ' Com_array[6] Ethernet-Paket: DestinationMAC-addr. 6 ' Ethernet packet source Dim T_enetpacketsrc0 As Byte At Com_array + &H06 Overlay ' Com_array[7] Ethernet-Paket: Source MAC-address 1 Dim T_enetpacketsrc1 As Byte At Com_array + &H07 Overlay ' Com_array[8] Ethernet-Paket: Source MAC-address 2 Dim T_enetpacketsrc2 As Byte At Com_array + &H08 Overlay ' Com_array[9] Ethernet-Paket: Source MAC-address 3 Dim T_enetpacketsrc3 As Byte At Com_array + &H09 Overlay ' Com_array[10] Ethernet-Paket: Source MAC-address 4 Dim T_enetpacketsrc4 As Byte At Com_array + &H0A Overlay ' Com_array[11] Ethernet-Paket: Source MAC-address 5 Dim T_enetpacketsrc5 As Byte At Com_array + &H0B Overlay ' Com_array[12] Ethernet-Paket: Source MAC-address 6 ' Ethernet packet type Dim T_enetpackettype As Word At Com_array + &H0C Overlay ' Com_array[13] Ethernet-Paket: Packettype 0 und ' Com_array[14] Ethernet-Paket: Packettype 1 (WORD) ' ARP control structure Dim T_arp_hwtype0 As Byte At Com_array + &H0E Overlay ' Com_array[15] ARP: hwtype 0 Dim T_arp_hwtype1 As Byte At Com_array + &H0F Overlay ' Com_array[16] ARP: hwtype 1 Dim T_arp_prttype0 As Byte At Com_array + &H10 Overlay ' Com_array[17] ARP: prtype 0 Dim T_arp_prttype1 As Byte At Com_array + &H11 Overlay ' Com_array[18] ARP: prtype 1 Dim T_arp_hwlen As Byte At Com_array + &H12 Overlay ' Com_array[19] ARP: hwlen Dim T_arp_prlen As Byte At Com_array + &H13 Overlay ' Com_array[20] ARP: prlen Dim T_arp_op0 As Byte At Com_array + &H14 Overlay ' Com_array[21] ARP: op 0 Dim T_arp_op1 As Byte At Com_array + &H15 Overlay ' Com_array[22] ARP: op 1 ' ARP source mac address Dim T_arp_src_enetpacket0 As Byte At Com_array + &H16 Overlay ' Com_array[23] ARP: Source MAC-address 1 Dim T_arp_src_enetpacket1 As Byte At Com_array + &H17 Overlay ' Com_array[24] ARP: Source MAC-address 2 Dim T_arp_src_enetpacket2 As Byte At Com_array + &H18 Overlay ' Com_array[25] ARP: Source MAC-address 3 Dim T_arp_src_enetpacket3 As Byte At Com_array + &H19 Overlay ' Com_array[26] ARP: Source MAC-address 4 Dim T_arp_src_enetpacket4 As Byte At Com_array + &H1A Overlay ' Com_array[27] ARP: Source MAC-address 5 Dim T_arp_src_enetpacket5 As Byte At Com_array + &H1B Overlay ' Com_array[28] ARP: Source MAC-address 6 ' ARP source ip address Dim T_arp_sipaddr0 As Byte At Com_array + &H1C Overlay ' Com_array[29] ARP: IP Source 0 Dim T_arp_sipaddr1 As Byte At Com_array + &H1D Overlay ' Com_array[30] ARP: IP Source 1 Dim T_arp_sipaddr2 As Byte At Com_array + &H1E Overlay ' Com_array[31] ARP: IP Source 2 Dim T_arp_sipaddr3 As Byte At Com_array + &H1F Overlay ' Com_array[32] ARP: IP Source 3 ' ARP source mac address Dim T_arp_dest_enetpacket0 As Byte At Com_array + &H20 Overlay ' Com_array[33] ARP: DestinationMAC-addr. 1 Dim T_arp_dest_enetpacket1 As Byte At Com_array + &H21 Overlay ' Com_array[34] ARP: DestinationMAC-addr. 2 Dim T_arp_dest_enetpacket2 As Byte At Com_array + &H22 Overlay ' Com_array[35] ARP: DestinationMAC-addr. 3 Dim T_arp_dest_enetpacket3 As Byte At Com_array + &H23 Overlay ' Com_array[36] ARP: DestinationMAC-addr. 4 Dim T_arp_dest_enetpacket4 As Byte At Com_array + &H24 Overlay ' Com_array[37] ARP: DestinationMAC-addr. 5 Dim T_arp_dest_enetpacket5 As Byte At Com_array + &H25 Overlay ' Com_array[38] ARP: DestinationMAC-addr. 6 ' ARP target IP address Dim T_arp_tipaddr0 As Byte At Com_array + &H26 Overlay ' Com_array[39] ARP: IP Destination 0 Dim T_arp_tipaddr1 As Byte At Com_array + &H27 Overlay ' Com_array[40] ARP: IP Destination 1 Dim T_arp_tipaddr2 As Byte At Com_array + &H28 Overlay ' Com_array[41] ARP: IP Destination 2 Dim T_arp_tipaddr3 As Byte At Com_array + &H29 Overlay ' Com_array[42] ARP: IP Destination 3 Dim T_arp_tipaddr As Long At Com_array + &H26 Overlay ' Com_array[39] ARP: IP Destination 0-3 in LONG ' IP header layout Dim T_ip_vers_len As Byte At Com_array + &H0E Overlay ' Com_array[15] IP: version and length Dim T_tos As Byte At Com_array + &H0F Overlay ' Com_array[16] IP: tos Dim T_ip_pktlen0 As Byte At Com_array + &H10 Overlay ' Com_array[17] IP: packet-length h Dim T_ip_pktlen1 As Byte At Com_array + &H11 Overlay ' Com_array[18] IP: packet-length l Dim T_id0 As Byte At Com_array + &H12 Overlay ' Com_array[19] IP: id 0 Dim T_id1 As Byte At Com_array + &H13 Overlay ' Com_array[20] IP: id1 Dim T_flags As Byte At Com_array + &H14 Overlay ' Com_array[21] IP: flags / frag-offset 0 Dim T_offset As Byte At Com_array + &H15 Overlay ' Com_array[22] IP: frag-offset 1 Dim T_ttl As Byte At Com_array + &H16 Overlay ' Com_array[23] IP: Time to live ' protocol (ICMP=1, TCP=6, UDP=11) Dim T_ip_proto As Byte At Com_array + &H17 Overlay ' Com_array[24] IP: Protocol ' header checksum Dim T_ip_hdr_cksum0 As Byte At Com_array + &H18 Overlay ' Com_array[25] IP: Headerchecksum h Dim T_ip_hdr_cksum1 As Byte At Com_array + &H19 Overlay ' Com_array[26] IP: Headerchecksum l Dim T_ip_hdr_cksum As Word At Com_array + &H18 Overlay ' Com_array[25] IP: Headerchecksum h + Headerchecksum l in WORD ' IP address of source Dim T_ip_srcaddr0 As Byte At Com_array + &H1A Overlay ' Com_array[27] IP: Sourceaddress 0 Dim T_ip_srcaddr1 As Byte At Com_array + &H1B Overlay ' Com_array[28] IP: Sourceaddress 1 Dim T_ip_srcaddr2 As Byte At Com_array + &H1C Overlay ' Com_array[29] IP: Sourceaddress 2 Dim T_ip_srcaddr3 As Byte At Com_array + &H1D Overlay ' Com_array[30] IP: Sourceaddress 3 Dim T_ip_srcaddr As Long At Com_array + &H1A Overlay ' Com_array[27] IP: Sourceaddress 0-3 in LONG ' IP address of destination Dim T_ip_destaddr0 As Byte At Com_array + &H1E Overlay ' Com_array[31] IP: Destinationaddress 0 Dim T_ip_destaddr1 As Byte At Com_array + &H1F Overlay ' Com_array[32] IP: Destinationaddress 1 Dim T_ip_destaddr2 As Byte At Com_array + &H20 Overlay ' Com_array[33] IP: Destinationaddress 2 Dim T_ip_destaddr3 As Byte At Com_array + &H21 Overlay ' Com_array[34] IP: Destinationaddress 3 Dim T_ip_destaddr As Long At Com_array + &H1E Overlay ' Com_array[31] IP: Destinationaddress 0-3 in LONG ' IP - ICMP Dim T_icmp_type As Byte At Com_array + &H22 Overlay ' Com_array[35] ICMP: Type Dim T_icmp_code As Byte At Com_array + &H23 Overlay ' Com_array[36] ICMP: Code Dim T_icmp_cksum0 As Byte At Com_array + &H24 Overlay ' Com_array[37] ICMP: Checksum h Dim T_icmp_cksum1 As Byte At Com_array + &H25 Overlay ' Com_array[38] ICMP: Checksum l Dim T_icmp_cksum As Word At Com_array + &H24 Overlay ' Com_array[37] ICMP: Checksum h + Checksum l in WORD ' IP - TCP Dim Tcp_srcporth As Byte At Com_array + &H22 Overlay ' Com_array[35] TCP: Sourceport h Dim Tcp_srcportl As Byte At Com_array + &H23 Overlay ' Com_array[36] TCP: Sourceport l Dim Tcp_destporth As Byte At Com_array + &H24 Overlay ' Com_array[37] TCP: Destinationport h Dim Tcp_destportl As Byte At Com_array + &H25 Overlay ' Com_array[38] TCP: Destinationport l Dim Tcp_destport As Word At Com_array + &H24 Overlay ' Com_array[37] TCP: Destinationport h + Destinationport l Dim Tcp_seqnum3 As Byte At Com_array + &H26 Overlay ' Com_array[39] TCP: Sequence-number 3 Dim Tcp_seqnum2 As Byte At Com_array + &H27 Overlay ' Com_array[40] TCP: Sequence-number 2 Dim Tcp_seqnum1 As Byte At Com_array + &H28 Overlay ' Com_array[41] TCP: Sequence-number 1 Dim Tcp_seqnum0 As Byte At Com_array + &H29 Overlay ' Com_array[42] TCP: Sequence-number 0 Dim Tcp_acknum3 As Byte At Com_array + &H2A Overlay ' Com_array[43] TCP: Acknowledgenumber 3 Dim Tcp_acknum2 As Byte At Com_array + &H2B Overlay ' Com_array[44] TCP: Acknowledgenumber 2 Dim Tcp_acknum1 As Byte At Com_array + &H2C Overlay ' Com_array[45] TCP: Acknowledgenumber 1 Dim Tcp_acknum0 As Byte At Com_array + &H2D Overlay ' Com_array[46] TCP: Acknowledgenumber 0 Dim Tcp_hdr As Byte At Com_array + &H2E Overlay ' Com_array[47] TCP: Header Dim Tcp_flags As Byte At Com_array + &H2F Overlay ' Com_array[48] TCP: Flags Dim Tcp_windowh As Byte At Com_array + &H30 Overlay ' Com_array[49] TCP: Window h Dim Tcp_windowl As Byte At Com_array + &H31 Overlay ' Com_array[50] TCP: Window l Dim Tcp_cksumh As Byte At Com_array + &H32 Overlay ' Com_array[51] TCP: Checksum h Dim Tcp_cksuml As Byte At Com_array + &H33 Overlay ' Com_array[52] TCP: Checksum l Dim Tcp_cksum As Word At Com_array + &H32 Overlay ' Com_array[51] TCP: Checksum h + Checksum l in WORD ' UDP header Dim T_udp_srcport0 As Byte At Com_array + &H22 Overlay ' Com_array[35] UDP: Sourceport h Dim T_udp_srcport1 As Byte At Com_array + &H23 Overlay ' Com_array[36] UDP: Sourceport l Dim T_udp_srcport As Word At Com_array + &H22 Overlay ' Com_array[35] UDP: Sourceport h + Sourceport l as WORD Dim T_udp_destport0 As Byte At Com_array + &H24 Overlay ' Com_array[37] UDP: Destinationport h Dim T_udp_destport1 As Byte At Com_array + &H25 Overlay ' Com_array[38] UDP: Destinationport l Dim T_udp_destport As Word At Com_array + &H24 Overlay ' Com_array[37] UDP: Destinationport h + Destinationport l Dim T_udp_len0 As Byte At Com_array + &H26 Overlay ' Com_array[39] UDP: Length h Dim T_udp_len1 As Byte At Com_array + &H27 Overlay ' Com_array[40] UDP: Length l Dim T_udp_len As Word At Com_array + &H26 Overlay ' Com_array[39] UDP: Length h + Length l as WORD Dim T_udp_chksum0 As Byte At Com_array + &H28 Overlay ' Com_array[41] UDP: Checksum h Dim T_udp_chksum1 As Byte At Com_array + &H29 Overlay ' Com_array[42] UDP: Checksum l Dim T_udp_chksum As Word At Com_array + &H28 Overlay ' Com_array[41] UDP: Checksum h + Checksum l as WORD ' UDP data Dim T_udp_data_array(32) As Byte At Com_array + &H2A Overlay Dim T_udp_data As Byte At Com_array + &H2A Overlay ' Com_array[43] UDP: UDP-data Dim T_udp_data1 As Byte At Com_array + &H2B Overlay ' Com_array[44] UDP: UDP-data Dim T_udp_data2 As Byte At Com_array + &H2C Overlay ' Com_array[45] UDP: UDP-data Dim T_udp_data3 As Byte At Com_array + &H2D Overlay ' Com_array[46] UDP: UDP-data Dim T_udp_data4 As Byte At Com_array + &H2E Overlay ' Com_array[47] UDP: UDP-data Dim T_udp_data5 As Byte At Com_array + &H2F Overlay ' Com_array[48] UDP: UDP-data Dim T_udp_data6 As Byte At Com_array + &H30 Overlay ' Com_array[49] UDP: UDP-data Dim T_udp_data7 As Byte At Com_array + &H31 Overlay ' Com_array[50] UDP: UDP-data Dim T_udp_data8 As Byte At Com_array + &H32 Overlay ' Com_array[51] UDP: UDP-data Dim T_udp_data9 As Byte At Com_array + &H33 Overlay ' Com_array[52] UDP: UDP-data Dim T_udp_data10 As Byte At Com_array + &H34 Overlay ' Com_array[53] UDP: UDP-data Dim T_udp_data11 As Byte At Com_array + &H35 Overlay ' Com_array[54] UDP: UDP-data Dim T_udp_data12 As Byte At Com_array + &H36 Overlay ' Com_array[55] UDP: UDP-data Dim T_udp_data13 As Byte At Com_array + &H37 Overlay ' Com_array[56] UDP: UDP-data Dim T_udp_data14 As Byte At Com_array + &H38 Overlay ' Com_array[57] UDP: UDP-data Dim T_udp_data15 As Byte At Com_array + &H39 Overlay ' Com_array[58] UDP: UDP-data Dim T_udp_data16 As Byte At Com_array + &H3A Overlay ' Com_array[59] UDP: UDP-data Dim T_udp_data17 As Byte At Com_array + &H3B Overlay ' Com_array[60] UDP: UDP-data Dim T_udp_data18 As Byte At Com_array + &H3C Overlay ' Com_array[61] UDP: UDP-data Dim T_udp_data19 As Byte At Com_array + &H3D Overlay ' Com_array[62] UDP: UDP-data Dim T_udp_data20 As Byte At Com_array + &H3E Overlay ' Com_array[63] UDP: UDP-data Dim T_udp_data21 As Byte At Com_array + &H3F Overlay ' Com_array[64] UDP: UDP-data Dim T_udp_data22 As Byte At Com_array + &H40 Overlay ' Com_array[65] UDP: UDP-data Dim T_udp_data23 As Byte At Com_array + &H41 Overlay ' Com_array[66] UDP: UDP-data Dim T_udp_data24 As Byte At Com_array + &H42 Overlay ' Com_array[67] UDP: UDP-data Dim T_udp_data25 As Byte At Com_array + &H43 Overlay ' Com_array[68] UDP: UDP-data Dim T_udp_data26 As Byte At Com_array + &H44 Overlay ' Com_array[69] UDP: UDP-data Dim T_udp_data27 As Byte At Com_array + &H45 Overlay ' Com_array[70] UDP: UDP-data Dim T_udp_data28 As Byte At Com_array + &H46 Overlay ' Com_array[71] UDP: UDP-data Dim T_udp_data29 As Byte At Com_array + &H47 Overlay ' Com_array[72] UDP: UDP-data Dim T_udp_data30 As Byte At Com_array + &H48 Overlay ' Com_array[73] UDP: UDP-data Dim T_udp_data31 As Byte At Com_array + &H49 Overlay ' Com_array[74] UDP: UDP-data Dim T_udp_data32 As Byte At Com_array + &H4A Overlay ' Com_array[75] UDP: UDP-data Dim Length As Word ' Globale Variable für Länge Ethernet-Frame Dim Rxstat As Word ' Globale Variable für 2 Byte RX Empfangsstatus ' Globale Hilfsvariablen für Funktionsübergreifenden Datenaustausch Dim Enc28j60_data As Byte ' Globale Byte Variable zur ENC28J60 Kommunikation (speziell für Kontrollregisterhandling) Dim Nextpacketptr As Word ' Globale Variable für Next Packet Pointer Dim I_checksum16 As Word ' 16 Bit Hilfsvariable für Checksummen Dim I_chksum32 As Long ' 32 Bit Hilfsvariable für Checksummen Dim Result16 As Word ' 16 Bit Hilfsvariable (WORD) Dim Result16h As Byte At Result16 + 1 Overlay ' Highbyte der Hilfsvariable Dim Result16l As Byte At Result16 Overlay ' Lowbyte der Hilfsvariable Dim I_value16 As Word ' 16 Bit Hilfsvariable (WORD) Dim I_value16h As Byte At I_value16 + 1 Overlay ' Highbyte der Hilfsvariable Dim I_value16l As Byte At I_value16 Overlay ' Lowbyte der Hilfsvariable ' Globale Variablen im Umgang mit DHCP Dim Xid(4) As Byte ' Globale Variable für eindeutige Verbindungs-ID ' Arbeitsvariablen für TCP Kontrollflags Dim Tcp_fin As Bit ' Schlussflag - dient zur Freigabe der Verbindung Dim Tcp_syn As Bit ' Pakete mit gesetztem SYN-Flag initiieren eine Verbindung Dim Tcp_rst As Bit ' Das Reset-Flag wird verwendet, wenn eine Verbindung abgebrochen werden soll Dim Tcp_psh As Bit ' Beim Versenden von Daten über das TCP werden zwei Puffer verwendet ' Bei gesetztem Flag wird sowohl der ausgehende, als auch der eingehende Puffer übergangen Dim Tcp_ack As Bit ' Das Acknowledgment-Flag hat in Verbindung mit der Acknowledgment-Nummer die Aufgabe, ' den Empfang von TCP-Segmenten beim Datentransfer zu bestätigen. Dim Tcp_urg As Bit ' Ist das Urgent-Flag (urgent = dringend) gesetzt, so werden die Daten nach dem Header ' sofort von der Anwendung bearbeitet. ' Arbeitsvariablen für TCP-Handling Dim Tempword As Word ' Temporäre WORD Arbeitsvariable mit Overlay Dim Tempwordh As Byte At Tempword + 1 Overlay Dim Tempwordl As Byte At Tempword Overlay Dim Acknum As Long Dim Acknum3 As Byte At Acknum Overlay Dim Acknum2 As Byte At Acknum + 1 Overlay Dim Acknum1 As Byte At Acknum + 2 Overlay Dim Acknum0 As Byte At Acknum + 3 Overlay Dim Seqnum As Long Dim Seqnum3 As Byte At Seqnum Overlay Dim Seqnum2 As Byte At Seqnum + 1 Overlay Dim Seqnum1 As Byte At Seqnum + 2 Overlay Dim Seqnum0 As Byte At Seqnum + 3 Overlay Dim Syncflag As Bit Dim Packetlength As Word ' ----- Arbeitsvariablen für Zentralsteuerung ----- ' Arbeitsvariablen für Persistancy Dim Control_runningmode As Byte ' Globale Variable für Betriebsmodus Dim Control_irhelligkeit As Byte ' Globale Variable für PWM-Wert IR Hintergrundbeleuchtung Dim Control_ldr_lower As Word ' Globale Variable für untere Helligkeitsgrenze Dim Control_ldr_upper As Word ' Globale Variable für obere Helligkeitsgrenze Dim Control_videotimer As Word ' Globale Variable für Schaltzeit Timer ' Arbeitsvariablen für die Steuerung der Kameras Dim Control_kamera_flag As Byte ' Globale Variable die anzeigt, welche Kamera gerade aktiv ist Dim Control_kamera1_pwr_flag As Byte ' Globale Variable die anzeigt, ob Kamera 1 bestromt ist oder nicht Dim Control_kamera2_pwr_flag As Byte ' Globale Variable die anzeigt, ob Kamera 2 bestromt ist oder nicht Dim Control_switch_kamera_request As Byte ' Globale Variable für das Umschalten von einer auf die andre (gibt an von wo nach wo) Dim Control_switch_kamera_status As Byte ' Globale Variable für den Status der Umschaltung (zeigt an ob Umschaltung noch läuft) Dim Control_switch_counter As Dword ' Globale Variable für die zeitliche Ablaufsteuerung der Umschaltung Dim Control_timer_mode_counter As Dword ' Globale Vraible für den Timer bei Zeitsteuerung ' ----- Arbeitsvariablen für Konsoleneingabe und Kommandoverarbeitung ----- Dim Consol_char_flag As Byte ' Flag zur Verarbeitung ob Zeichen in der RS232 auf Verarbeitung warten Dim Consol_instring As String * 32 ' Stringvariable zum Empfang von Kommandos über RS232 Dim Consol_outstring As String * 100 ' Stringvariable zum Ausgeben und Übergeben von Antwortstring Dim Consol_inchar As Byte ' Arbeitsvariable für das Handling einzelner Zeichen in der Kommandoverarbeitung Dim Consol_argument_array(10) As String * 20 ' Arbeitsmatrix für das Parsen von Kommandos Dim Consol_parameter_array(6) As Byte ' Arbeitsmatrix für das bereitstellen von geparsten Parametern Dim Consol_parameter_word As Word ' Globale Arbeitsvariable für das bereitstellen eines einzelnen geparsten Zahlenwerts Dim Consol_tcp_sequence_nummer As Byte ' Globale Variable steuert welche Teile gerade ausgegeben werden sollen ' Werte: 0 = nix ' 1 = Statusinfo ' 2 = Hilfe ' ----- Arbeitsvariablen für Lichtmessung via LDR ----- Dim Light_channel As Byte ' Variable für ADC-Kanal festlegen Dim Light_value As Word ' Variable für Helligkeitsmesswert Dim Light_timer As Dword ' Variable welche das erneute Lesen des Helligkeitswerts steuert ' ----- Arbeitsvariablen für IR Hintergrundbeleuchtung ----- Dim Ir_status_flag As Byte ' Variable welche den Status der IR-Hintergrundbeleuchtung angibt ' ----- Arbeitsvariablen für Relaissteuerung ----- Dim Relais_status_flag As Byte ' Globale Variable für Relais-Status '------------------------------------------------------------------------------ ' Prototyping '------------------------------------------------------------------------------ ' ========== Subroutinen ========== ' ----- Enc28j60 Funktion für Registerbankauswahl ----- Declare Sub Enc28j60_selectbank(byval Bank As Byte) ' Funktion zur Auswahl der entsprechenden Speicherbank ' ----- Enc28j60 Funktionen für die Controlregister ----- Declare Sub Enc28j60_readcontrolregbyte(byval Register As Byte) ' Funktion zum Lesen vonControlregistern Declare Sub Enc28j60_writecontrolregbyte(byval Register As Byte , Byval Value As Byte) ' Funktion zum Schreiben von Controlregistern Declare Sub Enc28j60_bitfield_set(byval Register As Byte , Byval Value As Byte) ' Funktion zum Setzen einzelner Bits in Controlregistern Declare Sub Enc28j60_bitfield_clear(byval Register As Byte , Byval Value As Byte) ' Funktion zum Löschen einzelner Bits in Controlregistern ' ----- Enc28j60 Funktionen für das PHY modul ----- Declare Sub Enc28j60_writephyword(byval Phyregister As Byte , Byval Phy_word As Word) ' Funktion zum Schreiben von Control-Worten in die PHY des Controllers ' ----- Enc28j60 Funktionen für allgemeines Handling und Betrieb ----- Declare Sub Enc28j60_init ' Init-Routine um bei Systemstart den Ethernetcontroller zu initialisieren Declare Sub Enc28j60_poll ' Polling-Routine in Hauptschleife für Paketeempfang und Verarbeitung Declare Sub Enc28j60_packetreceive ' Funktion zum Empfangen von Ethernetdaten Declare Sub Enc28j60_packetsend(byval Pcktlen As Word) ' Funktion zum Senden von Ethernetdaten Declare Sub Echopacket ' Funktion bereitet das Senden eines Datenpakets vor ' ----- Protokoll-Funktionen für das Ethernet ----- Declare Sub Arpreply ' Antwortroutine für ARP-Pakete Declare Sub Pingreply ' Antwortroutine für PING-Anfrage Declare Sub Udp_receive ' Antwortroutine für UDP-Pakete Declare Sub Tcp_receive ' Funktion zur Bearbeitung von TCP Paketen ' ----- Enc28j60 Funktionen zum DHCP Handling ----- Declare Sub Send_dhcp_discover ' Funktion zum Senden der Sequence DHCP Discover Declare Sub Send_dhcp_request ' Funktion zum Senden der Sequence DHCP Request Declare Sub Dhcp_receive ' Funktion zum Verarbeiten einder UDP-Nachricht mit Port 67 und 68 Declare Sub Dhcp_ack ' Funktiom zum Verarbeiten der DHCP Ack-Antwort und Festlegung der IP-Adresse ' ----- Enc28j60 Funktionen zum UDP Processing ----- Declare Sub Udp_processing ' Funktion zum Verarbeiten von UDP-Datenpaketen ' ----- Enc28j60 Funktionen zum TCP Processing ----- Declare Sub Tcp_processing ' Funktion zum bearbeiten der eigenen BirdView-TCP-Session Declare Sub Ack2tcp_ack ' Funktion zum Eintragen von Acknowledgement in Buffer eintragen Declare Sub Seq2tcp_seq ' Funktion zum Eintragen von Sequence number in Buffer eintragen Declare Sub Swapsrc2dest ' Funktion zum MAC-Adressen im Ethernetframe von Source und Destination vertauschen ' ----- Hilfsfunktionen für das Ethernet ----- Declare Sub Clearbuff ' Funktion zum Löschen des gesamten Sende- / Empfangsbuffers im RAM Declare Sub Setipaddrs ' Kopiert SourceIP auf DestinationIP, setzt eigene IP als SourceIP, erzeugt IP-Header Checksumme Declare Sub Src2dest ' Kopier Ethernet Source-MAC auf Destination-MAC Declare Sub Src2mymac ' Setzt eigene MAC-Adresse als Ethernet Source-MAC Declare Sub Swapdestport2srcport ' Routine vertauscht TCP Sourceport und TCP Destinationport miteinander. Declare Sub Ip_header_checksum ' Checksummenberechnung mit TCP-Lib von MCS Declare Sub Icmp_checksum ' Berechnet ICMP-Checksumme Declare Sub Udp_checksum ' Checksummenberechnung mit TCP-Lib von MCS Declare Sub Srcdestchksum ' Routine berechnet Teil der TCP Prüfsumme, bestehend aus Teil des TCP Pseudoheaders Declare Sub Tcp_checksum ' Checksummenberechnung für TCP-Checksumme ' ----- Control Funktionen zur Steuerung von Aktoren ----- Declare Sub Control_pwr_cam1(byval Pwr_status As Byte) ' Funktion zum Steuern der Betriebspannung für Kamera 1 Declare Sub Control_pwr_cam2(byval Pwr_status As Byte) ' Funktion zum Steuern der Betriebspannung für Kamera 2 ' ----- IR Hintergrundbeleuchtung ----- Declare Sub Ir_set_helligkeit(byval Value As Byte) ' Funktion zum Einstellen der IR Helligkeit ' ========== Funktionen ========== ' ----- Enc28j60 Funktionen für das PHY modul ----- Declare Function Enc28j60_readphyword(byval Phyregister As Byte) As Word ' Funktion zum Lesen von Control-Worten in die PHY des Controllers ' ----- Consol Funktionen für die Kommandoverarbeitung ----- Declare Function Consol_process_command(command_string As String , Byval Command_source As Byte) As Byte ' Verarbeitung von Kommandozeilen ' ----- Lichtmessung mit LDR ----- Declare Function Light_measurement() As Word ' Funktion zum Messen der Helligkeit mittels ADC '------------------------------------------------------------------------------ ' Konfiguration und Basiseinstellungen (Projekt und Testumgebung) '------------------------------------------------------------------------------ ' --------------------------------- CONFIG ------------------------------------ ' ----- Timer ----- ' Konfiguration eines Timers für 1 Sekunden Timer-Tick (Scheduler und Alive) Config Timer1 = Timer , Prescale = 256 ' Timer 1 verwenden On Timer1 Sekunden_tick ' Interrupt Routine Timer1 = Timervorgabe Enable Timer1 ' Interrupt für Sekunden-Tack ' Konfiguration Timer 2 für Hardware-PWM an OC2 (D.7) Config Timer2 = Pwm , Prescale = 32 , Compare Pwm = Clear Up ' ----- Ethernet Controller ENC28J60 ----- ' Config SPI-Bus für Anbindung Ethernetcontroller Config Spi = Hard , Interrupt = Off , Data Order = Msb , Master = Yes , Polarity = Low , Phase = 0 , Clockrate = 4 , Noss = 1 Spiinit ' Init SPI pins ' ----- Konfiguration ADC0 ----- ' Konfiguration ADC Single-Mode und automatische Prescaler Setting ' Der Single-Mode wir bei BASCOM in Verbindung mit der Funktion GETADC() verwendet ' Der Prescaler teilt den internen Tackt durch 2, 4, 8,16,32,64 or 128 da der ADC ' einen Takt zwischen 50-200 kHz benötigt. ' Das AUTO Feature von BASCOM, setzt automatisch die höchste mögliche Taktrate Config Adc = Single , Prescaler = Auto ' , Reference = OFF Start Adc ' ------------------------------- Port's und Pin's ---------------------------- ' ----- Ethernet Controller ENC28J60 ----- Config Enc28j60_cs = Output ' Chipselect ' ----- LED-Konfigurationen ----- ' Alle relevanten GPIO-Pin's für die LED's als OUTPUT konfigurieren Config Mode_led_pin = Output Config Video2_led_pin = Output Config Video1_led_pin = Output Config Ir_led_pin = Output Config Proc_led_pin = Output Config Alive_led_pin = Output ' ----- Tastenkonfiguration ----- ' Alle relevanten GPIO-Pin's als INPUT konfigurieren Config Key_1_pin = Input Config Key_2_pin = Input Config Key_3_pin = Input ' PullUps werden via default aktiviert. PullUp sind in Beschaltung vorgesehen ' darum hier PullUp deaktivieren Key_1 = Pullup_aus Key_2 = Pullup_aus Key_3 = Pullup_aus ' ----- Relaisstufe und Schaltstufen für Spannungsversorgungen ----- ' Alle relevanten GPIO-Pin's als OUTPUT konfigurieren Config Pwr_cam1_pin = Output Config Pwr_cam2_pin = Output Config Relais_pin = Output ' ----- Videomultiplexer ----- ' Alle relevanten GPIO-Pin's als OUTPUT konfigurieren Config Video_select_pin = Output ' ----- Tastatur ----- ' Entprellung für debounce einstellen Config Debounce = 10 ' Herstellerangaben: Contact bounce less than 10 msec ' ------------------------------ Variablen und Werte -------------------------- ' ----- Ethernet Controller ENC28J60 ----- ' Chipselect zurücknehmen Enc28j60_cs = 1 ' Eindeutige Verbindungs-ID für DHCP vorbelegen (willkürlich festgelegt) Xid(1) = &H1F Xid(2) = &H45 Xid(3) = &H3A Xid(4) = &HDE ' ----- LED-Konfigurationen ----- Mode_led = Led_aus ' LED für Betriebsmodus zunächst AUS, richtige Betriebsart später ... Video2_led = Led_aus ' LED für Kamera 2 aktiv bei Systemstart aus Video1_led = Led_aus ' LED für Kamera 1 aktiv bei Systemstart aus Ir_led = Led_aus ' LED für aktive Hintergrundbeleuchtung bei Systemstart aus Proc_led = Led_aus ' LED für Ethernet-Paketverarbeitung bei Systemstart aus Alive_led = Led_aus ' Alive-LED bei Systemstart aus ' ----- Relaisstufe und Schaltstufen für Spannungsversorgungen ----- Call Control_pwr_cam1(aus) ' Spannung für Kamera 1 aus Call Control_pwr_cam2(aus) ' Spannung für Kamera 2 aus Relais = Relais_aus ' Relais aus Relais_status_flag = Relais_aus ' Relais aus ' ----- Videomultiplexer ----- ' Wenn System startet soll Farbkamera (Kamera 2) aktiv sein Video_select = Kanal_2 ' Videomultiplexer Kanal 2 geschaltet ' ----- Consol: Kommandoverarbeitung ----- ' Globale Stringvariablen zurücksetzen und mit NULL-String initialisieren Consol_instring = "" Consol_outstring = "" Consol_tcp_sequence_nummer = Sequence_nix ' Leersequence ' ----- Scheduler: Timer und Counter-Variablen für Zeitsteuerung ----- Scheduler_timer_counter = 0 ' Initialisierung ' ----- Lichtmessung via LDR ----- Light_channel = 0 ' LDR hängt an ADC0 Light_timer = Scheduler_timer_counter + Light_timer_intervall ' Timerfür Helligkeitsmessung initialisieren ' ----- Control: Gesamtsteuerung ----- Control_switch_kamera_request = False ' Keine Umschaltung angefordert Control_switch_kamera_status = Switch_idle ' Keine Umschaltung angefordert, Zustand auf 0 '------------------------------------------------------------------------------ ' Und los gehts, hier noch die Restarbeiten '------------------------------------------------------------------------------ ' ----- Freigabe aller Interrupts ----- Enable Interrupts ' Damit auch Empfang von Daten über Buffer ' ----- Traceausgabe dass es nun los geht ----- Print "======================================================================" Print "======================= Ignition sequence start ======================" Print "======================================================================" Print ' ----- EEPROM ----- ' Initialisierung des internen EEPROM aufrufen und ggf. Traces schreiben Gosub Ee_init_internal_eeprom ' ----- Ethernetcontroller initialisieren ----- ' ggf. Traces ausgeben #if Enc28j60_testmodus Print "Beginne Ethernet zu initialisieren" #endif ' Erklärung aus dem Datenblatt: ' The System Reset Command (SRC) allows the host controller to issue a System Soft Reset command. ' Unlike other SPI commands, the SRC is only a single byte command and does not operate on any register. ' The command is started by pulling the CS pin low. The SRC opcode is the sent, followed by a 5-bit Soft Reset ' command constant of 1Fh. The SRC operation is terminated by raising the CS pin. ' Soft Reset für ENC28J60 durchführen Enc28j60_cs = 0 ' Chip auswählen Temp_byte_1 = Enc28j60_soft_reset ' Variable mit Reset Bitsequence laden Spiout Temp_byte_1 , 1 ' Resetsequenc an Chip übertragen Enc28j60_cs = 1 ' Chipselect zurücknehmen ' Erklärung aus dem Datenblatt: ' When the OST expires, the CLKRDY bit in the ESTAT register will be set. The application software should poll ' this bit as necessary to determine when normal device operation can begin. ' ' After a Power-on Reset, or the ENC28J60 is removed from Power-Down mode, the CLKRDY bit must be polled before ' transmitting packets, enabling packet reception or accessing any MAC, MII or PHY registers. ' Warteschleife bis Bit estat_clkrdy (bit 0) des ESTAT Register 1 ist Do Call Enc28j60_readcontrolregbyte(estat) ' ESTAT Register lesen Temp_byte_1 = Enc28j60_data.estat_clkrdy ' Bit für CLKRDY extrahieren Loop Until Temp_byte_1 = 1 ' ENC28J60 Errata !!! ' Module: Reset ' After sending an SPI Reset command, the PHY clock is stopped but the ESTAT.CLKRDY bit is not ' cleared. Therefore, polling the CLKRDY bit will not work to detect if the PHY is ready. ' Additionally, the hardware start-up time of 300 µs may expire before the device is ready to operate. ' ' Work around: ' After issuing the Reset command, wait at least 1 ms in firmware for the device to be ready. ' Hier wird dem Ethernetcontroller ausreichend StartUp-Zeit gegebe zum Einschwingen ' Bei Tests mit kleineren Werten als 200 ms gab es Probleme beim Senden! Waitms 250 ' .... nun kann es mit Volldampf weiter gehen! ' ggf. Traces ausgeben #if Enc28j60_testchiprevision ' MaFu: Entgegen der ursprünglichen Implementierung von Ben werden beim Auslesen der Revision Number ' nicht zwei Byte aus dem ENC28J60 ausgelesen sondern nur ein Byte. Gemäß Datenblatt beginnt der ' Controller sofort mit dem Senden des Datenbytes, beginnend mit MSB. ' Bei MAC, PHY oder MII Registern wird zuerst ein Dummybyte übertragen, erst dann erfolgt das ' eigentliche Datenbyte. ' Interessanter Weise funktioniert die Abfarge der Revision aber auch mit Ben's originalem Code. ' EREVID Chipversion auslesen Call Enc28j60_selectbank(3) ' Registerbank auswählen Ctrl_array(1) = &B000_10010 ' Read Control Register laden Enc28j60_cs = 0 ' Chip auswählen Spiout Ctrl_array(1) , 1 ' Daten an Chip übertragen Spiin Ctrl_array(1) , 1 ' Auf Chip Antwort warten Print "Enc28j60-version = " ; Ctrl_array(1) ; "{013}{010}" ' Version ausgeben Enc28j60_cs = 1 ' Chipselect zurücknehmen #endif ' Initialisierungsroutine aufrufen Call Enc28j60_init Waitms 200 ' Prüfen ob DHCP verwendet werden soll oder ob mit festen IP's gearbeitet wird If Enc28j60_dhcp_flag = Dhcp_ein Then ' JA, es soll DHCP verwendet werden Print "DHCP ist eingeschaltet{013}{010}" Call Send_dhcp_discover ' DHCP discover ausführen End If ' ----- Und hier kommt der Rest .... ----- ' Erste Helligkeitsmessung bei Systemstart durchführen Light_value = Light_measurement() ' Kamera 2 starten Call Control_pwr_cam2(ein) ' Spannungsversorgung von Kamera 2 einschalten Gosub Control_kamera2_aktiv ' Videomultiplexer auf Kamera 2 schalten Control_kamera_flag = 2 ' Kamera 2 aktiv ' IR Hintergrundbeleuchtung initialisieren aber Beleuchtung aus Gosub Ir_konfig ' PWM konfigurieren Gosub Ir_beleuchtung_aus ' Via Default IR-Hintergrundbeleuchtung aus ' prüfen welcher Betriebsmode und abhängig davon LED schalten, Zustände setzen oder Timer aufziehen Select Case Control_runningmode Case Mode_manuell : Mode_led = Led_aus ' LED-Anzeige für Betriebsart ausschalten Case Mode_licht : Mode_led = Led_ein ' LED-Anzeige für Betriebsart einschalten Gosub Control_check_licht ' Korrekte Kamera einstellen Case Mode_zeit : ' Bei Betriebsart ZEIT wird LED durch Sekunden-Tick getoggelt!!! ' Timer für nächste Kameraumschaltung setzen Control_timer_mode_counter = Scheduler_timer_counter + Control_videotimer End Select ' Wenn kein DHCP verwendet wir an dieser Stelle noch die Konfigurationsdaten ausgeben ' -> bei DHCP werden Betriebsdaten in DHCP-Antwortroutine von Controller gesendet If Enc28j60_dhcp_flag = Dhcp_aus Then ' NEIN, feste IP-Konfiguration wird verwendet ' Aktuelle IP-Konfiguration kann sofort ausgegegeben werden Print "DHCP ist ausgeschaltet{013}{010}" Gosub Enc28j60_print_konfig ' Restlichen Status auf RS232 senden Gosub Consol_print_konfig ' Anmerkung: ' Im Fall dass DHCP verwendet wird wird Bestätigung der Konfiguration in ' DHCP_ACK-Routine aufgerufen End If ' ############################################################################# ' ' Hauptprogramm ConvCtrl ' ' ############################################################################# ' ---------------------------------------------- ' ----- Hier ist die Programmhauptschleife ----- ' ---------------------------------------------- Do ' Tasten abfragen Debounce Key_1_pin , 0 , Control_key1 , Sub ' Hintergrundbeleuchtung Debounce Key_2_pin , 0 , Control_key2 , Sub ' Videokanal Debounce Key_3_pin , 0 , Control_key3 , Sub ' Betriebsmodus ' Ethernetverarbeitung in Polling-Betrieb Call Enc28j60_poll ' Console abfragen und ggf. Befehle verarbeiten Gosub Consol_poll ' Scheduler für zeitgesteuerte Aufgaben abfrage Gosub Scheduler_poll Loop ' Hauptschleife ' System halt End 'end program '## End Hauptprogramm ######################################################### '****************************************************************************** ' Interruptroutinen '****************************************************************************** '------------------------------------------------------------------------------ ' Interrupt-Service-Routine (Timer1): Sekunden_tick ' ' Routine zur Auswertung des Timer Interrupts ' ' Globale Variablen: ' Keine '------------------------------------------------------------------------------ Sekunden_tick: ' ----- Programmcode ----- Timer1 = Timervorgabe ' Timer neu laden ' Alive-LED toggeln lassen Toggle Alive_led ' globale Scheduler Vraible = Zeitbezug inkrementieren Incr Scheduler_timer_counter ' Prüfen ob Betriebsmodus = Zeitsteuerung ist If Control_runningmode = Mode_zeit Then ' JA Toggle Mode_led ' Mode-LED toggeln lassen End If ' Runningmode Zeit Return '-- End Sekunden_tick -------------------------------------------------------- '****************************************************************************** ' Subroutinen '****************************************************************************** ' ************ ' * ENC28J60 * ' ************ '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Enc28j60_selectbank ' ' Routine schaltet auf die entsprechende Registerbank um ' ' Parameter: bank = Registerbank die aktiviert werden soll ' Rückgabe: keine ' ' Globale Variablen: ' Ctrl_array = Control-Datenstruktur für das Senden und Empfangen von Daten '------------------------------------------------------------------------------ Sub Enc28j60_selectbank(bank As Byte) ' ----- lokale Variablen ----- #if Enc28j60_testmodus Local Ltemp_byte As Byte ' lokale BYTE-Arbeitsvariable #endif ' ----- Programmcode ----- ' ggf. Trace schreiben #if Enc28j60_testmodus Print "Enc28j60_selectbank entered" #endif ' Get ECON1 (BSEL1 en BSEL0) Ctrl_array(1) = &B000_11111 ' Read instruction und ECON1 Registerwert laden Enc28j60_cs = 0 ' Chip selektieren Spiout Ctrl_array(1) , 1 ' Datum (1 Byte) zum Ethernetcontroller senden Spiin Ctrl_array(1) , 1 ' Antwort des ENC28J60 einlesen (1 Byte) Enc28j60_cs = 1 ' Chipselekt wegnehmen ' ggf. aktuelle Bank ausgeben #if Enc28j60_testmodus Ltemp_byte = Ctrl_array(1) And &B0000_0011 ' Maske über BSEL0 und BSEL1 Print "Aktuelle Bank: " ; Ltemp_byte ' Ausgabe #endif ' A(1) beinhaltet ein nicht benötigtes Dummybyte, in A(2) befindet sich der Inhalt des Register ECON1 Ctrl_array(2) = Ctrl_array(1) And &B1111_1100 ' Maskieren der BSEL1 und BSEL0 Bits Ctrl_array(2) = Ctrl_array(2) Or Bank ' Bank auf die geschaltet werden soll verodern Ctrl_array(1) = &B010_11111 ' Write instruction und ECON1 Registerwert laden Enc28j60_cs = 0 ' Chip selektieren Spiout Ctrl_array(1) , 2 ' Datum (2 Bytes) zum Ethernetcontroller senden Enc28j60_cs = 1 ' Chipselect wegnehmen ' ggf. aktuelle Bank ausgeben #if Enc28j60_testmodus Print "Umgeschaltet auf Bank: " ; Ctrl_array(2) ' Ausgabe #endif ' MaFu: Die Control-Struktur könnte lokal umgesetzt werden. ' Ich vermute aber dass das Datenhandling lokaler Variablen etwas mehr ' Programmcode verbraucht welcher hier eh knapp ist, daher bleiben die ' Variablen zunächst global. End Sub '-- End Enc28j60_selectbank --------------------------------------------------- '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Enc28j60_readcontrolregbyte ' ' Routine dient zum Lesen von Controlregisterinhalten ' ' Parameter: register = Adresse des Registers was gelesen werden soll ' Rückgabe: keine ' ' Globale Variablen: ' Ctrl_array = Control-Datenstruktur für das Senden und Empfangen von Daten ' Enc28j60_data = Byte-Variable zur Übergabe von Registerinhalten '------------------------------------------------------------------------------ Sub Enc28j60_readcontrolregbyte(register As Byte) ' ----- Lokale Variable ----- Local Mcphy As Byte ' Flag für MAC/PHY Register Erkennung Local Bank As Byte ' Variable für Registerbank ' ----- Programmcode ----- ' ggf. Trace schreiben #if Enc28j60_testmodus Print "Enc28j60_readcontrolregbyte entered" #endif Bank = 0 ' Variable initialisieren Mcphy = 0 ' Variable initialisieren ' Korrekte Bank durch Bit 7 und 6 ermitteln If Register.7 = 1 Then Bank = 2 If Register.6 = 1 Then Bank = Bank + 1 If Register.5 = 1 Then Mcphy = 1 Register = Register And &B00011111 ' Registeradresse aus Bytewert extrahieren Call Enc28j60_selectbank(bank) ' Registerbank umschalten Ctrl_array(1) = Register ' Registerwert laden Enc28j60_cs = 0 ' Chip selektieren Spiout Ctrl_array(1) , 1 ' Datum (1 Byte) zum Ethernetcontroller senden Spiin Ctrl_array(1) , 3 ' Antwort des ENC28J60 einlesen (3 Bytes) Enc28j60_cs = 1 ' Chipselect wegnehmen ' In Abhängigkeit des zu lesenden Registers (E, MAC, MII) ist ein Dummybyte vorhanden oder nicht ' Auswertung ob Dummybyte vorhanden oder nicht If Mcphy = 1 Then Enc28j60_data = Ctrl_array(2) Else Enc28j60_data = Ctrl_array(1) ' Andere Implementierung als Ben's Tutorial, dort Ctrl_array(3) End If ' Ursprüngliche Implementierung war wohl auf Chipfehler zurückzuführen ' MaFu: Diese Subroutine kann auch als Funktion umgesetzt werden um den ' globale Variable Enc28j60_data zu vermeiden. ' Damit wäre das Handling des Rückgabewerts einfacher/übersichtlicher. ' Weiter könnte die Control-Struktur lokal umgesetzt werden. ' Ich vermute aber dass das Datenhandling lokaler Variablen etwas mehr ' Programmcode verbraucht welcher hier eh knapp ist, daher bleiben die ' Variablen zunächst global. End Sub '-- End Enc28j60_readcontrolregbyte ------------------------------------------ '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Enc28j60_writecontrolregbyte ' ' Routine dient zum Schreiben von Controlregisterinhalten ' ' Parameter: Register = Adresse des Registers was gelesen werden soll ' Value = Wert der in das Register geschrieben werden soll ' Rückgabe: keine ' ' Globale Variablen: ' Ctrl_array = Control-Datenstruktur für das Senden und Empfangen von Daten '------------------------------------------------------------------------------ Sub Enc28j60_writecontrolregbyte(register As Byte , Value As Byte) ' ----- Lokale Variable ----- Local Bank As Byte ' Variable für Registerbank Local Ltemp_byte As Byte ' lokale Arbeitsvariable ' ----- Programmcode ----- ' ggf. Trace schreiben #if Enc28j60_testmodus Print "Enc28j60_writecontrolregbyte entered" #endif Bank = 0 ' Variable initialisieren ' Korrekte Bank durch Bit 7 und 6 ermitteln If Register.7 = 1 Then Bank = 2 If Register.6 = 1 Then Bank = Bank + 1 Register = Register And &B00011111 ' Registeradresse aus Bytewert extrahieren Call Enc28j60_selectbank(bank) ' Registerbank umschalten Register.6 = 1 ' Write instruction 010_register laden Ctrl_array(1) = Register ' Registerwert laden Ctrl_array(2) = Value ' Registerinhalt laden Enc28j60_cs = 0 ' Chip selektieren Spiout Ctrl_array(1) , 2 ' Datum (2 Byte) zum Ethernetcontroller senden Enc28j60_cs = 1 ' Chipselect wegnehmen ' MaFu: Die Control-Struktur könnte lokal umgesetzt werden. ' Ich vermute aber dass das Datenhandling lokaler Variablen etwas mehr ' Programmcode verbursacht welcher hier eh knapp ist, daher bleiben die ' Variablen zunächst global. End Sub '-- End Enc28j60_writecontrolregbyte ----------------------------------------- '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Enc28j60_bitfield_set ' ' Routine dient zum Setzen von Bits in dem übergebenen Ethernet Control ' Register ' ' Parameter: register = Control Register welche manipuliert werden soll ' value = 8 Bit Variable zum Ausführen eines bitweisen OR (SET) ' Rückgabe: keine ' ' Globale Variablen: ' Ctrl_array = Control-Datenstruktur für das Senden und Empfangen von Daten ' ' Bemerkung: Routine kann nicht für MAC Register, MII Register, PHY Register ' und Buffer Memory verwendet werden. '------------------------------------------------------------------------------ Sub Enc28j60_bitfield_set(register As Byte , Value As Byte) ' ----- Lokale Variable ----- Local Bank As Byte ' Variable für Registerbank ' Local Com_array(2) As Byte ' Not possible, daher wird auf globale Datenstruktur zurückgegriffen ' ----- Programmcode ----- ' ggf. Trace schreiben #if Enc28j60_testmodus Print "Enc28j60_bitfield_set entered" #endif Bank = 0 ' Variable initialisieren ' Korrekte Bank durch Bit 7 und 6 ermitteln If Register.7 = 1 Then Bank = 2 If Register.6 = 1 Then Bank = Bank + 1 Register = Register And &B00011111 ' Registeradresse aus Bytewert extrahieren Call Enc28j60_selectbank(bank) ' Registerbank umschalten Register = Register Or &B100_00000 ' Bit field set instruction laden Ctrl_array(1) = Register ' Registeradresse laden Ctrl_array(2) = Value ' Bitfeld laden Enc28j60_cs = 0 ' Chip selektieren Spiout Ctrl_array(1) , 2 ' Datum (2 Byte) zum Ethernetcontroller senden Enc28j60_cs = 1 ' Chipselect wegnehmen End Sub '-- End Enc28j60_bitfield_set -------------------------------------------------- '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Enc28j60_bitfield_clear ' ' Routine dient zum Löschen von Bits in dem übergebenen Ethernet Control ' Register ' ' Parameter: register = Control Register welche manipuliert werden soll ' value = 8 Bit Variable zum Ausführen eines bitweisen ' NOT AND (CLEAR) ' Rückgabe: keine ' ' Globale Variablen: ' Ctrl_array = Control-Datenstruktur für das Senden und Empfangen von Daten ' ' Bemerkung: Routine kann nicht für MAC Register, MII Register, PHY Register ' und Buffer Memory verwendet werden. '------------------------------------------------------------------------------ Sub Enc28j60_bitfield_clear(register As Byte , Value As Byte) ' ----- Lokale Variable ----- Local Bank As Byte ' Variable für Registerbank ' ----- Programmcode ----- ' ggf. Trace schreiben #if Enc28j60_testmodus Print "Enc28j60_bitfield_clear entered" #endif Bank = 0 ' Variable initialisieren ' Korrekte Bank durch Bit 7 und 6 ermitteln If Register.7 = 1 Then Bank = 2 If Register.6 = 1 Then Bank = Bank + 1 Register = Register And &B00011111 ' Registeradresse aus Bytewert extrahieren Call Enc28j60_selectbank(bank) ' Registerbank umschalten Register = Register Or &B101_00000 ' Bit field clear instruction laden Ctrl_array(1) = Register ' Registeradresse laden Ctrl_array(2) = Value ' Bitfeld laden Enc28j60_cs = 0 ' Chip selektieren Spiout Ctrl_array(1) , 2 ' Datum (2 Byte) zum Ethernetcontroller senden Enc28j60_cs = 1 ' Chipselect wegnehmen End Sub '-- End Enc28j60_bitfield_clear ------------------------------------------------ '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Enc28j60_writephyword ' ' Routine dient zum Schreiben eines 16-Bit Werts in das PHY register. Bevor ' dies jedoch passiert wird der alte PHY-Register zunächst gelesen. ' ' Parameter: phyregister = Adresse des PHY rgisters ' Wdara = 16 Bit Wert der geschrieben werden soll ' Rückgabe: kein ' ' Globale Variablen: ' Enc28j60_data = Byte-Variable zur Übergabe von Registerinhalten '------------------------------------------------------------------------------ Sub Enc28j60_writephyword(phyregister As Byte , Phy_word As Word) ' Kommentar aus dem Datenblatt: ' When a PHY register is written to, the entire 16 bits is ' written at once; selective bit writes are not implemented. ' If it is necessary to reprogram only select bits ' in the register, the controller must first read the PHY ' register, modify the resulting data and then write the ' data back to the PHY register. ' ----- Lokale Variable ----- Local Value As Byte ' Lokale Byte Arbeitsvariable Local Ltemp_word As Word ' Lokale Word Arbeitsvariable ' ----- Programmcode ----- ' ggf. Trace schreiben #if Enc28j60_testmodus Print "Enc28j60_writephyword entered" #endif ' Inhalt PHY Register in MIREGADR-Register schreiben ' To write to a PHY register: Call Enc28j60_writecontrolregbyte(miregadr , Phyregister) ' Write the address of the PHY register to write to into the MIREGADR register Call Enc28j60_readcontrolregbyte(miregadr) Value = Low(phy_word) Call Enc28j60_writecontrolregbyte(miwrl , Value) ' Write the lower 8 bits of data to write into the MIWRL register. Value = High(phy_word) Call Enc28j60_writecontrolregbyte(miwrh , Value) ' Write the upper 8 bits of data to write into the MIWRH register. Do ' Writing to this register automatically Call Enc28j60_readcontrolregbyte(mistat) ' begins the MIIM transaction, so it must Loop Until Enc28j60_data.mistat_busy = 0 ' be written to after MIWRL. The MISTAT.BUSY ' bit becomes set. End Sub '-- End Enc28j60_writephyword -------------------------------------------------- '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Enc28j60_init ' ' Routine dient zum Initialisieren des Ethernetcontrollers ' - Einstellen der buffermemory-registers ' - Einstellen der MAC-address ' - Aufruf weiterer Subroutinen BITFIELD_SET, BITFIELD_CLEAR ' - Zugriffe auf das PHY-registers. ' ' Parameter: keine ' Rückgabe: keine ' ' Globale Variablen: ' Nextpacketptr = Zeiger auf das nächsten Datenpaket '------------------------------------------------------------------------------ Sub Enc28j60_init ' ----- Lokale Variable definieren ----- Local Value As Byte ' Lokale Byte Arbeitsvariable Local Ltemp_word As Word ' lokale Word Arbeitsvariable ' ----- Programmcode ----- ' ggf. Trace schreiben #if Enc28j60_testmodus Print "Enc28j60_init entered" #endif ' ----- Bank 0 ----- ' Initialisierung des Empfangsbuffers ' Der 16-bit Wert muss mit Lowbyte zuerst geschrieben werden ' Set Receive Buffer Start Address Nextpacketptr = Rxstart_init ' globalen Paket-Pointer auf Startwert setzen Value = Low(rxstart_init) ' Low-Byte laden Call Enc28j60_writecontrolregbyte(erxstl , Value) ' Adresswert in ERXSTL Register schreiben Value = High(rxstart_init) ' High-Byte laden Call Enc28j60_writecontrolregbyte(erxsth , Value) ' Adresswert in ERXSTH Register schreiben ' ===== START ERRATA ===== ' ENC28J60 Errata !!! ' Module: Memory (Ethernet Buffer) ' The receive hardware may corrupt the circular receive buffer (including the Next Packet Pointer ' and receive status vector fields) when an even value is programmed into the ERXRDPTH:ERXRDPTL ' registers. ' Work around ' Ensure that only odd addresses are written to the ERXRDPT registers. Assuming that ERXND contains ' An Odd Value , Many Applications Can Derive A Suitable Value To Write To Erxrdpt By Subtracting ' One From The Next Packet Pointer(a Value Alwaysensured To Be Even Because Of Hardware Padding) ' and then compensating for a potential ERXST to ERXND wrap-around. Assuming that the receive ' Buffer Area Does Not Span The 1fffh To 0000h Memory Boundary , The Logic In Example 2 Will Ensure That ' Erxrdpt Is Programmed With An Odd Value: ' if (Next Packet Pointer = ERXST) ' then: ' ERXRDPT = ERXND ' else: ' ERXRDPT = Next Packet Pointer – 1 ' set receive pointer address (-1 due to errata) If Nextpacketptr = 0 Then ' Nextpacketptr beinhaltet noch Rxstart_init welche geprüft werden soll Ltemp_word = Rxstop_init Else Ltemp_word = Rxstart_init Ltemp_word = Ltemp_word - 1 End If Value = Low(ltemp_word) ' Low-Byte laden Call Enc28j60_writecontrolregbyte(erxrdptl , Value) ' Adresswert in ERXRDPTL Register schreiben Value = High(ltemp_word) ' High-Byte laden Call Enc28j60_writecontrolregbyte(erxrdpth , Value) ' Adresswert in ERXRDPHT Register schreiben ' ===== END ERRATA ===== ' Set Receive Buffer End Value = Low(rxstop_init) ' Low-Byte laden Call Enc28j60_writecontrolregbyte(erxndl , Value) ' Adresswert in ERXNDL Register schreiben Value = High(rxstop_init) ' High-Byte laden Call Enc28j60_writecontrolregbyte(erxndh , Value) ' Adresswert in ERXNDH Register schreiben ' Set Transmit Buffer Start Value = Low(txstart_init) ' Low-Byte laden Call Enc28j60_writecontrolregbyte(etxstl , Value) ' Adresswert in ETXSTL Register schreiben Value = High(txstart_init) ' High-Byte laden Call Enc28j60_writecontrolregbyte(etxsth , Value) ' Adresswert in ETXSTH Register schreiben ' ----- Bank 2 ----- ' Enable MAC receive Value = 0 Value.macon1_marxen = 1 ' Enable MAC um frames zu empfangen Value.macon1_txpaus = 1 ' Allow the MAC to transmit pause control frames Value.macon1_rxpaus = 1 ' Inhibit transmissions when pause control frames are received Call Enc28j60_writecontrolregbyte(macon1 , Value) ' Adresswert in MACON1 Register schreiben ' Enable automatic padding and CRC operations Value = 0 Value.macon3_padcfg0 = 1 ' Automatic Pad and CRC Configuration bits Value.macon3_txcrcen = 1 ' Transmit CRC Enable bit Value.macon3_frmlnen = 1 ' Frame Length Checking Enable bit Value.macon3_fuldpx = 1 ' MaFu V1.1: MAC will operate in Full-Duplex mode. PDPXMD bit must also be set Call Enc28j60_writecontrolregbyte(macon3 , Value) ' Adresswert in MACON3 Register schreiben ' MaFu V1.1: Ergänzt um die Initialisierung des MAC Control Registers 4 Value = 0 Value.macon4_defer = 1 ' When the medium is occupied, the MAC will wait indefinitely for it to become free ' when attempting to transmit (use this setting for IEEE 802.3. compliance) Call Enc28j60_writecontrolregbyte(macon4 , Value) ' Adresswert in MACON4 Register schreiben ' Set maximum packet size which the controller will accept Value = Low(max_framelen) ' Low-Byte laden Call Enc28j60_writecontrolregbyte(mamxfll , Value) ' Wert in MAMXFLL Register schreiben Value = High(max_framelen) ' High-Byte laden Call Enc28j60_writecontrolregbyte(mamxflh , Value) ' Wert in MAMXFLH Register schreiben ' Set inter-frame gap (back-to-back) ' Configure the Back-to-Back Inter-Packet Gap register, MABBIPG. Most applications will program this register with 15h when Full-Duplexmode is used and 12h when Half-Duplex mode is used. Call Enc28j60_writecontrolregbyte(mabbipg , &H12) ' desired period in nibble times minus 6 ' When FULDPX (MACON3<0>) = 1: ' Nibble time offset delay between the end of one transmission and the beginning of the next in a ' back-to-back sequence. The register value should be programmed to the desired period in nibble times ' minus 3. The recommended setting is 15h which represents the minimum IEEE specified Inter-Packet ' Gap (IPG) of 9.6 µs. Call Enc28j60_writecontrolregbyte(mabbipg , &H15) ' MaFu V1.1: desired period in nibble times minus 6 ' Set inter-frame gap (non-back-to-back) ' Configure the Non-Back-to-Back Inter-Packet Gap register low byte, MAIPGL. Most applications will program this register with 12h. Call Enc28j60_writecontrolregbyte(maipgl , &H12) ' MAIPGL init gemäß Datenblatt ' If half duplex is used, the Non-Back-to-Back Inter-Packet Gap register high byte, MAIPGH, should be programmed. Most applications will program this register to 0Ch. Call Enc28j60_writecontrolregbyte(maipgh , &H0C) ' MAIPGH init gemäß Datenblatt ' ----- Bandk 3 ----- ' Set ECOCON Register for disabling for disabling clock output Call Enc28j60_writecontrolregbyte(ecocon , &B00000_000) ' Taktausgang wird nicht verwendet ' Set MAC-Adresse in MAADR Register-Set Call Enc28j60_writecontrolregbyte(maadr5 , Enc28j60_my_mac_adress(1)) ' Ethernet Adresse Byte 0 in Register MAADR5 schreiben Call Enc28j60_writecontrolregbyte(maadr4 , Enc28j60_my_mac_adress(2)) ' Ethernet Adresse Byte 1 in Register MAADR4 schreiben Call Enc28j60_writecontrolregbyte(maadr3 , Enc28j60_my_mac_adress(3)) ' Ethernet Adresse Byte 2 in Register MAADR3 schreiben Call Enc28j60_writecontrolregbyte(maadr2 , Enc28j60_my_mac_adress(4)) ' Ethernet Adresse Byte 3 in Register MAADR2 schreiben Call Enc28j60_writecontrolregbyte(maadr1 , Enc28j60_my_mac_adress(5)) ' Ethernet Adresse Byte 4 in Register MAADR1 schreiben Call Enc28j60_writecontrolregbyte(maadr0 , Enc28j60_my_mac_adress(6)) ' Ethernet Adresse Byte 5 in Register MAADR0 schreiben ' MaFu V1.1: PHY operates in Full-Duplex mode Call Enc28j60_writephyword(phcon1 , Phcon1_pdpxmd) ' PHY CONTROL REGISTER 1 schreiben ' No loopback of transmitted frames Call Enc28j60_writephyword(phcon2 , Phcon2_hdldis) ' PHY CONTROL REGISTER 2 schreiben ' Write LED Control Register with correct values ' !! Zur projektspezifischen Anpassung wird nicht definition aus Inlude-File verwendet !! ' bit 15-14 Reserved: Write as '0' ' bit 13-12 Reserved: Write as '1' ' bit 11-8 LACFG3:LACFG0: LEDA Configuration bits ' bit 7-4 LBCFG3:LBCFG0: LEDB Configuration bits ' bit 3-2 LFRQ1:LFRQ0: LED Pulse Stretch Time Configuration bits (see Table 2-1) ' bit 1 STRCH: LED Pulse Stretching Enable bit ' bit 0 Reserved: Write as '0' #if Compiler_flag = 1 ' Zielumgebung Call Enc28j60_writephyword(phlcon , &B00_11_0100_0111_00_1_0) 'PHLCON LED Control Register ' | | | | | | | ' | | | | | | +-- Reserved -> Write as 0 ' | | | | | +----- Stretchable LED events will cause lengthened LED pulses based on LFRQ1:LFRQ0 configuration ' | | | | +-------- Stretch LED events by TNSTRCH ' | | | +------------- Display link status ' | | +------------------ Display transmit and receive activity (stretchable) ' | +--------------------- Reserved -> Write as 1 ' +------------------------ Reserved -> Write as 0 #else ' EVA-Board Call Enc28j60_writephyword(phlcon , &B00_11_0111_0100_00_1_0) 'PHLCON LED Control Register ' | | | | | | | ' | | | | | | +-- Reserved -> Write as 0 ' | | | | | +----- Stretchable LED events will cause lengthened LED pulses based on LFRQ1:LFRQ0 configuration ' | | | | +-------- Stretch LED events by TNSTRCH ' | | | +------------- Display link status ' | | +------------------ Display transmit and receive activity (stretchable) ' | +--------------------- Reserved -> Write as 1 ' +------------------------ Reserved -> Write as 0 #endif ' Switch to bank 0 Call Enc28j60_selectbank(0) ' ----- Enable Interrupts ----- Value = 0 Value.eie_intie = 1 ' Global INT Interrupt Enable bit Value.eie_pktie = 1 ' Receive Packet Pending Interrupt Enable bit Call Enc28j60_bitfield_set(eie , Value) ' ETHERNET INTERRUPT ENABLE REGISTER schreiben ' ----- Setting Receive Filters ----- ' Filters according to Guido aus Ben's Tutorial Call Enc28j60_writecontrolregbyte(epmm0 , &H3F) Call Enc28j60_writecontrolregbyte(epmm1 , &H30) Call Enc28j60_writecontrolregbyte(epmcsl , &HF9) Call Enc28j60_writecontrolregbyte(epmcsh , &HF7) Value = 0 ' Variable initialisieren Value.erxfcon_pmen = 1 ' Pattern Match enable (ARP only) Value.erxfcon_ucen = 1 ' Unicast enable Call Enc28j60_bitfield_set(erxfcon , Value) ' ERXFCON Register schreiben Value = 0 ' Wichtig !!! Broadcast enable für DHCP!!! Value.erxfcon_bcen = 0 ' Broadcast enable for DHCP Call Enc28j60_bitfield_clear(erxfcon , Value) ' ERXFCON Register schreiben 'CRC check is enabled by default 'Something is wrong with the Broadcast filter (or the whole theory), it seems 'like every packet is coming in 'enable packet reception Value = 0 Value.econ1_rxen = 1 ' Receive Enable bit Call Enc28j60_bitfield_set(econ1 , Value) ' Wert in ECON1 Register schreiben 'Reset transmit logic Value = 0 Value.econ1_txrst = 1 Call Enc28j60_bitfield_set(econ1 , Value) Call Enc28j60_bitfield_clear(econ1 , Value) End Sub '-- End Enc28j60_init ---------------------------------------------------------- '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Enc28j60_poll ' ' Routine prüft ob Daten via Ethernet empfangen wurden. ' Wenn Ja wird Subroutine zum Empfang der Datenpakete aufgrufen ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variable ' Keine '------------------------------------------------------------------------------ Sub Enc28j60_poll ' ----- Programmcode ----- ' Ethernet Packet Count auslesen Call Enc28j60_readcontrolregbyte(epktcnt) ' Prüfen ob Daten empfangen wurden If Enc28j60_data > 0 Then ' JA ' ggf. Trace schreiben #if Enc28j60_testmodus Print "Empfangsdaten vorhanden" #endif ' Angekommenes Datenpaket verarbeiten Call Enc28j60_packetreceive End If ' Daten vorhanden End Sub '-- End Enc28j60_poll ---------------------------------------------------------- '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Enc28j60_packetreceive ' ' Routine dient zum Epmpfang von Daten via Ethernet ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' nextpacketptr = Zeiger auf Datenpakete innerhalb des Ethernetcontrollers ' Com_array = Kommunikationsdatenstruktur zum Senden und Empfangen von ' Ethernetpaketen ' Length = Globale Paketlängeninformation '------------------------------------------------------------------------------ Sub Enc28j60_packetreceive ' ----- Lokale Variable ----- Local Value As Byte Local Lbuffer_index As Word Local Ltemp_word As Word Local Wtemp As Word ' ----- Programmcode ----- ' Prozessing-LED einschalten Proc_led = Led_ein ' Ethernet Packet Count wurde ausglesen (in Sub Enc28j60_poll) und steht in globaler Variable enc28j60_data ' Ggf. Trace ausgeben #if Enc28j60_testreceive Print "EPKTCNT = " ; Bin(enc28j60_data) Print "Sub Enc28j60_packetreceive" #endif ' set the read pointer to the start of the received packet Value = Low(nextpacketptr) ' Low-Byte des globalen Paket Pointer erzeugen Call Enc28j60_writecontrolregbyte(erdptl , Value) ' Buffer Read Pointer Low-Byte and Ethernetcontroller senden Value = High(nextpacketptr) ' High-Byte des globalen Paket Pointer erzeugen Call Enc28j60_writecontrolregbyte(erdpth , Value) ' Buffer Read Pointer High-Byte and Ethernetcontroller senden ' Ggf Trace ausgeben #if Enc28j60_testreceive Print "Present nextpacketpntr " ; Hex(nextpacketptr) ' Position Read Pointer High-Byte ausgeben #endif Enc28j60_cs = 0 ' Chip selektieren ' Starte das Auslesen des Buffer Memory Spdr = &B001_11010 'Send Read Buffer Memory command &H3A ' Bemerkung: ' Aufgrund Autoinc enabled werden so lange Daten vom Ethernet-Controller geliefert, ' bis der Chipselect zurückgenommen wird. Dazu muss der ATmega32 aber einen SPI-Clock erzeugen. ' Warteschleife bis Senden erfolgreich Do Loop Until Spsr.spif = 1 ' Lese SPI Status Register und prüfe SPI Interrupt Flag ' Auslesen der ersten 6 Bytes (3 Word: Nextpacketptr, Packetlength, Rxstat) For Lbuffer_index = 1 To 6 ' Schleife zum Auslesen von 6 Datenbytes ' Starte durch Senden eines Dummy-Bytes die SPI erneut, um ein Byte aus dem Ethernet-Controller ' zum Atmega zu übertragen Spdr = &HFF ' Dummy byte senden damit SCK erzeugt wird (SPI read) ' Warteschleife bis Empfangen erfolgreich Do ' Wiederhole die Schleife so lange bis durch das SPI Interrupt Flag der ' erfolgreiche Empfang eines Datenbytes angezeigt wird. Loop Until Spsr.spif = 1 ' Lese SPI Status Register und prüfe SPI Interrupt Flag (SPI ready) ' Auslesen des empfangenen Daten-Bytes in globale Datenstruktur Com_array(lbuffer_index) = Spdr Next Lbuffer_index ' Schleife zum Auslesen von 6 Datenbytes ' Extrahieren der Arbeitsdaten Nextpacketptr, Packetlength, Rxstat aus ersten 6 empfangenen Bytes Nextpacketptr = Com_array(2) * 256 ' High-Byte in Word-Variable verarbeiten (Multiplikation mit 256 = Shift 8 Bit nach links) Nextpacketptr = Nextpacketptr + Com_array(1) ' Low-Byte hinzuaddieren, fertig ist Nextpacketptr Length = Com_array(4) * 256 ' High-Byte in Word-Variable verarbeiten (Multiplikation mit 256 = Shift 8 Bit nach links) Length = Length + Com_array(3) ' Low-Byte hinzuaddieren, fertig ist Paket Length Rxstat = Com_array(6) * 256 ' High-Byte in Word-Variable verarbeiten (Multiplikation mit 256 = Shift 8 Bit nach links) Rxstat = Rxstat + Com_array(5) ' Low-Byte hinzuaddieren, fertig ist Receive Status #if Enc28j60_testreceive ' Ggf. Ausgabe der gelesenen Daten Print "New Nextpacketpntr = " ; Hex(nextpacketptr) Print "Packetlength = " ; Hex(length) Print "Rxstat = " ; Bin(rxstat) #endif ' Auslesen der Nutzdaten (Payload) über zuvor ermittelte Paketelänge Length = Length - 4 ' Ignoriere die 4 Bytes der Checksumme For Lbuffer_index = 1 To Length ' Schleife zum Auslesen der Nutzdaten ' Starte durch Senden eines Dummy-Bytes die SPI erneut, um ein Byte aus dem Ethernet-Controller ' zum Atmega zu übertragen Spdr = &HFF ' Dummy byte senden damit SCK erzeugt wird (SPI read) ' Warteschleife bis Empfangen erfolgreich Do ' Wiederhole die Schleife so lange bis durch das SPI Interrupt Flag der ' erfolgreiche Empfang eines Datenbytes angezeigt wird. Loop Until Spsr.spif = 1 ' Lese SPI Status Register und prüfe SPI Interrupt Flag (SPI ready) ' Auslesen des empfangenen Daten-Bytes in globale Datenstruktur Com_array(lbuffer_index) = Spdr Next Lbuffer_index ' Schleife zum Auslesen der Nutzdaten Enc28j60_cs = 1 ' Chipselect wegnehmen 'move the rx read pointer to the start of the next received packet 'this frees the memory we just read out ' ===== ENC28J60 Errata !!! ===== ' Module: Memory (Ethernet Buffer) ' The receive hardware may corrupt the circular receive buffer (including the Next Packet Pointer ' and receive status vector fields) when an even value is programmed into the ERXRDPTH:ERXRDPTL ' registers. ' Work around ' Ensure that only odd addresses are written to the ERXRDPT registers. Assuming that ERXND contains ' An Odd Value , Many Applications Can Derive A Suitable Value To Write To Erxrdpt By Subtracting ' One From The Next Packet Pointer(a Value Alwaysensured To Be Even Because Of Hardware Padding) ' and then compensating for a potential ERXST to ERXND wrap-around. Assuming that the receive ' Buffer Area Does Not Span The 1fffh To 0000h Memory Boundary , The Logic In Example 2 Will Ensure That ' Erxrdpt Is Programmed With An Odd Value: ' if (Next Packet Pointer = ERXST) ' then: ' ERXRDPT = ERXND ' else: ' ERXRDPT = Next Packet Pointer – 1 ' set receive pointer address (-1 due to errata) If Nextpacketptr = 0 Then Ltemp_word = Rxstop_init Else Ltemp_word = Nextpacketptr - 1 End If Value = Low(ltemp_word) ' Low-Byte laden Call Enc28j60_writecontrolregbyte(erxrdptl , Value) ' Adresswert in ERXRDPTL Register schreiben Value = High(ltemp_word) ' High-Byte laden Call Enc28j60_writecontrolregbyte(erxrdpth , Value) ' Adresswert in ERXRDPHT Register schreiben ' ===== Ende of ENC28J60 Errata !!! ===== ' decrement the packet counter indicate we are done with this packet Value = 0 ' Variable initialisieren ' Bit 6 Pktdec : Packet Decrement Bit ' 1 = Decrement the EPKTCNT register by one ' 0 = Leave EPKTCNT unchanged Value.econ2_pktdec = 1 Call Enc28j60_bitfield_set(econ2 , Value) ' ECON2 register schreiben ' Verarbeitung der Pakete in Abhängigkeit ihrer Semantik ' Werte im Typfeld (EtherType) für einige wichtige Protokolle: ' Typfeld | Protokoll ' ========+=================================================== ' 0x0800 | IP Internet Protocol, Version 4 (IPv4) ' 0x0806 | Address Resolution Protocol (ARP) ' 0x0842 | Wake on LAN (WoL) ' 0x8035 | Reverse Address Resolution Protocol (RARP) ' 0x809B | AppleTalk (EtherTalk) ' 0x80F3 | Appletalk Address Resolution Protocol (AARP) ' 0x8100 | VLAN Tag (VLAN) ' 0x8137 | Novell IPX (alt) ' 0x8138 | Novell ' 0x86DD | IP Internet Protocol, Version 6 (IPv6) ' 0x8863 | PPPoE Discovery ' 0x8864 | PPPoE Session ' 0x8870 | Jumbo Frames ' 0x8892 | Echtzeit-Ethernet PROFINET ' 0x88A2 | ATA over Ethernet Coraid AoE [2] ' 0x88A4 | Echtzeit-Ethernet EtherCAT ' 0x88A8 | Provider Bridging ' 0x88AB | Echtzeit-Ethernet Ethernet POWERLINK ' 0x88CD | Echtzeit-Ethernet SERCOS III ' 0x8906 | Fibre Channel over Ethernet ' 0x8914 | FCoE Initialization Protocol (FIP) ' Der IPv4-Header ist normalerweise 20 Bytes lang. Bei Übertragung auf Basis von Ethernet ' folgt er dem Ethernet-Typfeld, das für IP-Pakete auf 0800 festgelegt ist. Auf anderen ' Übertragungsmedien und Protokollen kann der Header auch der erste Eintrag sein. ' ' IPv4 bietet verschiedene, größtenteils ungenutzte Optionen, die den Header bis auf 60 ' Bytes (in 4-Byte-Schritten) verlängern können. ' ' +---------+---------+---------+---------+---------+---------+---------+---------+ ' | 0-3 | 4-7 | 8-11 | 12-15 | 16-18 | 19-23 | 24-27 | 28-31 | ' +---------+---------+---------+---------+---------+---------+---------+---------+ ' | Version | IHL | Type of Service | Gesamtlänge | ' +---------+---------+-------------------+---------+-----------------------------+ ' | Identifikation | Flags | Fragment Offset | ' +-------------------+-------------------+---------+-----------------------------+ ' | TTL | Protokoll | Header-Prüfsumme | ' +-------------------+-------------------+---------------------------------------+ ' | Quell-IP-Adresse | ' +-------------------------------------------------------------------------------+ ' | Ziel-IP-Adresse | ' +-------------------------------------------------------------------------------+ ' | evtl. Optionen ... | ' +-------------------------------------------------------------------------------+ ' ' Eine spezielle Bedeutung kommt in modernen Implementierungen dem Feld Type of Service zu. ' Ursprünglich diente dieses Feld bei der Vermittlung eines Datenpaketes als ' Entscheidungshilfe für die beteiligten Router bei der Wahl der Übertragungsparameter. In ' modernen Implementierungen wird dieses Feld im Zusammenhang mit der Vermeidung von ' Überlastungen verwendet. ' ===== Type: ARP 0x0806 ===== If Com_array(13) = &H08 Then ' Type Byte 0: Address Resolution Protocol (ARP) 0x0806 If Com_array(14) = &H06 Then ' Type Byte 1: Address Resolution Protocol (ARP) 0x0806 If Com_array(21) = &H00 Then ' ARP request Byte 0 If Com_array(22) = &H01 Then ' ARP request Byte 1 If Com_array(39) = Enc28j60_my_ip_adress(1) Then ' Eigene IP Byte 1 If Com_array(40) = Enc28j60_my_ip_adress(2) Then ' Eigene IP Byte 2 If Com_array(41) = Enc28j60_my_ip_adress(3) Then ' Eigene IP Byte 3 If Com_array(42) = Enc28j60_my_ip_adress(4) Then ' Eigene IP Byte 4 ' Routine zur Verarbeitng des ARP Request aufrufen Call Arpreply End If End If End If End If End If End If End If ' ARP ' ===== Type: IP 0x0800 ===== ' Byte Com_array(13) = &H08 bereits oben angefragt If Com_array(14) = &H00 Then ' Type: IP Internet Protocol, Version 4 (IPv4) 0x0800 If Com_array(15) = &H45 Then ' We handle only simple IP packets (Version 4 und IHL 5*32 Bit lang) 'If Com_array(21) = 0 Then ' We handle only non fragmented packets ' ---- Behandlung von Botschaften welche für die eigene IP gedacht sind ----- If Com_array(31) = Enc28j60_my_ip_adress(1) Then ' Ip packet for us If Com_array(32) = Enc28j60_my_ip_adress(2) Then If Com_array(33) = Enc28j60_my_ip_adress(3) Then If Com_array(34) = Enc28j60_my_ip_adress(4) Then ' ----- Protokol:ICMP (Internet Control Message Protocol) If Com_array(24) = 1 Then ' Protokollnummer für ICMP ' PING Echo Request If Com_array(35) = &H08 Then 'ICMP-Pakettype Echo Request (wird für PING verwendet) Call Pingreply End If ' PING End If ' ICMP ' ---- Protokoll: TCP (Transmission Control Protocol) If Com_array(24) = 6 Then ' Protokollnummer für TCP Call Tcp_receive ' Korrekte TCP Verarbeitung End If ' TCP ' ----- Protokoll: UDP (User Datagram Protocol) If Com_array(24) = 17 Then ' Protokollnummer für UDP Call Udp_receive ' Korrekte UDP Verarbeitung End If End If End If End If End If ' Eigene IP ' ----- Botschaften welche für die Broadcast IP 255.255.255.255 gedacht sind ----- ' Wird z.B. für die Behandlung und Verarbeitung von DHCP verwendet If Com_array(31) = 255 Then 'Ip broadcast If Com_array(32) = 255 Then If Com_array(33) = 255 Then If Com_array(34) = 255 Then ' ----- Protokoll: UDP (User Datagram Protocol) If Com_array(24) = 17 Then 'Protocol:UDP ' Prüfung ob UDP Routine ausgeführt werden soll ' JA Call Udp_receive ' Korrekte UDP Verarbeitung End If ' UDP End If End If End If End If ' Broadcast 'End If End If End If ' Type: IP End If ' ARP & IP Byte 1 ' Prozessing-LED ausschalten Proc_led = Led_aus End Sub '-- End Enc28j60_packetreceive ------------------------------------------------ '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Enc28j60_packetsend ' ' Routine dient zum Senden von Daten ' ' Parameter: pcktlen = Länge des zu Sendenden Datenpakets in Bytes ' Rückgabe: keine ' ' Globale Variablen: ' Com_array = Kommunikationsdatenstruktur zum Senden und Empfangen von ' Ethernetpaketen ' '------------------------------------------------------------------------------ Sub Enc28j60_packetsend(pcktlen As Word) ' ----- Lokale Variable ----- Local Value As Byte ' Lokale Byte Arbeitsvariable Local Ltemp_word As Word ' Lokale Word Arbeitsvariable ' ----- Programmcode ----- ' ggf. Trace schreiben #if Enc28j60_testmodus Print "Enc28j60_packetsend entered" #endif 'set the write pointer to start of transmit buffer area Value = Low(txstart_init) Call Enc28j60_writecontrolregbyte(ewrptl , Value) ' Schreibe den Write Pointer Low Byte Value = High(txstart_init) Call Enc28j60_writecontrolregbyte(ewrpth , Value) ' Schreibe den Write Pointer High Byte ' Zu sendendes Paket zum Ethernetcontroler übertragen Enc28j60_cs = 0 ' Chip selektieren ' Starte das Schreiben in den Buffer Memory Spdr = Enc28j60_write_buf_mem ' Steuercommando write buffer memory &H7A = &B011_11010 ' Warteschleife bis Senden erfolgreich Do ' Wiederhole die Schleife so lange bis durch das SPI Interrupt Flag das ' erfolgreiche Senden des Buffer Memmory Request angezeigt wird. Loop Until Spsr.spif = 1 ' Lese SPI Status Register und prüfe SPI Interrupt Flag ' Schreiben des PER Packet Bytes Spdr = &B000_1110 'per packet byte ' Warteschleife bis Senden erfolgreich Do ' Wiederhole die Schleife so lange bis durch das SPI Interrupt Flag das ' erfolgreiche Senden des Buffer Memmory Request angezeigt wird. Loop Until Spsr.spif = 1 ' Lese SPI Status Register und prüfe SPI Interrupt Flag ' Schreibe die Anzahl der Datenpakete welche als Parameter übergeben wurden For Ltemp_word = 1 To Pcktlen ' Schleife über alle Datenbytes ' Datenbyte aus Datenstruktur an Ethernetcontroller senden Spdr = Com_array(ltemp_word) ' Warteschleife bis Senden erfolgreich Do ' Wiederhole die Schleife so lange bis durch das SPI Interrupt Flag das ' erfolgreiche Senden des Buffer Memmory Request angezeigt wird. Loop Until Spsr.spif = 1 ' Lese SPI Status Register und prüfe SPI Interrupt Flag Next Ltemp_word ' Schleife über alle Datenbytes Enc28j60_cs = 1 ' Chipselect wegnehmen ' Prüfen ob minimale Paketlänge erreicht, wenn nicht auf minimale Länge setzen If Pcktlen < 60 Then Pcktlen = 60 ' 60 + 4Byte CRC = 64 Bytes minimale Ether-Paketlänge 'set the TXND pointer to correspond to the packet size given Value = Low(txstart_init) Value = Value + Low(pcktlen) Call Enc28j60_writecontrolregbyte(etxndl , Value) ' TX End Low Byte Value = High(txstart_init) Value = Value + High(pcktlen) Call Enc28j60_writecontrolregbyte(etxndh , Value) ' TX End High Byte 'write per-packet control byte has been put in the writeroutine!!! 'send the contents of the transmit buffer onto the network Value = 0 ' Variable initialisieren ' Transmit Only Reset setzen Value.econ1_txrts = 1 ' The Transmit Only Reset is performed by writing a .1. to the TXRST bit Call Enc28j60_bitfield_set(econ1 , Value) ' ECON1 Register schreiben ' .... und raus damit .... ' MaFu V1.1: Handling für ECON1.TXRTS ' Anmerkung: ' Bei Tests wurde ein sporadischer Hängenbleiber der Senderoutine bzw. der Sendebearbeitung des Chips festgestellt. Der Fehler ' zeigt sich, dass die Botschaft welche zum ENC28J60 übertragen wurde nur unvollständig gesendet wird und der Chip dann im ' Status Senden hängen bleibt, was am ECON1.TXRTS Bit zu erkennen ist welches normalerweise nach einem erfolgreichen Senden auf ' NULL zurückgesetzt wird. ' Die Ursache des Fehlers konnte bis jetzt nicht ermittelt werden. Die Arbeitshypothese ist, das es zu einer Kollision zwischen ' Daten die gesendet- und Daten die empfangen werden sollen kommt. Der ENC28J60 wurde auf Voll-Duplex-Betrieb umkonfiguriert. Bis ' jetzt verliefen die Tests positiv was die Arbeitshypothese etwas bestätigt. ' Sollte der Fehler erneut auftreten wäre eine Überwachung der Sendung mit Timeout und anschließendem Reset des Controllers ' eine weitere mögliche Maßnahme um den Hänger zu lösen. ' Sicherlich nur eine Hammermethode aber mir fällt aktuell nix besseres ein. '( ##MaFu## ' Warteschleife bis Bit estat_clkrdy (bit 0) des ESTAT Register 1 ist Do Call Enc28j60_readcontrolregbyte(econ1) ' ECON1 Register lesen Temp_byte_1 = Enc28j60_data.econ1_txrts ' Bit für TXRTS extrahieren ' Ggf. Trace ausgeben #if Enc28j60_testmodus Print "*"; #endif ' Hier hat der Hänger stattgefunden --> Bit TXRTS ging nie auf 0 ' ==> es konnten keine neuen Daten mehr gesendet werden. Loop Until Temp_byte_1 = 0 ') ' Ggf. Trace ausgeben #if Enc28j60_testmodus Print "fertig" #endif End Sub '-- End Enc28j60_packetsend ---------------------------------------------------- '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Echopacket ' ' Routine sendet die empfangenen Datenpakete als 1:1 Echo wieder zurück ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' T_udp_len0 + T_udp_len1 = TCP-Längeninformation für Paketgröße ' '------------------------------------------------------------------------------ Sub Echopacket ' ----- lokale Variablen ----- Local L_buffer_index As Word ' Bufferindex Local Ltemp_word As Word ' WORD-Hilfsvariable ' ----- Programmcode ----- ' Prüfen ob UDP Traces geschrieben werden sollen #if Enc28j60_testmodus Print "Echopacket" #endif ' UDP-Paketenlänge der UDP-Daten ermitteln, dazu HighByte und LowByte verrechnen ' und Gesamtanzahl berechnen Ltemp_word = T_udp_len0 * 256 ' Highbyte verarbeiten Ltemp_word = Ltemp_word + T_udp_len1 ' Lowbyte verarbeiten ' 34 Bytes für Ethernet-Frame-Header (14 Bytes) und IP-Frame-Header (20 Byte) hinzuaddieren Ltemp_word = Ltemp_word + 34 ' Daten senden. Die Bufferfelder wurden zuvor manipuliert. Der Datenbereich wird wegen Echo ' 1:1 übernommen. Call Enc28j60_packetsend(ltemp_word) End Sub '-- End Echopacket ------------------------------------------------------------ ' **************************** ' * Ethernet Hilfsfunktionen * ' **************************** '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Setipaddrs ' ' Routine verarbeitet bei UDP-Protokollen die IP-Adressen. Die Routine ' - kopiert die Source IP auf die Destination IP um ' - setzt die eigene IP als Source IP und ' - erzeugt die IP-Header Checksumme ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen_ ' T_ip_destaddr = IP DestinatioN Adress (Overlays des Ethernetbuffers) ' T_ip_srcaddr = IP Sourceadress (Overlays des Ethernetbuffers) ' Enc28j60_my_ip = Datenstruktur für eigene IP-Adresse ' ' Anmerkung: Neue optimierte Version ' '------------------------------------------------------------------------------ Sub Setipaddrs ' ----- Programmcode ----- T_ip_destaddr = T_ip_srcaddr ' Kopiere Source IP in Destination (IP-Frame) T_ip_srcaddr = Enc28j60_my_ip ' Make ethernet module IP address source address ' Kopiere die ethernet packet source address auf die ethernet packet destination address und belege ' die ethernet packet source adresse mit der eigenen MAC-Adresse Call Src2dest ' Checksumme für IP-Header berechnen Call Ip_header_checksum End Sub '-- End Setipaddrs ------------------------------------------------------------ '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Src2dest ' ' Diese Routine kopiert die ethernet packet source address auf die ethernet ' packet destination address und belegt die ethernet packet source adresse mit ' der eigenen MAC-Adresse ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' T_enetpacketdest0 bis T_enetpacketdest5 (Overlays des Ethernetbuffers) ' T_enetpacketsrc0 bis T_enetpacketsrc5 (Overlays des Ethernetbuffers) ' ' Anmerkung: Funktion verändert Ethernetbuffers! ' '------------------------------------------------------------------------------ Sub Src2dest ' ----- Programmcode ----- ' Move hardware source address to destination address T_enetpacketdest0 = T_enetpacketsrc0 T_enetpacketdest1 = T_enetpacketsrc1 T_enetpacketdest2 = T_enetpacketsrc2 T_enetpacketdest3 = T_enetpacketsrc3 T_enetpacketdest4 = T_enetpacketsrc4 T_enetpacketdest5 = T_enetpacketsrc5 ' Kopiere eigene MAC-Adresse in ethernet packet source adresse Call Src2mymac End Sub '-- End Src2dest -------------------------------------------------------------- '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Src2mymac ' ' Diese Routine kopiert die eigene MAC-Adresse in die ethernet packed source ' adresse des IP Pakets. ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: Mymac (enthält die eigene MAC Adresse) ' T_enetpacketsrc0 bis T_enetpacketsrc5 (Overlays des Ethernetbuffers) ' ' Anmerkung: Funktion verändert Ethernetbuffers! ' '------------------------------------------------------------------------------ Sub Src2mymac ' ----- Programmcode ----- ' Make ethernet module mac address the source address T_enetpacketsrc0 = Enc28j60_my_mac_adress(1) T_enetpacketsrc1 = Enc28j60_my_mac_adress(2) T_enetpacketsrc2 = Enc28j60_my_mac_adress(3) T_enetpacketsrc3 = Enc28j60_my_mac_adress(4) T_enetpacketsrc4 = Enc28j60_my_mac_adress(5) T_enetpacketsrc5 = Enc28j60_my_mac_adress(6) End Sub '-- End Src2mymac ------------------------------------------------------------- '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Ip_header_checksum ' ' Routine dient zum erzeugen der IP-Header-Checksumme im IP-Frame-Anteil ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' T_ip_hdr_cksum, ' T_ip_hdr_cksum1, ' T_ip_hdr_cksum0 = IP-Header Checksumme (Overlays des Ethernetbuffers) ' T_ip_vers_len = IP-Header Längenbyte (Overlays des Ethernetbuffers) ' ' Bemerkung: Die Routine erzeugt die Checksumme direkt auf der Datenstruktur ' Die Berechnung der Checksumme erfolgt mittels Funktion ' "Tcpchecksum" aus der tcpip.lbx von MCS '------------------------------------------------------------------------------ Sub Ip_header_checksum ' ----- lokale Variablen ----- Local Ip_checksum16 As Word Local Ip_header_length As Byte ' ----- Programmcode ----- ' calculate the IP header checksum ' Zur Berechnung der IP-Header-Checksumme wird zunächst Checksumme auf NULL gesetzt T_ip_hdr_cksum = &H0000 'Calc starts with chksum=0 'Calculate IP header length Ip_header_length = T_ip_vers_len And &H0F ' IHL (IP Header Length) aus 1. Byte extrahieren Ip_header_length = 4 * Ip_header_length ' Die gesamte Länge des IP-Kopfdatenbereiches ist in Vielfachen von 32 Bit angegeben ' Checksumme erzeugen ' Parameter: ' Res: A word variable that is assigned with the TCP/IP checksum of the buffer ' Buffer: A variable or array to get the checksum of. ' Bytes : The number of bytes that must be examined. ' w1,w2 : Optional words that will be included in the checksum. Ip_checksum16 = Tcpchecksum(com_array(15) , Ip_header_length ) ' Ergebnis in Sende- und Empfangsbuffer zurückschreiben T_ip_hdr_cksum1 = High(ip_checksum16) ' Highbyte T_ip_hdr_cksum0 = Low(ip_checksum16) ' Lowbyte End Sub '-- End Ip_header_checksum ---------------------------------------------------- '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Icmp_checksum ' ' Routine berechnet die IPCM Checksumme ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: T_icmp_cksum (Overlay auf ethernet buffer) ' T_icmp_cksum0 und T_icmp_cksum1 (Overlay auf ethernet buffer) ' I_header_length ' i_checksum16 ' ' Anmerkung: ' Funktion arbeitet direkt mittels Overlay auf ethernet buffer '------------------------------------------------------------------------------ Sub Icmp_checksum ' ----- lokale Variablen ----- Local I_header_length As Word ' Hilfsvariable (WORD) für Checksummenberechnunge Local I_checksum16 As Word ' Hilfsvariable (WORD) für Checksummenberechnunge ' ----- Programmcode ----- ' Clear the ICMP checksum before starting calculation T_icmp_cksum = &H00 ' Calculate the ICMP checksum ' Die Größe des IP Headers beträgt 20 Bytes. Damit beträgt die Länge des ICMP-Pakets ' IP-Länge - 20 I_header_length = T_ip_pktlen1 - 20 ' Parameter: ' Res: A word variable that is assigned with the TCP/IP checksum of the buffer ' Buffer: A variable or array to get the checksum of. ' Bytes : The number of bytes that must be examined. ' w1,w2 : Optional words that will be included in the checksum. ' ' Bei com_array(35) beginnt die payload eines IP pakets I_checksum16 = Tcpchecksum(com_array(35) , I_header_length ) 'built-in way ' Checksumme in ethernet buffer schreiben T_icmp_cksum1 = High(i_checksum16) ' Highbyte extahieren T_icmp_cksum0 = Low(i_checksum16) ' Lowbyte extrahieren End Sub '-- End Icmp_checksum --------------------------------------------------------- '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Srcdestchksum ' ' Diese Routine berechnet einen Teil der TCP Prüfsumme, bestehend aus einem ' Teil des TCP Pseudoheaders ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' Funktion arbeitet mittels einigen Overlaystrukturen direkt auf dem Com_array ' Buffer zum Senden und Empfangen von Daten ' ' Anmerkung: Funktion verändert Ethernetbuffers! ' '------------------------------------------------------------------------------ Sub Srcdestchksum ' ----- Programmcode ----- I_chksum32 = 0 ' Variablen initialisieren ' Werte der Source IP Adresse zusammenzählen I_value16h = T_ip_srcaddr0 I_value16l = T_ip_srcaddr1 I_chksum32 = I_chksum32 + I_value16 I_value16h = T_ip_srcaddr2 I_value16l = T_ip_srcaddr3 I_chksum32 = I_chksum32 + I_value16 ' Werte der Destination IP Adresse zusammenzählen I_value16h = T_ip_destaddr0 I_value16l = T_ip_destaddr1 I_chksum32 = I_chksum32 + I_value16 I_value16h = T_ip_destaddr2 I_value16l = T_ip_destaddr3 I_chksum32 = I_chksum32 + I_value16 ' Wert des Protokollbytes zusammenzählen I_chksum32 = I_chksum32 + T_ip_proto End Sub '-- End Srcdestchksum --------------------------------------------------------- '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Udp_checksum ' ' Routine erzeugt die UDP-Checksumme über den UDP-Pseudo-Header ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variable: ' ' ' Bemerkung: Die Routine erzeugt die Checksumme direkt auf der Datenstruktur ' Die Berechnung der Checksumme erfolgt mittels Funktion ' "Tcpchecksum" aus der tcpip.lbx von MCS '------------------------------------------------------------------------------ Sub Udp_checksum ' ----- lokale Variablen ----- Local Ltemp_word_1 As Word ' Lokale WORD-Variable Local Ltemp_word_2 As Word ' Lokale WORD-Variable ' ----- Programmcode ----- ' Setzte das Prüffeld auf NULL ' CRC Bytes zu berechnen T_udp_chksum = &H00 ' Berechne einen Teil der TCP Prüfsumme, bestehend aus einem Teil des TCP Pseudoheaders Call Srcdestchksum ' resultat in I_chksum32 ' Addiere die UDP Packet length auf die 32-Bit Prüfsumme I_value16h = T_udp_len0 I_value16l = T_udp_len1 I_chksum32 = I_chksum32 + I_value16 ' Erzeuge die Länge des UDP-Pakets Result16h = T_udp_len0 Result16l = T_udp_len1 Ltemp_word_2 = Highw(i_chksum32) ' Extrahiere aus 32-Bit Variable HighWord Ltemp_word_1 = I_chksum32 ' Erzeugung des LowWord erfolgt durch Casting auf Word ' Parameter: ' Res: A word variable that is assigned with the TCP/IP checksum of the buffer ' Buffer: A variable or array to get the checksum of. ' Bytes : The number of bytes that must be examined. ' w1,w2 : Optional words that will be included in the checksum. I_checksum16 = Tcpchecksum(com_array(&H23) , Result16 , Ltemp_word_1 , Ltemp_word_2) ' Return a TCP/IP checksum, also called Internet Checksum, or IP Checksum. ' Auszug aus der BASCOM-Hilfe ' This checksum is calculated by grouping the bytes in the array into 2-byte words. ' If the number of Bytes is an odd number, then an extra byte of zero is used to make ' the last 2-byte word. All of the words are added together, keeping the total in a ' 4-byte Long variable. If the optional words w1, w2, are included, they are also added ' to the total. Next, the 4-byte Long total is split into two, 2-byte words, and these ' words are added together to make a new 2-byte Word total. Finally the total is inverted. ' This is the value returned as Res. ' ' This function using w1, w2, are very useful when working directly with Ethernet chips ' like the RTL8019AS or with protocols not directly supported by the WIZnet chips. ' Highbyte und Lowbyte der 16-Bit Checksumme nun noch in die Datenstruktur eintragen T_udp_chksum1 = High(i_checksum16) T_udp_chksum0 = Low(i_checksum16) End Sub '-- End Udp_checksum ---------------------------------------------------------- '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Tcp_checksum ' ' Routine erzeugt die TCP-Checksumme über den TCP-Header ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' Tcp_cksum = Globale Arbeitsvariable für TCP-Checksumme ' Tcp_cksuml, Tcp_cksumh = Overlayvariablen für Tcp_cksum ' Tempword = Globale temporäre Arbeitsvariable ' Tempwordh, Tempwordl = Overlayvariablen für Tempword ' T_ip_pktlen0, T_ip_pktlen1 = Overlay auf IP-Längeninformation in Buffer ' I_checksum16 = Globale Arbeitsvariable für 16-Bit Checksumme ' I_chksum32 = Globale Arbeitsvariable für 32-Bit Checksumme ' Com_array = Globaler Sende- und Empfangsbuffer ' ' Bemerkung: Die Routine erzeugt die Checksumme direkt auf der Datenstruktur ' Die Berechnung der Checksumme erfolgt mittels Funktion ' "Tcpchecksum" aus der tcpip.lbx von MCS ' '------------------------------------------------------------------------------ Sub Tcp_checksum ' ----- lokale Adressen ----- Local Whulp1 As Word Local Tempword2 As Word Local Val1 As Word Local Val2 As Word ' ----- Programmcode ----- ' Variable mit NULL initialisieren Tcp_cksum = 0 ' Berechne einen Teil der TCP Prüfsumme, bestehend aus einem Teil des TCP Pseudoheaders Call Srcdestchksum ' Addiere die IP Packet length auf die 32-Bit Prüfsumme Tempwordh = T_ip_pktlen0 Tempwordl = T_ip_pktlen1 I_chksum32 = I_chksum32 + Tempword ' Länge IP-Header berechnen und wieder abziehen Tempword2 = T_ip_vers_len And &H0F ' IP Header Length ermitteln Tempword2 = Tempword2 * 4 ' mit 4 Multiplizieren ?!?!? ' OK IP Header ist vielfaches von 32 Bit = 4 Byte I_chksum32 = I_chksum32 - Tempword2 ' IP-Header-Länge abziehen ' Länge des zu berechnenden TCP-Paket ergibt sich aus IP-Länge - Header (20 Bytes) Whulp1 = Tempword - 20 Val2 = Highw(i_chksum32) ' Extrahiere aus 32-Bit Variable HighWord Val1 = I_chksum32 ' Erzeugung des LowWord erfolgt durch Casting auf Word ' Parameter: ' Res: A word variable that is assigned with the TCP/IP checksum of the buffer ' Buffer: A variable or array to get the checksum of. ' Bytes : The number of bytes that must be examined. ' w1,w2 : Optional words that will be included in the checksum. I_checksum16 = Tcpchecksum(com_array(&H23) , Whulp1 , Val2 , Val1) ' Auszug aus der BASCOM-Hilfe ' This checksum is calculated by grouping the bytes in the array into 2-byte words. ' If the number of Bytes is an odd number, then an extra byte of zero is used to make ' the last 2-byte word. All of the words are added together, keeping the total in a ' 4-byte Long variable. If the optional words w1, w2, are included, they are also added ' to the total. Next, the 4-byte Long total is split into two, 2-byte words, and these ' words are added together to make a new 2-byte Word total. Finally the total is inverted. ' This is the value returned as Res. ' ' This function using w1, w2, are very useful when working directly with Ethernet chips ' like the RTL8019AS or with protocols not directly supported by the WIZnet chips. ' Highbyte und Lowbyte der 16-Bit Checksumme nun noch in die Datenstruktur eintragen Tcp_cksuml = High(i_checksum16) Tcp_cksumh = Low(i_checksum16) End Sub '-- End Tcp_checksum ---------------------------------------------------------- '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Clearbuff ' ' Diese Routine löscht den kompletten Send- und Empfangsbuffer im RAM ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' Com_array = Kommunikationsdatenstruktur zum Senden und Empfangen von ' Ethernetpaketen ' Max_framelen = Konstante für Größe des Buffer-Speichers im RAM ' '------------------------------------------------------------------------------ Sub Clearbuff ' ----- lokale Variablen ----- Local L_bufferindex As Word ' lokale Word-Variable für den Zugriff auf den Sendebuffer ' ----- Programmcode ----- For L_bufferindex = 1 To Max_framelen Com_array(l_bufferindex) = 0 Next L_bufferindex End Sub '-- End Clearbuff ------------------------------------------------------------- '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Swapdestport2srcport ' ' Diese Routine vertauscht TCP Sourceport und TCP Destinationport miteinander. ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' Tcp_srcporth, Tcp_srcportl, Tcp_destporth, Tcp_destportl sind Overlays der ' eigentlichen Com_array Datenstruktur. ' '------------------------------------------------------------------------------ Sub Swapdestport2srcport ' ----- Programmcode ----- Swap Tcp_srcporth , Tcp_destporth Swap Tcp_srcportl , Tcp_destportl End Sub '-- End Swapdestport2srcport -------------------------------------------------- ' ******************************** ' * Ethernet Protokollfunktionen * ' ******************************** '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Arpreply ' ' Routine dient zur Bearbeitung einer ARP-Anfrage und senden die notwendigen ' Antwortdaten zurück and den anfragenden Teilnehmer ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' Die Fuktion arbeitet hauptsächlich mit Overlays of der Com_array-Struktur ' ' Anmerkungen: ' Die Funktion arbeitet mittels Overlay direkt auf dem ethernet buffer '------------------------------------------------------------------------------ Sub Arpreply ' Bemerkung: ' Zu dieser Zeit befindet sich noch das originale ARP Request Packet in ' der Datenbufferstruktur Com_array. Es wird dan dieser Stelle direkt wieder ' benutzt und nur geringfügig für die ARP-Response abgeändert! ' Der Aufbau des ARP-Paket für Response und Request ist gleich. Daher können ' die Daten weitgehend übernommen werden. ' ----- lokale Variablen ----- Local Ltemp_byte As Byte ' ----- Programmcode ----- ' kopiert die ethernet packet source address auf die ethernet packet destination address ' und belegt die ethernet packet source adresse mit der eigenen MAC-Adresse ' Swap MAC addresses Call Src2dest ' Copy target MAC in ARP packet T_arp_dest_enetpacket0 = T_enetpacketdest0 T_arp_dest_enetpacket1 = T_enetpacketdest1 T_arp_dest_enetpacket2 = T_enetpacketdest2 T_arp_dest_enetpacket3 = T_enetpacketdest3 T_arp_dest_enetpacket4 = T_enetpacketdest4 T_arp_dest_enetpacket5 = T_enetpacketdest5 ' Set target IP in ARP packet T_arp_tipaddr0 = T_arp_sipaddr0 T_arp_tipaddr1 = T_arp_sipaddr1 T_arp_tipaddr2 = T_arp_sipaddr2 T_arp_tipaddr3 = T_arp_sipaddr3 ' Copy source MAC to ARP T_arp_src_enetpacket0 = T_enetpacketsrc0 T_arp_src_enetpacket1 = T_enetpacketsrc1 T_arp_src_enetpacket2 = T_enetpacketsrc2 T_arp_src_enetpacket3 = T_enetpacketsrc3 T_arp_src_enetpacket4 = T_enetpacketsrc4 T_arp_src_enetpacket5 = T_enetpacketsrc5 ' Set source IP to ARP packet pos 29 T_arp_sipaddr0 = Enc28j60_my_ip_adress(1) T_arp_sipaddr1 = Enc28j60_my_ip_adress(2) T_arp_sipaddr2 = Enc28j60_my_ip_adress(3) T_arp_sipaddr3 = Enc28j60_my_ip_adress(4) ' ARP type von Request auf Reply umschalten (Position 22) ' (1 für ARP-Anforderung, 2 für ARP-Antwort) T_arp_op1 = 2 ' ARP Reply Packet senden, Anzahl der Bytes = 42 (Ethernet-Frame + Payload) Call Enc28j60_packetsend(42) End Sub '-- End Arpreply -------------------------------------------------------------- '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Pingreply ' ' Routine dient zur Bearbeitung einer PING-Anfrage und senden die notwendigen ' Antwortdaten zurück and den anfragenden Teilnehmer ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' Com_array = Kommunikationsdatenstruktur zum Senden und Empfangen von ' Ethernetpaketen ' ' Anmerkung: ' Diese Version dieser Funktion entspricht der einer "aufgeräumten" Version aus ' Ben's Tutorial nach Einführung einiger Hilfsfunktionen. ' Die Funktion arbeitet mittels Overlay direkt auf dem ethernet buffer '------------------------------------------------------------------------------ Sub Pingreply ' Bemerkung: ' Zu dieser Zeit befindet sich noch das originale PING Request Packet in ' der Datenbufferstruktur Com_array. Es wird dan dieser Stelle direkt wieder ' benutzt und nur geringfügig für die ARP-Response abgeändert! ' Der Aufbau des ARP-Paket für Response und Request ist gleich. Daher können ' die Daten weitgehend übernommen werden. ' ----- lokale Variablen ----- Local Lpacketlength As Word ' ----- Programmcode ----- ' Die Länge wird dabei aus der IP packet length Information berechnet Lpacketlength = Com_array(17) * 256 Lpacketlength = Lpacketlength + Com_array(18) ' We are going to calculate the checksum till the end of packet (IP length + 14 byte of the ethernet stuff), -1 to get word start Lpacketlength = Lpacketlength + 13 ' set echo reply T_icmp_type = &H00 T_icmp_code = &H00 ' setup the IP-header Call Setipaddrs ' IPCM Checksumme berechnen Call Icmp_checksum Lpacketlength = Lpacketlength + 1 ' Send the reply packet ' Setting packetlength to the correct value (Korrektur von vorheriger Anpassung wegen Checksummenberechnung) Call Enc28j60_packetsend(lpacketlength) End Sub '-- End Pingreply ------------------------------------------------------------- '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Send_dhcp_discover ' ' Diese Routine sendet ein DHCP Discover an den Router ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' Com_array = Kommunikationsdatenstruktur zum Senden und Empfangen von ' Ethernetpaketen ' '------------------------------------------------------------------------------ Sub Send_dhcp_discover ' ----- lokale Variablen ----- Local L_buffer_index As Word ' ----- Programmcode ----- Call Clearbuff ' Buffer komplett löschen ' ===== MAC Header in Buffer schreiben ===== ' Broadcast-Adresse (ist immer FF:FF:FF:FF:FF:FF) Com_array(1) = &HFF Com_array(2) = &HFF Com_array(3) = &HFF Com_array(4) = &HFF Com_array(5) = &HFF Com_array(6) = &HFF Call Src2mymac 'MAC source address ' Ethernet Type = &h0800 = IP Com_array(13) = &H08 Com_array(14) = &H00 ' ===== IP-Header in Buffer schreiben ===== Com_array(15) = &H45 ' Header length Com_array(16) = &H00 ' Type of service Com_array(17) = &H01 ' Packet length high Com_array(18) = &H16 ' Packet length low Com_array(19) = &H05 ' Identification Com_array(20) = &H0D Com_array(21) = &H00 ' Flags Com_array(22) = &H00 ' Flags + Fragment Offset Com_array(23) = &H80 ' TTL = Time To Live Com_array(24) = &H11 ' Protocol UDP = 17 ' (25) IP checksum ' (26) IP checksum ' Source IP-Addresse T_ip_srcaddr = &H00000000 ' => 000.000.000.000 (Verwendung von Overlay) ' Destination Addresse T_ip_destaddr = &HFFFFFFFF ' => 255.255.255.255 (Verwendung von Overlay) ' ===== UDP- Header in Buffer schreiben ===== ' Source Port Com_array(35) = &H00 ' UDP Source Port 68 = Client Port DHCP = 0x0044 Com_array(36) = &H44 ' Destinatin Port Com_array(37) = &H00 ' UDP Destination Port 67 = Server Port DHCP = 0x0043 Com_array(38) = &H43 ' UDP-Paketlänge Com_array(39) = &H01 ' Length = 0x0102 = 258 Com_array(40) = &H02 ' (41) UDP checksum ' (42) UDP checksum ' ===== UDP-Payload in Buffer schreiben = DHCP ===== ' Konstanten für das DHCP-Handling ' Const Dhcp_pack_request = &H01 ' OP Byte: 1=request, 2=reply ' Const Dhcp_htype10mb = &H01 ' HW Type: 1 = 10 MBit Ethernet ' Const Dhcp_htype100mb = &H02 ' 2 = Experimental Ethernet ' Const Dhcp_hlenethernet = &H06 ' Länge der physikalischen Netzadresse in Bytes (z. B. 6 = MAC/Ethernet-Adresse) ' Const Dhcp_hops = &H00 ' Anzahl der DHCP-Relay-Agents auf dem Datenpfad ' Const Dhcp_secs = &H00 ' Zeit in Sekunden seit dem Start des Clients ' Const Dhcp_flags = &H80 ' Z. Zt. wird nur das erste Bit verwendet (zeigt an, ob der Client noch eine gültige ' IP-Adresse hat), die restlichen Bits sind für spätere Protokollerweiterungen reserviert Com_array(43) = Dhcp_pack_request ' Request = 1 Com_array(44) = Dhcp_htype10mb ' Ethernet = 1 Com_array(45) = Dhcp_hlenethernet ' MAC-Address length = 6 Com_array(46) = Dhcp_hops ' Optional daher auf 0 ' Eindeutige ID der Verbindung zwischen Client und Server Com_array(47) = Xid(1) ' 0x1F Com_array(48) = Xid(2) ' 0x45 Com_array(49) = Xid(3) ' 0x3A Com_array(50) = Xid(4) ' 0xDE ' (51) + (52) secs nicht belegt Com_array(53) = Dhcp_flags ' Broadcastflag ist gesetzt Com_array(54) = &H00 ' Bleibt 00 ' Bytes (54) .. (70) Client-IP, eigene IP, Server-IP und Relay-Agent-IP werden nicht gesetzt (16 Bytes überspringen) ' Client-MAX-Adresse (eigene MAC-Adresse eintragen Com_array(71) = Enc28j60_my_mac_adress(1) Com_array(72) = Enc28j60_my_mac_adress(2) Com_array(73) = Enc28j60_my_mac_adress(3) Com_array(74) = Enc28j60_my_mac_adress(4) Com_array(75) = Enc28j60_my_mac_adress(5) Com_array(76) = Enc28j60_my_mac_adress(6) ' (77) .. (86) bleiben leer da MAC-Adresse nur 6 Stellen, Feld aber 16 Byte groß ' 64 Bytes für den Namen des DHCP-Servers werden übersprungen und bleiben 0xFF (86) .. (150) ' 128 Bytes für Dateiname wird übersprungen und bleibt 0xFF (151) .. (278) ' ===== Optionales DHCP-Feld schreiben ===== ' Vendor Information "Magic Cookie" ' ' As suggested in [RFC-951], the first four bytes of this field have ' been assigned to the magic cookie, which identifies the mode in ' which the succeeding data is to be interpreted. The value of the ' magic cookie is the 4 octet dotted decimal 99.130.83.99 (or ' hexadecimal number 63.82.53.63) in network byte order. ' DHCP cookie Com_array(279) = 99 ' 0x63 Com_array(280) = 130 ' 0x82 Com_array(281) = 83 ' 0x53 Com_array(282) = 99 ' 0x63 ' Request for Subnetmask, Router and DNS Com_array(283) = Dhcpparamrequest ' Dhcpparamrequest = 55 = 0x37 Com_array(284) = 3 ' Fordere 3 Optionen vom Router an Com_array(285) = Subnet_mask ' 1. Subnetmask = 1 Com_array(286) = Router ' 2. Router = 3 Com_array(287) = Dns ' 3. Dns = 6 Com_array(288) = Dhcpmessagetype ' Dhcpmessagetype = 53 = 0x35 Com_array(289) = 1 ' Längeninformation für Option 53 Com_array(290) = Dhcp_opt53_discover ' Dhcp_discover = &H01 Com_array(291) = Endoption ' End options = 0xFF Call Ip_header_checksum ' IP-Checksumme berechnen Call Udp_checksum ' UDP-Checksumme berechnen Call Echopacket ' ... und raus damit ' ggf. Trace ausgeben #if Enc28j60_dhcp_output Print "Schritt 1 ---> DHCP discover" #endif End Sub '-- End Send_dhcp_discover ---------------------------------------------------- '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Dhcp_receive ' ' Diese Routine dient zum Auswerten von Daten welche im Rahmen einer DHCP ' Sequence vom Router an den Client gesendet wurden. ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' Com_array = Kommunikationsdatenstruktur zum Senden und Empfangen von ' Ethernetpaketen ' '------------------------------------------------------------------------------ Sub Dhcp_receive ' ----- Programmcode ----- #if Enc28j60_dhcp_output Print "Funktion DHCP Receive aufgerufen" #endif ' OP auswerten If Com_array(43) = &H02 Then ' boot reply = Antwort ' Transaction ID auswerten If Com_array(47) = Xid(1) Then ' Byte 1 = 0x1F If Com_array(48) = Xid(2) Then ' Byte 2 = 0x45 If Com_array(49) = Xid(3) Then ' Byte 3 = 0x3A If Com_array(50) = Xid(4) Then ' Byte 4 = 0xDE If Com_array(283) = &H35 Then ' Options (53) DHCP Message Type If Com_array(284) = &H01 Then ' DHCP Offer If Com_array(285) = &H02 Then ' ggf. Trace ausgeben #if Enc28j60_dhcp_output Print "Schritt 2 <--- DHCP offer" #endif ' Nachdem der offer erfolgt ist kann nun der Request erfolgen Call Send_dhcp_request ' DHCP ACK Elseif Com_array(285) = &H05 Then ' Acknowledge erhalten und verarbeiten. Nun steht IP-Adresse fest Call Dhcp_ack End If End If End If End If End If End If End If End If End Sub '-- End Dhcp_receive ---------------------------------------------------------- '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Send_dhcp_request ' ' Diese Routine sendet ein DHCP Request an den Router, nachdem der Router mit ' einem DHCP Offer geantwortet hat. ' Die Funktion setzt voraus, dass die empfangenen Daten des DHCP offer vom ' Router noch unverändert im Buffer stehen! ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' Com_array = Kommunikationsdatenstruktur zum Senden und Empfangen von ' Ethernetpaketen ' '------------------------------------------------------------------------------ Sub Send_dhcp_request ' ----- lokale Variablen ----- Local Lbuffer_index As Word ' ----- Programmcode ----- ' ===== MAC Header in Buffer bearbeiten ===== Call Src2mymac 'MAC source address Com_array(17) = &H01 ' Packet length high Com_array(18) = &H2B ' Packet length low ' ===== IP-Header in Buffer bearbeiten ===== ' Source IP-Addresse T_ip_srcaddr = &H00000000 ' => 000.000.000.000 (Verwendung von Overlay) ' ===== UDP- Header in Buffer bearbeiten ===== Call Swapdestport2srcport ' Swap Souce und Destination Port 67<-->68 Com_array(39) = &H01 ' Length = 0x0117 = 279 Com_array(40) = &H17 ' ===== UDP-Payload in Buffer bearbeiten = DHCP ===== Com_array(43) = Dhcp_pack_request ' Request = 1 Com_array(44) = Dhcp_htype10mb ' Ethernet = 1 ' ===== Optionales DHCP-Feld bearbeiten ===== Com_array(283) = Dhcpmessagetype ' Options 53 = 0x35 = DHCP Message Type Com_array(284) = 1 ' Längeninformation für Option 53 = 1 Com_array(285) = Dhcp_opt53_dhcprequest ' Dhcp_request = &H03 Com_array(286) = Dhcprequestipaddress ' Option 50 = 0x32 = DHCP Requested IP Adress Com_array(287) = 04 ' Längeninformation für Option 50 = 4 ' Adresse welche vom Router geofferd wurde übernehmen Com_array(288) = Com_array(59) ' IP-Adresse Byte 1 Com_array(289) = Com_array(60) ' IP-Adresse Byte 2 Com_array(290) = Com_array(61) ' IP-Adresse Byte 3 Com_array(291) = Com_array(62) ' IP-Adresse Byte 4 Com_array(292) = Dhcphostname ' Option 12 = 0x0C = DHCP Host Name Option Com_array(293) = &H05 ' Längeninformation für Option 12 (variabel) Com_array(294) = "n" Com_array(295) = "e" Com_array(296) = "t" Com_array(297) = "i" Com_array(298) = "o" Com_array(299) = Endoption ' End options = 0xFF ' Alles nicht mehr benötigte wird auf 0 gesetzt For Lbuffer_index = Tcp_data To 70 Com_array(lbuffer_index) = 0 Next Lbuffer_index For Lbuffer_index = 300 To Max_framelen Com_array(lbuffer_index) = 0 Next Lbuffer_index Call Ip_header_checksum ' IP-Checksumme berechnen Call Udp_checksum ' UDP-Checksumme berechnen Call Echopacket ' ... und raus damit #if Enc28j60_dhcp_output Print "Schritt 3 ---> DHCP request" #endif End Sub '-- End Send_dhcp_request ----------------------------------------------------- '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Dhcp_ack ' Diese Routine verarbeitet nach der ACK Bestätigunng des Routers die vom ' Router erhaltenen Detailinformationen und speichert diese in globalen ' Datenstrukturen. ' ' Parameter: keiner ' Rückgabe: Die Rückgabe der einzelnen Parameter erfolgt in globale ' Datenstrukturen ' ' Globale Variablen: ' Com_array = Kommunikationsdatenstruktur zum Senden und Empfangen von ' Ethernetpaketen ' '------------------------------------------------------------------------------ Sub Dhcp_ack ' ----- Programmcode ----- ' Source-MAC-Adresse, wenn DHCP-Server Router ist entspricht die MAC-Adresse auch der Router-MAC-Adresse Enc28j60_router_mac_adress(1) = Com_array(7) Enc28j60_router_mac_adress(2) = Com_array(8) Enc28j60_router_mac_adress(3) = Com_array(9) Enc28j60_router_mac_adress(4) = Com_array(10) Enc28j60_router_mac_adress(5) = Com_array(11) Enc28j60_router_mac_adress(6) = Com_array(12) ' Empfangene und damit zugewiesene IP Enc28j60_my_ip_adress(1) = Com_array(59) Enc28j60_my_ip_adress(2) = Com_array(60) Enc28j60_my_ip_adress(3) = Com_array(61) Enc28j60_my_ip_adress(4) = Com_array(62) ' Subnetzmaske im optionalen Teil Enc28j60_subnetmask(1) = Com_array(312) Enc28j60_subnetmask(2) = Com_array(313) Enc28j60_subnetmask(3) = Com_array(314) Enc28j60_subnetmask(4) = Com_array(315) ' Aktuelle IP-Konfiguration ausgegegeben werden Gosub Enc28j60_print_konfig ' Restlichen Status auf RS232 senden Gosub Consol_print_konfig End Sub '-- End Send_dhcp_request ----------------------------------------------------- '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Udp_receive ' ' Routine dient zum Handling von UDP-Paketen. ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Parameter: ' T_udp_destport0 und T_udp_destport0 für Zugriff in Datenstruktur auf Ports ' '------------------------------------------------------------------------------ Sub Udp_receive ' ----- lokale Variablen ----- Local Ltemp_word As Word ' ----- Programmcode ----- ' ===== Verarbeitung für DHCP / UDP-Port 67 und 68 ===== ' Prüfen ob auf UDP-Port Src = 67 und Dest = 68 eine Antwort kam If T_udp_destport0 = 0 And T_udp_destport1 = 68 Then '68 our DHCP port If T_udp_srcport0 = 0 And T_udp_srcport1 = 67 Then '67 server DHCP port ' JA, es scheint sich um eine Antwort auf unsere DHCP Anfrage zu handeln ' ggf. Trace ausgeben #if Enc28j60_dhcp_output Print "Antwort von Router auf Port 67 / 68 erhalten" #endif ' Funktion zum Auswerten der DHCP-Antwort aufrufen Call Dhcp_receive End If End If ' ===== ' ===== Verarbeitung für eingestellten Port ===== ' Da Destination-Port-Nummer anders in Datenstruktur abgelegt ist als der ' Kontroller HB und LW verwarbeitet, müssen zum Vergleich HB und LB gedreht werden! Ltemp_word = Enc28j60_tcp_port ' Portnummer in Arbeitsvariable Swap Ltemp_word ' High-Byte und Low-Byte drehen ' Prüfen ob auf eigenen eingestellten Port eine UDP-Botschaft gesendet wurde If T_udp_destport = Ltemp_word Then ' JA ' ggf. Trace ausgeben #if Enc28j60_udp_output Print "UDP Paket auf Port " ; Enc28j60_tcp_port ; " empfangen" #endif Call Udp_processing ' Processing aufrufen ' JA End If ' ===== End Sub '-- End Udp_receive ----------------------------------------------------------- '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Udp_processing ' ' Die Routine dient zum Verarbeiten von UDP-Protokoll-Paketen ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Parameter: ' Com_array = Datenstruktur des Sende- Empfangsbuffers ' ' Anmerkung: ' Funktion ist Notnagel-Funktion falls TCP-IP Kommunikation hängt so dass ' Mittels UDP-REBOOT-Kommando Steuerung in den Reset gezwungen werden kann. '------------------------------------------------------------------------------ Sub Udp_processing ' ----- lokale Variablen ----- Local Msg As String * 70 Local Ltemp_byte As Byte Local Ltemp_word As Word ' ----- Programmcode ----- ' Schleife über alle For Ltemp_word = 43 To Length Msg = Msg + Chr(com_array(ltemp_word ) ) ' String zusammenbauen Next Ltemp_word ' Eingegebener String komplett in Grossbuchstaben wandeln Msg = Ucase(msg) ' Führende Leerzeichen entfernen Msg = Ltrim(msg) ' Nachfolgende Leerzeichen entfernen Msg = Rtrim(msg) ' Prüfen ob Befehl REBOOT empfangen wurde If Msg = "REBOOT" Then ' JA --> Reset durchführen Goto 0 ' Reset End If ' REBOOT End Sub '-- End Udp_processing -------------------------------------------------------- '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Tcp_receive ' ' Die Routine dient zum Verarbeiten von TCP-Protokoll-Paketen ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Parameter: ' T_udp_destport0 und T_udp_destport0 für Zugriff in Datenstruktur auf Ports ' '------------------------------------------------------------------------------ Sub Tcp_receive ' ----- lokale Variablen ----- Local Ltemp_word_1 As Word ' ----- Programmcode ----- ' Ggf Trace schreiben #if Enc28j60_tcptrace Print "Enter Tcp_receive" #endif ' Da Destination-Port-Nummer anders in Datenstruktur abgelegt ist als der ' Kontroller HB und LW verwarbeitet, müssen zum Vergleich HB und LB gedreht werden! Ltemp_word_1 = Enc28j60_tcp_port ' Portnummer in Arbeitsvariable Swap Ltemp_word_1 ' High-Byte und Low-Byte drehen ' Prüfen ob Destination Port der eigenen eingestellten Portnummer enstpricht If Tcp_destport = Ltemp_word_1 Then ' JA ' Ggf Trace schreiben #if Enc28j60_tcptrace Print "** eigene Portnummer erkannt : " ; Enc28j60_tcp_port #endif ' Verarbeitung des TCP-Pakets aufrufen Call Tcp_processing End If End Sub '-- End Tcp_receive ----------------------------------------------------------- '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Tcp_processing ' ' Diese Routine dient zur Verarbeitung und Behandlung aller TCP-Pakete welche ' über den eingestellten Port empfangen werden und damit zum Hanlding von ' Konsoleneingaben via TCP dienen. ' ' Parameter: keiner ' Rückgabewert: keiner ' ' Globale Variablen: ' Die Funktion verwendet eine Vielzahl globaler Variablen welche ich hier nicht ' alle aufführen mag.... '------------------------------------------------------------------------------ Sub Tcp_processing ' ----- lokale Variablen ----- Local Work As Byte Local L_tempbyte As Byte Local Msg As String * 70 Local Char As String * 1 Local Work2 As Word Local Tcp_header_len As Byte Local Expected_seq As Long Local L_buffer_index As Word ' ----- Programmcode ----- ' Extrahiere die Flags aus der empfangenen Botschaft und speichere sie in Arbeitsvariablen Work = Tcp_flags ' Flags in Bytevariable umkopieren Tcp_fin = Work.0 ' FIN-Flag Tcp_syn = Work.1 ' SYNc-Flag Tcp_rst = Work.2 ' ReSeT-Flag Tcp_psh = Work.3 ' PuSH-Flag Tcp_ack = Work.4 ' ACKnowedgent-Flag Tcp_urg = Work.5 ' URGent-Flag ' Berechne die Länge des IP-Datenpakets Packetlength = T_ip_pktlen0 * 256 Packetlength = Packetlength + T_ip_pktlen1 ' Paketlänge der tatsächlichen Payload berechnen aus Paketlänge - (20Bytes IP-Header + 20Bytes TCP-Header = 40Bytes) Packetlength = Packetlength - 40 ' Acknowledgement number in Arbeitsvariable lesen Acknum3 = Tcp_acknum0 Acknum2 = Tcp_acknum1 Acknum1 = Tcp_acknum2 Acknum0 = Tcp_acknum3 ' Sequence number in Arbeitsvariable lesen Seqnum3 = Tcp_seqnum0 Seqnum2 = Tcp_seqnum1 Seqnum1 = Tcp_seqnum2 Seqnum0 = Tcp_seqnum3 ' TCP-Headerlaenge berechnen ' Anmerkung: ' Der TCP-Header ist ohne Optionsbytes 20 Bytes groß. Im Falle des Telnet Verbindungsaufbaus ist der Header 28 Bytes groß da 8 Bytes Optionen mitgesendet werden. Tcp_header_len = Tcp_hdr And &HF0 Shift Tcp_header_len , Right , 4 Tcp_header_len = Tcp_header_len * 4 'if an ACK is received and the destination port address is valid 'and no data is in the packet ' ===== Initiale Verarbeitung (ACK ohne Daten) ===== ' Dieser Codeteil dient zum Verarbeiten einer initialen Telent-Session direkt nach einem erfolgreichen SYN. ' Der eingehende ACK wird ohne Daten vom Client gesendet und verursacht das Senden des Menüs als erstes ' gültiges Telnet-Datenpaket. If Tcp_ack = 1 Then If Tcp_psh = 0 Then If Syncflag = 1 Then ' SyncFlag für Menü ' ggf. Trace ausgeben #if Enc28j60_tcptrace Print "*[1]* ACK ohne Daten" #endif Syncflag = 0 ' Syncflag zur weiteren Verarbeitung zurücksetzen ' TCP Handshake Expected_seq = Acknum Acknum = Seqnum + Packetlength Seqnum = Expected_seq Call Ack2tcp_ack ' Acknowledgement in Buffer eintragen Call Seq2tcp_seq ' Sequence number in Buffer eintragen Call Swapdestport2srcport ' Destination-Port und Source-Port Vertauschen da Antwort Call Swapsrc2dest ' MAC-Adressen im Ethernetframe von Source und Destination vertauschen Swap T_ip_destaddr , T_ip_srcaddr ' Move IP source address to destination address ' TCP-Flags setzen Tcp_flags = 0 ' Variable auf 0 Set Tcp_flags._ack ' ACK-Flag setzen (Bit 4) ' Willkommensbotschaft in Arbeitsvariable laden Msg = Versiontext + "{010}" ' Mittels Schleife String in Buffer zum Senden überragen For Work = 1 To Len(msg) L_tempbyte = 54 + Work Char = Mid(msg , Work , 1) Com_array(l_tempbyte) = Asc(char) Next Work ' Stringlänge ermitteln L_tempbyte = Len(msg) ' IP-Paketlänge berechnen und setzen Packetlength = 40 + L_tempbyte T_ip_pktlen0 = High(packetlength) T_ip_pktlen1 = Low(packetlength) ' Checksummen berechnen Call Ip_header_checksum ' IP Checksumme berechnen Call Tcp_checksum ' TCP Checksumme berechnen ' 14 Bytes für Länge des Ethernet-Frames hinzuaddieren Packetlength = Packetlength + 14 ' Und raus damit Call Enc28j60_packetsend(packetlength) End If End If End If ' ===== ' ===== Verarbeitung von Daten (ACK mit Daten) ===== ' Dieser Codeteil dient zum Verarbeiten eines eingehenden ACK mit anschließender Verarbeitung. ' Der Coderteil wird während einer normalen Kommunikation durchlaufen If Tcp_ack = 1 Then If Tcp_psh = 1 Then If Packetlength > 0 Then ' ggf. Trace ausgeben #if Enc28j60_tcptrace Print "*[3]* ACK mit Daten" #endif ' Anmerkungen: ' [1] ' Die Eingaben über Putty werden aktuelle in zwei einzelnen Botschaften gesendet. ' Die Botschaft 1 beinhaltet den eigentlichen Kontent und die Botschaft 2 besteht aus CR+LF ' Die Kommandos werden erst dann verarbeitet wenn CR+LF <0D><0A> oder LF+CR <0A><0D> empfangen wurde. ' TCP Handshake Expected_seq = Acknum Acknum = Seqnum + Packetlength Seqnum = Expected_seq Call Ack2tcp_ack ' Acknowledgement in Buffer eintragen Call Seq2tcp_seq ' Sequence number in Buffer eintragen Call Swapdestport2srcport ' Destination-Port und Source-Port Vertauschen da Antwort Call Swapsrc2dest ' MAC-Adressen im Ethernetframe von Source und Destination vertauschen Swap T_ip_destaddr , T_ip_srcaddr ' Move IP source address to destination address ' TCP-Flags setzen Tcp_flags = 0 ' Variable auf 0 Set Tcp_flags._ack ' ACK-Flag setzen (Bit 4) ' ggf. Trace ausgeben #if Enc28j60_tcptrace Print "Empfangene Paketlänge : " ; Length #endif ' Tatsächliche Länge der empfangenen Daten im TCP-Datenpaket berechnen Work2 = T_ip_pktlen0 * 256 ' Highbyte verrechnen Work2 = Work2 + T_ip_pktlen1 ' Low-Byte verrechnen Work2 = Work2 - Ip_header_const ' IP-Headergröße abziehen ' ggf. Trace ausgeben #if Enc28j60_tcptrace Print "Empfangene Größe Nutzdaten : " ; Work2 #endif ' Work2 = Length - Tcp_data ' Länge des String berechnen welcher Empfangen wurde Msg = "" ' String zurücksetzen ' Prüfen ob Empfangsstring noch in Buffer passt If Work2 < 70 Then ' JA ' Hilfsvariable auf Ende der Nutzdaten berechnen Work2 = Work2 + Tcp_data ' Endzeiger berechnen Decr Work2 ' korrigieren ' Schleife über alle For Work = Tcp_data To Work2 Msg = Msg + Chr(com_array(work ) ) ' String zusammenbauen Next Work ' String zunächst zusammensetzen falls mehrteilige Botschaft empfangen wurde Consol_instring = Consol_instring + Msg ' Prüfen ob CR+LF bereits empfangen wurde L_tempbyte = Instr(consol_instring , "{013}{010}") If L_tempbyte > 0 Then ' JA, es wurde CR+LF empfangen --> String verarbeiten ' CR + LF aus String entfernrn Delchars Consol_instring , 10 ' entferne alle CR Delchars Consol_instring , 13 ' entferne alle LF ' Eingegebener String komplett in Grossbuchstaben wandeln Consol_instring = Ucase(consol_instring) ' Führende Leerzeichen entfernen Consol_instring = Ltrim(consol_instring) ' Nachfolgende Leerzeichen entfernen Consol_instring = Rtrim(consol_instring) ' Stringeingabe bearbeiten und String parsen. ' Rückgabewert enthält boolsche Variable ob Verarbeitung erfolgreich war oder Fehler aufgetreten ist. ' Entsprechende Rückgaben und Meldungen werden im globalen string Console_outstring von der Funktion zurückgegeben. Temp_byte_1 = Consol_process_command(consol_instring , Source_tcp) ' Prüfen ob Text direkt übernommen werden kann oder ob es sich um eine Sequence handelt If Consol_tcp_sequence_nummer = Sequence_nix Then ' NEIN -> Botschaft kann normal verarbeitet werden Msg = Consol_outstring + "{010}" ' Text in Buffer kopieren (ab Position 55 = Tcp_data) For Work = 1 To Len(msg) L_buffer_index = 54 + Work Char = Mid(msg , Work , 1) Com_array(l_buffer_index) = Asc(char) Next Work ' Paketlänge um Länge des String ergänzen der gerade eingeladen wurde Packetlength = Len(msg) Else ' JA -> Text ist sequence ' Paket-Laenge zunächst auf NULL setzen Packetlength = 0 ' Entsprechende Textsequence in Buffer schreiben Gosub Consol_tcp_text_output End If ' Ein- und Ausgabestring zurücksetzen Consol_instring = "" Consol_outstring = "" Else ' String ist noch nicht vollständig oder es wurde irgendwas empfangen damit nix machen sondern nur quittieren Packetlength = 0 ' keine weitere Daten End If End If ' Prügung Empfangsstrinlänge ' An dieser Stelle beinhaltet Paletlength nur die Länge des String in der Payload ' IP-Paketlänge berechnen und setzen Packetlength = Packetlength + 40 ' 20 Bytes IP-Header + 20 Bytes TCP-Header T_ip_pktlen0 = High(packetlength) T_ip_pktlen1 = Low(packetlength) ' Checksummen berechnen Call Ip_header_checksum ' IP Checksumme berechnen Call Tcp_checksum ' TCP Checksumme berechnen Packetlength = Packetlength + 14 ' Korrektur 14 Bytes des Ethernet-Frames ' ggf. Trace ausgeben #if Enc28j60_tcptrace Print "## Paketlänge : " ; Packetlength #endif ' Und raus damit Call Enc28j60_packetsend(packetlength) End If End If End If ' ===== ' ===== SYN ACK als Antwort auf SYN ===== ' Dieser Codeteil dient zum Verarbeiten eines eingehenden SYN als Verbindungsaufbau welcher vom Telnet Client initiiert wird. ' Es wird die initiale sequence number erzeugt und zusammen mit dem acknowledgment und dem aktiven ACK flag and den Client ' als Antwort auf das SYN paket zurückgesendet. If Tcp_syn = 1 Then ' SYN-Flag gesetzt? ' ggf. Trace ausgeben #if Enc28j60_tcptrace Print "*[4]* SYN ACK auf SYN" #endif ' TCP Handshake zum Verbindungsaufbau ' SYN Anfrage vom Client mit seq=x erfolgt Acknum = Seqnum + 1 ' SYN ACK=x+1 und Seqnum = &H1011FFFF ' Initial Sequence Number seq=y Set Syncflag Call Ack2tcp_ack ' Acknowledgement in Buffer eintragen Call Seq2tcp_seq ' Sequence number in Buffer eintragen Call Swapdestport2srcport ' Destination-Port und Source-Port Vertauschen da Antwort Call Swapsrc2dest ' MAC-Adressen im Ethernetframe von Source und Destination vertauschen Swap T_ip_destaddr , T_ip_srcaddr ' Move IP source address to destination address ' TCP-Flags setzen Tcp_flags = 0 ' Variable auf 0 Set Tcp_flags.syn ' SYN-Flag setzen (Bit 1) Set Tcp_flags._ack ' ACK-Flag setzen (Bit 4) ' IP-Paketlänge berechnen und setzen T_ip_pktlen0 = &H00 T_ip_pktlen1 = Length - 14 ' Gesamtlänge 14 Bytes für Ethernetframelänge ' Checksummen berechnen Call Ip_header_checksum ' IP Checksumme berechnen Call Tcp_checksum ' TCP Checksumme berechnen ' Und raus damit Call Enc28j60_packetsend(length) ' Umgebaut auf neue tatsächliche Länge ' Ben's Originalimplementierung arbeitete mit fester Länge End If ' ===== ' ===== ACK and FIN ===== ' Verarbeitung der Ende-Session If Tcp_ack = 1 Then ' ACK-Flag gesetzt? If Tcp_fin = 1 Then ' FIN-Flag gesetzt? ' ggf. Trace ausgeben #if Enc28j60_tcptrace Print "*[5]* ACK and FIN" #endif ' TCP Hansshake Expected_seq = Acknum ' Acknowledgement lesen Acknum = Seqnum + 1 ' SYN ACK=x+1 und Seqnum = Expected_seq ' Sequence Number setzen Call Ack2tcp_ack ' Acknowledgement in Buffer eintragen Call Seq2tcp_seq ' Sequence number in Buffer eintragen Call Swapdestport2srcport ' Destination-Port und Source-Port Vertauschen da Antwort Call Swapsrc2dest ' MAC-Adressen im Ethernetframe von Source und Destination vertauschen Swap T_ip_destaddr , T_ip_srcaddr ' Move IP source address to destination address ' TCP-Flags setzen Tcp_flags = 0 ' Variable auf 0 Set Tcp_flags._ack ' ACK-Flag setzen (Bit 4) Set Tcp_flags.fin ' FIN-Flag setzen (Bit 0) T_ip_pktlen0 = &H00 T_ip_pktlen1 = Length - 14 ' Gesamtlänge 14 Bytes für Ethernetframelänge ' Checksummen berechnen Call Ip_header_checksum ' IP Checksumme berechnen Call Tcp_checksum ' TCP Checksumme berechnen ' Und raus damit Call Enc28j60_packetsend(length) ' Umgebaut auf neue tatsächliche Länge ' Ben's Originalimplementierung arbeitete mit fester Länge End If End If ' ===== End Sub '-- End Tcp_processing -------------------------------------------------------- '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Ack2tcp_ack ' Diese Routine übertrag das Acknowledgement aus der globalen Arbeitsvariable ' in die TCP-Struktur des Sendebuffers ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' Acknum0 .. Acknum3: beinhaltet das zuvor gespeicherte Acknowledgement '------------------------------------------------------------------------------ Sub Ack2tcp_ack Tcp_acknum3 = Acknum0 Tcp_acknum2 = Acknum1 Tcp_acknum1 = Acknum2 Tcp_acknum0 = Acknum3 End Sub '-- End Ack2tcp_ack ----------------------------------------------------------- '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Seq2tcp_seq ' Diese Routine übertrag die Sequencenummer aus der globalen Arbeitsvariable ' in die TCP-Struktur des Sendebuffers ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' Seqnum0 .. Seqnum3: beinhaltet die zuvor gespeicherte Sequence Number '------------------------------------------------------------------------------ Sub Seq2tcp_seq Tcp_seqnum3 = Seqnum0 Tcp_seqnum2 = Seqnum1 Tcp_seqnum1 = Seqnum2 Tcp_seqnum0 = Seqnum3 End Sub '-- End Seq2tcp_seq ----------------------------------------------------------- '------------------------------------------------------------------------------ ' ENC28J60 - Sub-Routine: Swapsrc2dest ' Diese Routine vertausche MAC-Destination- und MAC-Source-Adresse im TCP-Frame ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' T_enetpacketsrc0..T_enetpacketsrc6 = Adressfeld für MAC-Source-Adresse ' T_enetpacketdest0..T_enetpacketdest6 = Adressfeld für MAC-Destination-Adresse '------------------------------------------------------------------------------ Sub Swapsrc2dest Swap T_enetpacketdest0 , T_enetpacketsrc0 Swap T_enetpacketdest1 , T_enetpacketsrc1 Swap T_enetpacketdest2 , T_enetpacketsrc2 Swap T_enetpacketdest3 , T_enetpacketsrc3 Swap T_enetpacketdest4 , T_enetpacketsrc4 Swap T_enetpacketdest5 , T_enetpacketsrc5 End Sub '-- End Swapsrc2dest ---------------------------------------------------------- ' ********************** ' * Controllfunktionen * ' ********************** '------------------------------------------------------------------------------ ' Control - Sub-Routine: Control_pwr_cam1 ' ' Routine steuert die Spannungsversogung für Kamera 1 ' ' Parameter: Pwr_status gibt an ob die Spannungsversorgung ' "Ein" = 1 = eingeschaltet oder ' "Aus" = 0 = ausgeschaltet werden soll ' Rückgabe: keine ' ' Globale Parameter: ' Control_kamera1_pwr_flag = Zustand des Schalters ' '------------------------------------------------------------------------------ Sub Control_pwr_cam1(byval Pwr_status As Byte) ' ----- Programmcode ----- Select Case Pwr_status Case Aus: Pwr_cam1 = Aus Control_kamera1_pwr_flag = Aus Case Ein: Pwr_cam1 = Ein Control_kamera1_pwr_flag = Ein End Select End Sub '-- End Control_pwr_cam1 ------------------------------------------------------ '------------------------------------------------------------------------------ ' Control - Sub-Routine: Control_pwr_cam1 ' ' Routine steuert die Spannungsversogung für Kamera 1 ' ' Parameter: Pwr_status gibt an ob die Spannungsversorgung ' "Ein" = 1 = eingeschaltet oder ' "Aus" = 0 = ausgeschaltet werden soll ' Rückgabe: keine ' ' Globale Parameter: ' Control_kamera2_pwr_flag = Zustand des Schalters ' '------------------------------------------------------------------------------ Sub Control_pwr_cam2(byval Pwr_status As Byte) ' ----- Programmcode ----- Select Case Pwr_status Case Aus: Pwr_cam2 = Aus Control_kamera2_pwr_flag = Aus Case Ein: Pwr_cam2 = Ein Control_kamera2_pwr_flag = Ein End Select End Sub '-- End Control_pwr_cam2 ------------------------------------------------------ ' ***************************** ' * IR Hintergrundbeleuchtung * ' ***************************** '------------------------------------------------------------------------------ ' IR - Subroutine: Ir_set_helligkeit ' ' Subroutine setzt den als Übergabeparameter übergebenen Bytewert als ' IR Helligkeitswert ' ' Parameter: Value = Bytewert für IR Helligkeit ' Rückgabewert: keine ' ' Globale Variable: ' Control_irhelligkeit = globale Variable für Helligkeitswert '------------------------------------------------------------------------------ Sub Ir_set_helligkeit(byval Value As Byte) ' ----- Programmcode ----- #if Ir_testmodus Print "Enter Ir_set_helligkeit" #endif ' PWM-Wert in Arbeitsvarable schreiben Control_irhelligkeit = Value ' PWM-Wert gleich in EEPROM abspeichern Ee_data_irhelligkeit = Control_irhelligkeit ' Variable in Timer-Count-Register laden Ocr2 = Control_irhelligkeit ' Prüfen welche Werte geschrieben wurden und entsprechend Status setzen If Value = Ir_helligkeit_aus Then Ir_status_flag = Aus Else Ir_status_flag = Ein End If End Sub '-- End Ir_set_helligkeit ----------------------------------------------------- '****************************************************************************** ' Funktionen '****************************************************************************** ' ************ ' * ENC28J60 * ' ************ '------------------------------------------------------------------------------ ' ENC28J60 - Funktion: Enc28j60_readphyword ' ' Routine dient zum Lesen eines 16-Bit Werts aus dem PHY register. ' ' Parameter: phyregister = Adresse des PHY rgisters ' Rückgabe: (WORD) Inhalt des PHY-Registers in einer ' ' Globale Variablen: ' Enc28j60_data = Byte-Variable zur Übergabe von Registerinhalten '------------------------------------------------------------------------------ Function Enc28j60_readphyword(phyregister As Byte) As Word ' ----- Lokale Variablen ----- Local Ltemp_word As Word ' ----- Programmcode ----- ' ggf. Trace schreiben #if Enc28j60_testmodus Print "Enc28j60_readphyword entered" #endif ' Set the right address and start the register read operation Call Enc28j60_writecontrolregbyte(miregadr , Phyregister) ' Write the address of the PHY register to read from into the MIREGADR register. Call Enc28j60_writecontrolregbyte(micmd , Micmd_miird) ' Set the MICMD.MIIRD bit. The read operation begins and the MISTAT.BUSY bit is set. ' Kommentar aus dem Datenblatt: ' Wait 10.24 ìs. Poll the MISTAT.BUSY bit to be ' certain that the operation is complete. While ' busy, the host controller should not start any ' MIISCAN operations or write to the MIWRH ' register. ' When the MAC has obtained the register ' Contents , The Busy Bit Will Clear Itself. ' wait until the PHY read completes Do Call Enc28j60_readcontrolregbyte(mistat) Loop Until Enc28j60_data.mistat_busy = 0 ' quit reading Call Enc28j60_writecontrolregbyte(micmd , 0) ' Clear the MICMD.MIIRD bit. ' get data value Call Enc28j60_readcontrolregbyte(mirdl) ' Read the desired data from the MIRDL and Ltemp_word = Enc28j60_data ' MIRDH registers. The order that these bytes are Shift Ltemp_word , Left , 8 ' accessed is unimportant. Call Enc28j60_readcontrolregbyte(mirdh) Ltemp_word = Ltemp_word + Enc28j60_data ' 16 Bit Variable zusammensetzen ' Rückgabewert and Funktion übergeben Enc28j60_readphyword = Ltemp_word End Function '-- End Enc28j60_readphyword --------------------------------------------------- ' ********** ' * CONSOL * ' ********** '------------------------------------------------------------------------------ ' CONSOL - Funktion: Consol_process_command ' ' Routine dient zum Parsen und Verarbeiten empfangener Kommandos welche über ' RS232-Konsole oder via TCP-Protokoll empfangen wurden. ' ' Parameter: Command_string = String der geparst und verarbeitet werden soll ' Command_source = Flag ob Eingabe über RS232 oder TCP erfolgte ' Rückgabe: boolsche Variable True/False ob Verarbeitung erfolgreich war ' ' Globale Variablen: ' Enc28j60_data = Byte-Variable zur Übergabe von Registerinhalten '------------------------------------------------------------------------------ Function Consol_process_command(command_string As String , Command_source As Byte) As Byte ' ----- lokale Variablen ----- Local Lresult As Byte Local Largument_count As Byte Local Ltemp_string As String * 20 ' ----- Programcode ----- Lresult = True ' ggf. Traces ausgeben #if Consol_trace Print "Verarbeite String : " ; Command_string If Command_source = Source_tcp Then Print "Quelle ist : TCP" Else Print "Quelle ist : RS232" End If #endif ' Kommandostring zerlegen, als Trennzeichen SPACE verwenden Largument_count = Split(command_string , Consol_argument_array(1) , " " ) ' Prüfen ob String mehr als 2 Teilargumente (Kommandos + Parameter) hat If Largument_count > 2 Then ' JA, das ist ein Fehler --> keine Verarbeitung ' Fehlerflag setzen Lresult = False Else ' NEIN, String besitzt maximal 2 Argumente ' Prüfen ob String sogar nur ein Argument besitzt, für Kommandos ohne Parameter If Largument_count = 1 Then ' JA, das Kommando kann ohne weitere Verarbeitung direkt überprüft werden Select Case Consol_argument_array(1) Case "REBOOT" : Goto 0 Case "VERSION" : Consol_outstring = Versiontext Case "RESETPARAM" : ' Defaultwerte in EEPROM schreiben Gosub Ee_write_default_eeprom Consol_outstring = "OK" + "{013}{010}" Case "XSTATUS" : ' Prüfen ob Kommando über TCP kam If Command_source = Source_tcp Then Consol_tcp_sequence_nummer = Sequence_xstatus Consol_outstring = "*SEQUENCE*" Else Consol_outstring = "NOK" + "{013}{010}" End If Case "GETSTATUS" : Select Case Command_source Case Source_tcp : Consol_tcp_sequence_nummer = Sequence_status Consol_outstring = "*SEQUENCE*" Case Source_rs232 : Gosub Enc28j60_print_konfig Gosub Consol_print_konfig Case Else : Consol_outstring = "undefiniert" + "{013}{010}" End Select Case "HELP" : Select Case Command_source Case Source_tcp : Consol_tcp_sequence_nummer = Sequence_help Consol_outstring = "*SEQUENCE*" Case Source_rs232 : Gosub Consol_print_help Case Else : Consol_outstring = "undefiniert" + "{013}{010}" End Select Case "GETDHCP" : If Enc28j60_dhcp_flag = Dhcp_aus Then Consol_outstring = "DHCP ist AUS" + "{013}{010}" Else Consol_outstring = "DHCP ist EIN" + "{013}{010}" End If Case "GETIP" : Consol_outstring = "IP: " + Str(enc28j60_my_ip_adress(1)) + "." + Str(enc28j60_my_ip_adress(2)) + "." + Str(enc28j60_my_ip_adress(3)) + "." + Str(enc28j60_my_ip_adress(4)) + "{013}{010}" Case "GETGW" : Consol_outstring = "IP: " + Str(enc28j60_gateway_ip_adress(1)) + "." + Str(enc28j60_gateway_ip_adress(2)) + "." + Str(enc28j60_gateway_ip_adress(3)) + "." + Str(enc28j60_gateway_ip_adress(4)) + "{013}{010}" Case "GETSUBNET" : Consol_outstring = "IP: " + Str(enc28j60_subnetmask(1)) + "." + Str(enc28j60_subnetmask(2)) + "." + Str(enc28j60_subnetmask(3)) + "." + Str(enc28j60_subnetmask(4)) + "{013}{010}" Case "GETMAC" : Consol_outstring = "MAC: " + Hex(enc28j60_my_mac_adress(1)) + ":" + Hex(enc28j60_my_mac_adress(2)) + ":" + Hex(enc28j60_my_mac_adress(3)) + ":" + Hex(enc28j60_my_mac_adress(4)) + ":" + Hex(enc28j60_my_mac_adress(5)) + ":" + Hex(enc28j60_my_mac_adress(6)) + "{013}{010}" Case "GETNTP" : Consol_outstring = "IP: " + Str(enc28j60_ntp_ip_adress(1)) + "." + Str(enc28j60_ntp_ip_adress(2)) + "." + Str(enc28j60_ntp_ip_adress(3)) + "." + Str(enc28j60_ntp_ip_adress(4)) + "{013}{010}" Case "GETROUTERMAC" : Consol_outstring = "MAC: " + Hex(enc28j60_router_mac_adress(1)) + ":" + Hex(enc28j60_router_mac_adress(2)) + ":" + Hex(enc28j60_router_mac_adress(3)) + ":" + Hex(enc28j60_router_mac_adress(4)) + ":" + Hex(enc28j60_router_mac_adress(5)) + ":" + Hex(enc28j60_router_mac_adress(6)) + "{013}{010}" Case "GETPORT" : Consol_outstring = "PORT: " + Str(enc28j60_tcp_port) + "{013}{010}" Case "GETMODE" : Select Case Control_runningmode Case Mode_manuell : Consol_outstring = "MANUELL" + "{013}{010}" Case Mode_licht : Consol_outstring = "LICHT" + "{013}{010}" Case Mode_zeit : Consol_outstring = "ZEIT" + "{013}{010}" Case Else : Consol_outstring = "undefiniert" + "{013}{010}" End Select Case "GETPWMVALUE" : Consol_outstring = "PWM: " + Str(control_irhelligkeit) + "{013}{010}" Case "GETLDRLOWER" : Consol_outstring = "LDR unten: " + Str(control_ldr_lower) + "{013}{010}" Case "GETLDRUPPER" : Consol_outstring = "LDR oben: " + Str(control_ldr_upper) + "{013}{010}" Case "GETTIMER" : Consol_outstring = "Zeit: " + Str(control_videotimer) + "{013}{010}" Case "GETIR" : Select Case Ir_status_flag Case Aus : Consol_outstring = "IR ist AUS" + "{013}{010}" Case Ein : Consol_outstring = "IR ist EIN" + "{013}{010}" Case Else : Consol_outstring = "undefiniert" + "{013}{010}" End Select Case "GETSOURCE" : Select Case Control_kamera_flag Case 1 : Consol_outstring = "Kamera 1" + "{013}{010}" Case 2 : Consol_outstring = "Kamera 2" + "{013}{010}" Case Else : Consol_outstring = "undefiniert" + "{013}{010}" End Select Case "GETPWRCAM1" : Select Case Control_kamera1_pwr_flag Case Aus : Consol_outstring = "Kamera 1 AUS" + "{013}{010}" Case Ein : Consol_outstring = "Kamera 1 EIN" + "{013}{010}" Case Else : Consol_outstring = "undefiniert" + "{013}{010}" End Select Case "GETPWRCAM2" : Select Case Control_kamera2_pwr_flag Case Aus : Consol_outstring = "Kamera 2 AUS" + "{013}{010}" Case Ein : Consol_outstring = "Kamera 2 EIN" + "{013}{010}" Case Else : Consol_outstring = "undefiniert" + "{013}{010}" End Select Case "GETLDR" : Consol_outstring = "LDR: " + Str(light_value) + "{013}{010}" Case "DOMEASUREMENT" : Light_value = Light_measurement() Consol_outstring = "LDR: " + Str(light_value) + "{013}{010}" Case "GETRELAIS" : Select Case Relais_status_flag Case Relais_aus : Consol_outstring = "Relais AUS" + "{013}{010}" Case Relais_ein : Consol_outstring = "Relais EIN" + "{013}{010}" Case Else : Consol_outstring = "undefiniert" + "{013}{010}" End Select Case Else: Lresult = False ' Nix dabei -> Fehlerflag setzen End Select Else ' NEIN, Kommando hat mindestens einen Parameter, Parameter muss weiter zerlegt werden ' Zur weiteren Verarbeitung 2. Argument in lokale Variable retten Ltemp_string = Consol_argument_array(2) ' Versuche String mit PUNKT Trennzeichen zu zerlegen um IP-Adressen zu extrahieren Largument_count = Split(ltemp_string , Consol_argument_array(2) , "." ) ' Prüfe ob Argument in 4 einzene Teile für das Format einer IP-Adresse zerlegt werden konnte If Largument_count = 4 Then ' JA, es wurden 4 Einzelteile mit PUNKT als Trennzeichen erkannt. ' Wandle alle 4 Teilstrings in einzelne Zahlen und speichere diese zur weiteren Verarbeitung ' in einem globalen Zahlenarray Consol_parameter_array(1) = Val(consol_argument_array(2)) Consol_parameter_array(2) = Val(consol_argument_array(3)) Consol_parameter_array(3) = Val(consol_argument_array(4)) Consol_parameter_array(4) = Val(consol_argument_array(5)) ' ggf. einzelne Zahlen als Trace ausgeben #if Consol_trace Print "Parameter : " ; Consol_parameter_array(1) ; "." ; Consol_parameter_array(2) ; "." ; Consol_parameter_array(3) ; "." ; Consol_parameter_array(4) #endif ' Nun können alle Kommandos erkannt werden welche eine IP-Adresse als Parameter haben Select Case Consol_argument_array(1) Case "SETIP" : Ee_data_ip_adr_1 = Consol_parameter_array(1) Ee_data_ip_adr_2 = Consol_parameter_array(2) Ee_data_ip_adr_3 = Consol_parameter_array(3) Ee_data_ip_adr_4 = Consol_parameter_array(4) Consol_outstring = "OK, set to " + Str(consol_parameter_array(1)) + "." + Str(consol_parameter_array(2)) + "." + Str(consol_parameter_array(3)) + "." + Str(consol_parameter_array(4)) + "{013}{010}" Case "SETGW" : Ee_data_gateway_1 = Consol_parameter_array(1) Ee_data_gateway_2 = Consol_parameter_array(2) Ee_data_gateway_3 = Consol_parameter_array(3) Ee_data_gateway_4 = Consol_parameter_array(4) Consol_outstring = "OK, set to " + Str(consol_parameter_array(1)) + "." + Str(consol_parameter_array(2)) + "." + Str(consol_parameter_array(3)) + "." + Str(consol_parameter_array(4)) + "{013}{010}" Case "SETSUBNET" : Ee_data_submask_1 = Consol_parameter_array(1) Ee_data_submask_2 = Consol_parameter_array(2) Ee_data_submask_3 = Consol_parameter_array(3) Ee_data_submask_4 = Consol_parameter_array(4) Consol_outstring = "OK, set to " + Str(consol_parameter_array(1)) + "." + Str(consol_parameter_array(2)) + "." + Str(consol_parameter_array(3)) + "." + Str(consol_parameter_array(4)) + "{013}{010}" Case "SETNTP" : Ee_data_ntp_1 = Consol_parameter_array(1) Ee_data_ntp_2 = Consol_parameter_array(2) Ee_data_ntp_3 = Consol_parameter_array(3) Ee_data_ntp_4 = Consol_parameter_array(4) Consol_outstring = "OK, set to " + Str(consol_parameter_array(1)) + "." + Str(consol_parameter_array(2)) + "." + Str(consol_parameter_array(3)) + "." + Str(consol_parameter_array(4)) + "{013}{010}" Case Else: Lresult = False ' Nix dabei -> Fehlerflag setzen End Select Else ' NEIN es wurden nicht 4 Einzelteile mit PUNKT Trennzeichen erkannt ' ==> es kann nur eine Zahl ohne Trennzeichen geben oder aber mehr ' Versuche String mit DOPPELPUNKT Trennzeichen zu zerlegen um MAC-Adressen zu extrahieren Largument_count = Split(ltemp_string , Consol_argument_array(2) , ":" ) ' Prüfe ob Argument in 6 einzene Teile für das Format einer MAC-Adresse zerlegt werden konnte If Largument_count = 6 Then ' JA, es wurden 6 Einzelteile mit DOPPELPUNKT als Trennzeichen erkannt. ' Wandle alle 6 Teilstrings in einzelne Zahlen und speichere diese zur weiteren Verarbeitung ' in einem globalen Zahlenarray. beachte dass MAC-Adressen in HEX-Schreibweise eingegeben werden! Consol_parameter_array(1) = Hexval(consol_argument_array(2)) Consol_parameter_array(2) = Hexval(consol_argument_array(3)) Consol_parameter_array(3) = Hexval(consol_argument_array(4)) Consol_parameter_array(4) = Hexval(consol_argument_array(5)) Consol_parameter_array(5) = Hexval(consol_argument_array(6)) Consol_parameter_array(6) = Hexval(consol_argument_array(7)) ' ggf. einzelne Zahlen als Trace ausgeben #if Consol_trace Print "Parameter : " ; Hex(consol_parameter_array(1)) ; ":" ; Hex(consol_parameter_array(2)) ; ":" ; Hex(consol_parameter_array(3)) ; ":" ; Hex(consol_parameter_array(4)) ; ":" ; Hex(consol_parameter_array(5)) ; ":" ; Hex(consol_parameter_array(6)) #endif ' Nun können alle Kommandos erkannt werden welche eine MAC-Adresse als Parameter haben Select Case Consol_argument_array(1) Case "SETMAC" : Ee_data_mac_1 = Consol_parameter_array(1) Ee_data_mac_2 = Consol_parameter_array(2) Ee_data_mac_3 = Consol_parameter_array(3) Ee_data_mac_4 = Consol_parameter_array(4) Ee_data_mac_5 = Consol_parameter_array(5) Ee_data_mac_6 = Consol_parameter_array(6) Consol_outstring = "OK, set to " + Hex(consol_parameter_array(1)) + ":" + Hex(consol_parameter_array(2)) + ":" + Hex(consol_parameter_array(3)) + ":" + Hex(consol_parameter_array(4)) + ":" + Hex(consol_parameter_array(5)) + ":" + Hex(consol_parameter_array(6)) + "{013}{010}" Case "SETROUTERMAC" : Ee_data_mac_router_1 = Consol_parameter_array(1) Ee_data_mac_router_2 = Consol_parameter_array(2) Ee_data_mac_router_3 = Consol_parameter_array(3) Ee_data_mac_router_4 = Consol_parameter_array(4) Ee_data_mac_router_5 = Consol_parameter_array(5) Ee_data_mac_router_6 = Consol_parameter_array(6) Consol_outstring = "OK, set to " + Hex(consol_parameter_array(1)) + ":" + Hex(consol_parameter_array(2)) + ":" + Hex(consol_parameter_array(3)) + ":" + Hex(consol_parameter_array(4)) + ":" + Hex(consol_parameter_array(5)) + ":" + Hex(consol_parameter_array(6)) + "{013}{010}" Case Else: Lresult = False ' Nix dabei -> Fehlerflag setzen End Select Else ' NEIN es wurden nicht 6 Einzelteile mit DOPPELPUNKT Trennzeichen erkannt ' ==> es besteht noch die Chance dass das Kommando nur ein einzelnes Argument besitzt ' Versuche Teilstring in Zahl umzuwandeln. Achtung! Zahl kann größer sein daher Umwandlung in WORD ' Wenn Wandlung fehlschlägt wird Zahl auch auf NULL gesetzt Consol_parameter_word = Val(ltemp_string) ' ggf. einzelne Zahlen als Trace ausgeben #if Consol_trace Print " Parameter : " ; Consol_parameter_word #endif ' Nun können noch alle Kommandos erkannt werden welche nur einen einzelnen Parameter haben Select Case Consol_argument_array(1) Case "SETDHCP" : If Consol_parameter_word <= 1 Then Temp_byte_1 = Consol_parameter_word ' Word auf Byte casten Ee_data_dhcp = Temp_byte_1 Consol_outstring = "OK" + "{013}{010}" Else Consol_outstring = "NOK" + "{013}{010}" End If Case "SETPORT" : Ee_data_port = Consol_parameter_word Consol_outstring = "OK" + "{013}{010}" Case "SETMODE" : If Consol_parameter_word <= 3 Then Temp_byte_1 = Consol_parameter_word ' Word auf Byte casten Control_runningmode = Temp_byte_1 Ee_data_runningmode = Control_runningmode Select Case Control_runningmode Case Mode_manuell : Consol_outstring = "OK - Manuell" + "{013}{010}" Mode_led = Led_aus ' LED-Anzeige für Betriebsart ausschalten Case Mode_licht : Light_value = Light_measurement() ' Neue Lichtmessung durchführen Gosub Control_check_licht ' Korrekte Kamera auswählen Consol_outstring = "OK - Licht" + "{013}{010}" Mode_led = Led_ein ' LED-Anzeige für Betriebsart einschalten Case Mode_zeit : ' Timer neu setzen für die Zeit in der das nächste mal Umgeschaltet werden soll Control_timer_mode_counter = Scheduler_timer_counter + Control_videotimer Consol_outstring = "OK - Zeit" + "{013}{010}" ' Bei Betriebsart ZEIT wird LED durch Sekunden-Tick getoggelt!!! End Select Else Consol_outstring = "NOK" + "{013}{010}" End If Case "SETPWMVALUE" : If Consol_parameter_word <= 255 Then Temp_byte_1 = Consol_parameter_word ' Word auf Byte casten Call Ir_set_helligkeit(temp_byte_1) ' Parameter speichern Consol_outstring = "OK" + "{013}{010}" Else Consol_outstring = "NOK" + "{013}{010}" End If Case "SETLDRLOWER" : If Consol_parameter_word <= 1023 Then Control_ldr_lower = Consol_parameter_word Ee_data_ldr_lower = Control_ldr_lower Consol_outstring = "OK" + "{013}{010}" Else Consol_outstring = "NOK" + "{013}{010}" End If Case "SETLDRUPPER" : If Consol_parameter_word <= 1023 Then Control_ldr_upper = Consol_parameter_word Ee_data_ldr_upper = Control_ldr_upper Consol_outstring = "OK" + "{013}{010}" Else Consol_outstring = "NOK" + "{013}{010}" End If Case "SETTIMER" : Control_videotimer = Consol_parameter_word Ee_data_videotimer = Control_videotimer Consol_outstring = "OK" + "{013}{010}" Case "SETIR" : Select Case Consol_parameter_word Case Aus : Gosub Ir_beleuchtung_aus Consol_outstring = "OK" + "{013}{010}" Case Ein : Gosub Ir_beleuchtung_an Consol_outstring = "OK" + "{013}{010}" Case Else: Consol_outstring = "NOK" + "{013}{010}" End Select Case "SETSOURCE" : Select Case Consol_parameter_word Case 1: ' Schalten auf Kamera 1 Gosub Control_kamera1_aktiv Consol_outstring = "OK" + "{013}{010}" Control_runningmode = Mode_manuell ' Aufgrund manuellem Eingriff wir temporär auf manuellen Betriebmodus geschaltet Mode_led = Led_aus ' Status für Betriebsart anpassen Case 2 : ' Schalten Auf Kamera 2 Gosub Control_kamera2_aktiv Consol_outstring = "OK" + "{013}{010}" Control_runningmode = Mode_manuell ' Aufgrund manuellem Eingriff wir temporär auf manuellen Betriebmodus geschaltet Mode_led = Led_aus ' Status für Betriebsart anpassen Case Else: ' Fehler Consol_outstring = "NOK" + "{013}{010}" End Select ' Kommando SETSOURCE Case "SETPWRCAM1" : Select Case Consol_parameter_word Case Aus: ' Schalten auf Kamera 1 Call Control_pwr_cam1(aus) Consol_outstring = "OK" + "{013}{010}" Control_runningmode = Mode_manuell ' Aufgrund manuellem Eingriff wir temporär auf manuellen Betriebmodus geschaltet Mode_led = Led_aus ' Status für Betriebsart anpassen Case Ein : ' Schalten Auf Kamera 2 Call Control_pwr_cam1(ein) Consol_outstring = "OK" + "{013}{010}" Control_runningmode = Mode_manuell ' Aufgrund manuellem Eingriff wir temporär auf manuellen Betriebmodus geschaltet Mode_led = Led_aus ' Status für Betriebsart anpassen Case Else: ' Fehler Consol_outstring = "NOK" + "{013}{010}" End Select ' Kommando SETSOURCE Case "SETPWRCAM2" : Select Case Consol_parameter_word Case Aus: ' Schalten auf Kamera 1 Call Control_pwr_cam2(aus) Consol_outstring = "OK" + "{013}{010}" Control_runningmode = Mode_manuell ' Aufgrund manuellem Eingriff wir temporär auf manuellen Betriebmodus geschaltet Mode_led = Led_aus ' Status für Betriebsart anpassen Case Ein : ' Schalten Auf Kamera 2 Call Control_pwr_cam2(ein) Consol_outstring = "OK" + "{013}{010}" Control_runningmode = Mode_manuell ' Aufgrund manuellem Eingriff wir temporär auf manuellen Betriebmodus geschaltet Mode_led = Led_aus ' Status für Betriebsart anpassen Case Else: ' Fehler Consol_outstring = "NOK" + "{013}{010}" End Select ' Kommando SETSOURCE Case "SETRELAIS" : Select Case Consol_parameter_word Case Relais_aus: Relais = Relais_aus Relais_status_flag = Relais_aus Consol_outstring = "OK" + "{013}{010}" Case Relais_ein: Relais = Relais_ein Relais_status_flag = Relais_ein Consol_outstring = "OK" + "{013}{010}" Case Else: Consol_outstring = "NOK" + "{013}{010}" End Select Case Else: Lresult = False ' Nix dabei -> Fehlerflag setzen End Select End If ' Kommando mit nur einem Parameter End If ' Kommando mit MAC-Adresse End If ' Kommando mit IP-Adresse End If ' Kommando ohne Parameter ' Im Fehlerfall Rückgabestring setzen If Lresult = False Then Consol_outstring = "NOK" + "{013}{010}" End If ' Endergebnis als Rückgabewert der Funktion übergeben Consol_process_command = Lresult End Function '-- End Consol_process_command ------------------------------------------------ ' ********* ' * LIGHT * ' ********* '------------------------------------------------------------------------------ ' LIGHT - Function: Light_measurement ' ' Funktion liefert den vom ADC ermittelten Wert zurück. ' Die Messungen wurde in eine eigene Funktion verpackt um spätere Rechnungen ' oder Nrmierungen direkt auf dem Rohwert durchführen zu können. ' Aktuell wird der ADC-Wert direkt durchgereicht. ' ' Parameter: keiner ' Rückgabewert: ADC-Wert in Word-Variable ' ' Globale Variablen: ' keine '------------------------------------------------------------------------------ Function Light_measurement() As Byte ' ----- lokale Variablen ----- Local Ltemp_word As Word ' ----- Programmcode ----- ' ggf. Traces ausgeben #if Light_trace Print "Enter Light_measurement" #endif ' Die Spannungsversorgung für den ADC einschalten und den ADC starten ' Start Adc ' Single-Shot für ADC-Wert (Licht sampeln) Ltemp_word = Getadc(light_channel) ' Mit STOP ADC kann die Spannung abgeschaltet und der ADC gestopped werden ' Stop Adc ' ggf. Traces ausgeben #if Light_trace Print "Lichtwert = " ; Ltemp_word ; " -- " ; Bin(ltemp_word) #endif ' Messwert in Rückgabewert übergeben Light_measurement = Ltemp_word End Function '-- End Light_measurement ----------------------------------------------------- '****************************************************************************** ' Gosub-Subroutinen '****************************************************************************** ' *********** ' * EEPROM * ' *********** '------------------------------------------------------------------------------ ' EE-Gosubroutine: Ee_init_internal_eeprom ' ' Subroutine überprüft die Datenkonsitenz aufgrund des verwendeten Versions- ' Index und führt ggf. eine Grundinitialisierung der Datenstrukturen durch. ' ' Parameter: keine ' Rückgabe: keine ' ' Globale Variablen: ' Die Gosubroutine verwendet sehr viele globale Variablen die hier nicht ' einzeln aufgeführt werden. '------------------------------------------------------------------------------ Ee_init_internal_eeprom: ' ----- Programmcode ----- ' Wenn Konstante gesetzt Trace Output schreiben #if Eeprom_testmodus ' Trace Print "Enter Ee_init_internal_eeprom" #endif ' Trace ' Zur Vollständigkeit hier nochmals die Datenstruktur der internen Daten: ' ======================================================================= ' Dim Ee_data_version_intern As Eram Byte At &H0000 ' Speicherstelle für Datenversion ' Dim Ee_data_dhcp As Eram Byte At &H0001 ' Einstellung ob DHCP verwendet wird oder nicht ' Dim Ee_data_ip_adr_1 As Eram Byte At &H0002 ' Byte 1 der fest eingestellten eigenen IP-Adresse ' Dim Ee_data_ip_adr_2 As Eram Byte At &H0003 ' Byte 2 der fest eingestellten eigenen IP-Adresse ' Dim Ee_data_ip_adr_3 As Eram Byte At &H0004 ' Byte 3 der fest eingestellten eigenen IP-Adresse ' Dim Ee_data_ip_adr_4 As Eram Byte At &H0005 ' Byte 4 der fest eingestellten eigenen IP-Adresse ' Dim Ee_data_submask_1 As Eram Byte At &H0006 ' Byte 1 der Subnetzmaske ' Dim Ee_data_submask_2 As Eram Byte At &H0007 ' Byte 2 der Subnetzmaske ' Dim Ee_data_submask_3 As Eram Byte At &H0008 ' Byte 3 der Subnetzmaske ' Dim Ee_data_submask_4 As Eram Byte At &H0009 ' Byte 4 der Subnetzmaske ' Dim Ee_data_gateway_1 As Eram Byte At &H000A ' Byte 1 der IP-Adresse des Routers ' Dim Ee_data_gateway_2 As Eram Byte At &H000B ' Byte 2 der IP-Adresse des Routers ' Dim Ee_data_gateway_3 As Eram Byte At &H000C ' Byte 3 der IP-Adresse des Routers ' Dim Ee_data_gateway_4 As Eram Byte At &H000D ' Byte 4 der IP-Adresse des Routers ' Dim Ee_data_mac_1 As Eram Byte At &H000E ' Byte 1 der eigenen MAC-Adresse ' Dim Ee_data_mac_2 As Eram Byte At &H000F ' Byte 2 der eigenen MAC-Adresse ' Dim Ee_data_mac_3 As Eram Byte At &H0010 ' Byte 3 der eigenen MAC-Adresse ' Dim Ee_data_mac_4 As Eram Byte At &H0011 ' Byte 4 der eigenen MAC-Adresse ' Dim Ee_data_mac_5 As Eram Byte At &H0012 ' Byte 5 der eigenen MAC-Adresse ' Dim Ee_data_mac_6 As Eram Byte At &H0013 ' Byte 6 der eigenen MAC-Adresse ' Dim Ee_data_mac_router_1 As Eram Byte At &H0014 ' Byte 1 der Router MAC-Adresse ' Dim Ee_data_mac_router_2 As Eram Byte At &H0015 ' Byte 2 der Router MAC-Adresse ' Dim Ee_data_mac_router_3 As Eram Byte At &H0016 ' Byte 3 der Router MAC-Adresse ' Dim Ee_data_mac_router_4 As Eram Byte At &H0017 ' Byte 4 der Router MAC-Adresse ' Dim Ee_data_mac_router_5 As Eram Byte At &H0018 ' Byte 5 der Router MAC-Adresse ' Dim Ee_data_mac_router_6 As Eram Byte At &H0019 ' Byte 6 der Router MAC-Adresse ' Dim Ee_data_ntp_1 As Eram Byte At &H001A ' Byte 1 der IP-Adresse des NTP-Servers ' Dim Ee_data_ntp_2 As Eram Byte At &H001B ' Byte 2 der IP-Adresse des NTP-Servers ' Dim Ee_data_ntp_3 As Eram Byte At &H001C ' Byte 3 der IP-Adresse des NTP-Servers ' Dim Ee_data_ntp_4 As Eram Byte At &H001D ' Byte 4 der IP-Adresse des NTP-Servers ' Dim Ee_data_port As Eram Word At &H001E ' Eigene TCP Portnummer für Kommunikations ' Dim Ee_data_runningmode As Eram Byte At &H0020 ' Einstellung für den Betriebsmodus ' Dim Ee_data_irhelligkeit As Eram Byte At &H0021 ' PWM Einstellung für Helligkeit IR Hintergrundbeleuchtung ' Dim Ee_data_ldr_lower As Eram Word At &H0022 ' Einstellung für die untere Helligkeitsgrenze ' Dim Ee_data_ldr_upper As Eram Word At &H0024 ' Einstellung für die untere Helligkeitsgrenze ' Dim Ee_data_videotimer As Eram Word At &H0026 ' Schaltzeit in Sekunden in der zwischen Videoquelle 1 und 2 hin- und hergeschaltet wird. ' Aktuelle Datenversion des internen EEPROM lesen Temp_byte_1 = Ee_data_version_intern ' Ist die Datenversion korrekt If Temp_byte_1 <> Akt_internal_ee_version Then ' NEIN, Datenstruktur ist nicht aktuell und Defaultwerte müssen neu geladen werden ' Wenn Konstante gesetzt Trace Output schreiben #if Eeprom_testmodus ' Trace Print "Ee_init_internal_eeprom: Datenversion intern stimmt nicht" Print "Ee_init_internal_eeprom: Initialisiere internes EEPROM neu!" #endif ' Trace ' Datenstruktur internes EEPROM entspricht nicht dem aktuellen Stand ' => Datenstruktur neu anlegen bzw. neue Defaultwerte setzen. ' Aktuele Datenversion laden Ee_data_version_intern = Akt_internal_ee_version ' Defaultwerte in EEPROM schreiben Gosub Ee_write_default_eeprom End If ' Datenversion? ' ----- Übergabe der Daten in globale Arbeitsvariablen ----- ' DHCP-Flag setzen Enc28j60_dhcp_flag = Ee_data_dhcp ' Prüfen ob DHCP verwendet werden soll If Enc28j60_dhcp_flag = Dhcp_aus Then ' NEIN, DHCP soll nicht verwendet werden ' Eigene IP-Adresse laden Enc28j60_my_ip_adress(1) = Ee_data_ip_adr_1 Enc28j60_my_ip_adress(2) = Ee_data_ip_adr_2 Enc28j60_my_ip_adress(3) = Ee_data_ip_adr_3 Enc28j60_my_ip_adress(4) = Ee_data_ip_adr_4 ' Subnetzmaske laden Enc28j60_subnetmask(1) = Ee_data_submask_1 Enc28j60_subnetmask(2) = Ee_data_submask_2 Enc28j60_subnetmask(3) = Ee_data_submask_3 Enc28j60_subnetmask(4) = Ee_data_submask_4 ' Router-MAC-Adresse laden Enc28j60_router_mac_adress(1) = Ee_data_mac_router_1 Enc28j60_router_mac_adress(2) = Ee_data_mac_router_2 Enc28j60_router_mac_adress(3) = Ee_data_mac_router_3 Enc28j60_router_mac_adress(4) = Ee_data_mac_router_4 Enc28j60_router_mac_adress(5) = Ee_data_mac_router_5 Enc28j60_router_mac_adress(6) = Ee_data_mac_router_6 Else ' JA, DHCP soll verwendet werden ' Eigene IP-Adresse zunächst mit NULL vorbelegen da Zuteilung über DHCP Enc28j60_my_ip = 0 ' Subnetzmaske zunächst mit NULL vorbelegen da Zuteilung über DHCP Enc28j60_submask = 0 ' Router-MAC-Adresse zunächst mit NULL vorbelegen da Zuteilung über DHCP Enc28j60_router_mac_adress(1) = 0 Enc28j60_router_mac_adress(2) = 0 Enc28j60_router_mac_adress(3) = 0 Enc28j60_router_mac_adress(4) = 0 Enc28j60_router_mac_adress(5) = 0 Enc28j60_router_mac_adress(6) = 0 End If ' Gatewayadresse laden Enc28j60_gateway_ip_adress(1) = Ee_data_gateway_1 Enc28j60_gateway_ip_adress(2) = Ee_data_gateway_2 Enc28j60_gateway_ip_adress(3) = Ee_data_gateway_3 Enc28j60_gateway_ip_adress(4) = Ee_data_gateway_4 ' Eigene MAC-Adresse laden Enc28j60_my_mac_adress(1) = Ee_data_mac_1 Enc28j60_my_mac_adress(2) = Ee_data_mac_2 Enc28j60_my_mac_adress(3) = Ee_data_mac_3 Enc28j60_my_mac_adress(4) = Ee_data_mac_4 Enc28j60_my_mac_adress(5) = Ee_data_mac_5 Enc28j60_my_mac_adress(6) = Ee_data_mac_6 ' IP-Adresse für Zeitserver laden Enc28j60_ntp_ip_adress(1) = Ee_data_ntp_1 Enc28j60_ntp_ip_adress(2) = Ee_data_ntp_2 Enc28j60_ntp_ip_adress(3) = Ee_data_ntp_3 Enc28j60_ntp_ip_adress(4) = Ee_data_ntp_4 ' TCP-Portnummer laden Enc28j60_tcp_port = Ee_data_port ' Arbeitsvariablen für Zentralsteuerung laden Control_runningmode = Ee_data_runningmode ' Betriebsmodus Control_irhelligkeit = Ee_data_irhelligkeit ' PWM-Wert IR Hintergrundbeleuchtung Control_ldr_lower = Ee_data_ldr_lower ' untere Helligkeitsgrenze Control_ldr_upper = Ee_data_ldr_upper ' obere Helligkeitsgrenze Control_videotimer = Ee_data_videotimer ' Schaltzeit Timer ' Gelesene Daten auf Plausibilität prüfen ' Bemerkung: ' Auf die Prüfung der gelesenen Daten und die Werte in den Variablen wird hier zunächst verzichtet. ' Es wird davon ausgegangen dass korrekte Werte im EEPROM stehen und dass eine Plausibilitätsprüfung ' in den Kommunikationsroutinen mit der Zentralsteuerung erfolgt. ' Wenn Konstante gesetzt Trace Output schreiben #if Eeprom_testmodus ' Trace Print "Ee_init_internal_eeprom: Setting-Daten internes EEPROM:" ' Wert 01 Temp_byte_1 = Ee_data_version_intern Print "Version Datenstruktur : " ; Hex(temp_byte_1) ' Wert 02 Print "DHCP-Flag : " ; Hex(enc28j60_dhcp_flag) ' Wert 03 Print "Eigene IP-Adresse : " ; Enc28j60_my_ip_adress(1) ; "." ; Enc28j60_my_ip_adress(2) ; "." ; Enc28j60_my_ip_adress(3) ; "." ; Enc28j60_my_ip_adress(4) ' Wert 04 Print "Subnetzmaske : " ; Enc28j60_subnetmask(1) ; "." ; Enc28j60_subnetmask(2) ; "." ; Enc28j60_subnetmask(3) ; "." ; Enc28j60_subnetmask(4) ' Wert 05 Print "IP-Adresse Gateway/Router : " ; Enc28j60_gateway_ip_adress(1) ; "." ; Enc28j60_gateway_ip_adress(2) ; "." ; Enc28j60_gateway_ip_adress(3) ; "." ; Enc28j60_gateway_ip_adress(4) ' Wert 06 Print "Eigene MAC-Adresse : " ; Hex(enc28j60_my_mac_adress(1)) ; ":" ; Hex(enc28j60_my_mac_adress(2)) ; ":" ; Hex(enc28j60_my_mac_adress(3)) ; ":" ; Hex(enc28j60_my_mac_adress(4)) ; ":" ; Hex(enc28j60_my_mac_adress(5)) ; ":" ; Hex(enc28j60_my_mac_adress(6)) ' Wert 07 Print "MAC-Adresse Gateway/Router : " ; Hex(enc28j60_router_mac_adress(1)) ; ":" ; Hex(enc28j60_router_mac_adress(2)) ; ":" ; Hex(enc28j60_router_mac_adress(3)) ; ":" ; Hex(enc28j60_router_mac_adress(4)) ; ":" ; Hex(enc28j60_router_mac_adress(5)) ; ":" ; Hex(enc28j60_router_mac_adress(6)) ' Wert 08 Print "IP-Adresse Zeitserver : " ; Enc28j60_ntp_ip_adress(1) ; "." ; Enc28j60_ntp_ip_adress(2) ; "." ; Enc28j60_ntp_ip_adress(3) ; "." ; Enc28j60_ntp_ip_adress(4) ' Wert 09 Print "TCP-Port : " ; Enc28j60_tcp_port ' Wert 10 Print "Betriebsmodus : " ; Hex(control_runningmode) ' Wert 11 Print "PWM IR-Hintergrund : " ; Control_irhelligkeit ' Wert 12 Print "Untere Helligkeitsgrenze : " ; Control_ldr_lower ' Wert 13 Print "Obere Helligkeitsgrenze : " ; Control_ldr_upper ' Wert 14 Print "Schaltzeit Timer : " ; Control_videotimer #endif ' Trace Return '-- End Ee_init_internal_eeprom ----------------------------------------------- '------------------------------------------------------------------------------ ' EE-Gosubroutine: Ee_write_default_eeprom ' ' Subroutine übertrag die Defaultwerte ohne Prüfung hart in das EEPROM ' ' Parameter: keine ' Rückgabe: keine ' ' Globale Variablen: ' Die Gosubroutine verwendet sehr viele globale Variablen die hier nicht ' einzeln aufgeführt werden. '------------------------------------------------------------------------------ Ee_write_default_eeprom: ' ----- Programmcode ----- ' Wenn Konstante gesetzt Trace Output schreiben #if Eeprom_testmodus ' Trace Print "Enter Ee_write_default_eeprom" #endif ' Trace ' Zur Vollständigkeit hier nochmals die Datenstruktur der internen Daten: ' ======================================================================= ' Dim Ee_data_version_intern As Eram Byte At &H0000 ' Speicherstelle für Datenversion ' Dim Ee_data_dhcp As Eram Byte At &H0001 ' Einstellung ob DHCP verwendet wird oder nicht ' Dim Ee_data_ip_adr_1 As Eram Byte At &H0002 ' Byte 1 der fest eingestellten eigenen IP-Adresse ' Dim Ee_data_ip_adr_2 As Eram Byte At &H0003 ' Byte 2 der fest eingestellten eigenen IP-Adresse ' Dim Ee_data_ip_adr_3 As Eram Byte At &H0004 ' Byte 3 der fest eingestellten eigenen IP-Adresse ' Dim Ee_data_ip_adr_4 As Eram Byte At &H0005 ' Byte 4 der fest eingestellten eigenen IP-Adresse ' Dim Ee_data_submask_1 As Eram Byte At &H0006 ' Byte 1 der Subnetzmaske ' Dim Ee_data_submask_2 As Eram Byte At &H0007 ' Byte 2 der Subnetzmaske ' Dim Ee_data_submask_3 As Eram Byte At &H0008 ' Byte 3 der Subnetzmaske ' Dim Ee_data_submask_4 As Eram Byte At &H0009 ' Byte 4 der Subnetzmaske ' Dim Ee_data_gateway_1 As Eram Byte At &H000A ' Byte 1 der IP-Adresse des Routers ' Dim Ee_data_gateway_2 As Eram Byte At &H000B ' Byte 2 der IP-Adresse des Routers ' Dim Ee_data_gateway_3 As Eram Byte At &H000C ' Byte 3 der IP-Adresse des Routers ' Dim Ee_data_gateway_4 As Eram Byte At &H000D ' Byte 4 der IP-Adresse des Routers ' Dim Ee_data_mac_1 As Eram Byte At &H000E ' Byte 1 der eigenen MAC-Adresse ' Dim Ee_data_mac_2 As Eram Byte At &H000F ' Byte 2 der eigenen MAC-Adresse ' Dim Ee_data_mac_3 As Eram Byte At &H0010 ' Byte 3 der eigenen MAC-Adresse ' Dim Ee_data_mac_4 As Eram Byte At &H0011 ' Byte 4 der eigenen MAC-Adresse ' Dim Ee_data_mac_5 As Eram Byte At &H0012 ' Byte 5 der eigenen MAC-Adresse ' Dim Ee_data_mac_6 As Eram Byte At &H0013 ' Byte 6 der eigenen MAC-Adresse ' Dim Ee_data_mac_router_1 As Eram Byte At &H0014 ' Byte 1 der Router MAC-Adresse ' Dim Ee_data_mac_router_2 As Eram Byte At &H0015 ' Byte 2 der Router MAC-Adresse ' Dim Ee_data_mac_router_3 As Eram Byte At &H0016 ' Byte 3 der Router MAC-Adresse ' Dim Ee_data_mac_router_4 As Eram Byte At &H0017 ' Byte 4 der Router MAC-Adresse ' Dim Ee_data_mac_router_5 As Eram Byte At &H0018 ' Byte 5 der Router MAC-Adresse ' Dim Ee_data_mac_router_6 As Eram Byte At &H0019 ' Byte 6 der Router MAC-Adresse ' Dim Ee_data_ntp_1 As Eram Byte At &H001A ' Byte 1 der IP-Adresse des NTP-Servers ' Dim Ee_data_ntp_2 As Eram Byte At &H001B ' Byte 2 der IP-Adresse des NTP-Servers ' Dim Ee_data_ntp_3 As Eram Byte At &H001C ' Byte 3 der IP-Adresse des NTP-Servers ' Dim Ee_data_ntp_4 As Eram Byte At &H001D ' Byte 4 der IP-Adresse des NTP-Servers ' Dim Ee_data_port As Eram Word At &H001E ' Eigene TCP Portnummer für Kommunikations ' Dim Ee_data_runningmode As Eram Byte At &H0020 ' Einstellung für den Betriebsmodus ' Dim Ee_data_irhelligkeit As Eram Byte At &H0021 ' PWM Einstellung für Helligkeit IR Hintergrundbeleuchtung ' Dim Ee_data_ldr_lower As Eram Word At &H0022 ' Einstellung für die untere Helligkeitsgrenze ' Dim Ee_data_ldr_upper As Eram Word At &H0024 ' Einstellung für die untere Helligkeitsgrenze ' Dim Ee_data_videotimer As Eram Word At &H0026 ' Schaltzeit in Sekunden in der zwischen Videoquelle 1 und 2 hin- und hergeschaltet wird. ' Defaultwert für DHCP laden Ee_data_dhcp = Default_data_dhcp ' Defaultwert für eigene IP laden Ee_data_ip_adr_1 = Default_data_ip_adr_1 Ee_data_ip_adr_2 = Default_data_ip_adr_2 Ee_data_ip_adr_3 = Default_data_ip_adr_3 Ee_data_ip_adr_4 = Default_data_ip_adr_4 ' Defaultwert für Subnetzmaske laden Ee_data_submask_1 = Default_data_submask_1 Ee_data_submask_2 = Default_data_submask_2 Ee_data_submask_3 = Default_data_submask_3 Ee_data_submask_4 = Default_data_submask_4 ' Defaultwert für Gateway-Adresse laden Ee_data_gateway_1 = Default_data_gateway_1 Ee_data_gateway_2 = Default_data_gateway_2 Ee_data_gateway_3 = Default_data_gateway_3 Ee_data_gateway_4 = Default_data_gateway_4 ' Defaultwert für eigene MAC-Adresse laden Ee_data_mac_1 = Default_data_mac_1 Ee_data_mac_2 = Default_data_mac_2 Ee_data_mac_3 = Default_data_mac_3 Ee_data_mac_4 = Default_data_mac_4 Ee_data_mac_5 = Default_data_mac_5 Ee_data_mac_6 = Default_data_mac_6 ' Defaultwert für MAC-Adresse des Routers laden Ee_data_mac_router_1 = Default_data_mac_router_1 Ee_data_mac_router_2 = Default_data_mac_router_2 Ee_data_mac_router_3 = Default_data_mac_router_3 Ee_data_mac_router_4 = Default_data_mac_router_4 Ee_data_mac_router_5 = Default_data_mac_router_5 Ee_data_mac_router_6 = Default_data_mac_router_6 ' Defaultwert für IP-Adresse Zeitserver laden Ee_data_ntp_1 = Default_data_ntp_1 Ee_data_ntp_2 = Default_data_ntp_2 Ee_data_ntp_3 = Default_data_ntp_3 Ee_data_ntp_4 = Default_data_ntp_4 ' Defaultwert für TCP-Portadresse laden Ee_data_port = Default_data_port ' Defaultwert für Betriebsmodus laden Ee_data_runningmode = Default_data_runningmode ' Defaultwert für PWM-Wert IR-Helligkeit laden Ee_data_irhelligkeit = Default_data_irhelligkeit ' Defaultwert für Grenzhelligkeiten laden Ee_data_ldr_lower = Default_data_ldr_lower ' Untere Grenze Ee_data_ldr_upper = Default_data_ldr_upper ' Obere Grenze ' Defaultwert für Timerintervall laden Ee_data_videotimer = Default_data_videotimer Return '-- End Ee_write_default_eeprom ----------------------------------------------- ' ************ ' * ENC28J60 * ' ************ '------------------------------------------------------------------------------ ' EE-Gosubroutine: Enc28j60_print_konfig ' ' Routine gibt die folgenden Betriebsdaten auf RS232-Schnittstelle aus: ' - eigene IP-Adresse ' - eigene MAC-Adresse ' - Subnetzmaske ' - Router-IP-Adresse ' - TCP-Port ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' Die Gosubroutine verwendet sehr viele globale Variablen die hier nicht ' einzeln aufgeführt werden. '------------------------------------------------------------------------------ Enc28j60_print_konfig: ' ----- Programmcode ----- Print "Eigene IP-Adresse : " ; Enc28j60_my_ip_adress(1) ; "." ; Enc28j60_my_ip_adress(2) ; "." ; Enc28j60_my_ip_adress(3) ; "." ; Enc28j60_my_ip_adress(4) Print "Eigene MAC-Adresse : " ; Hex(enc28j60_my_mac_adress(1)) ; ":" ; Hex(enc28j60_my_mac_adress(2)) ; ":" ; Hex(enc28j60_my_mac_adress(3)) ; ":" ; Hex(enc28j60_my_mac_adress(4)) ; ":" ; Hex(enc28j60_my_mac_adress(5)) ; ":" ; Hex(enc28j60_my_mac_adress(6)) Print "Subnetzmaske : " ; Enc28j60_subnetmask(1) ; "." ; Enc28j60_subnetmask(2) ; "." ; Enc28j60_subnetmask(3) ; "." ; Enc28j60_subnetmask(4) Print "IP-Adresse Router : " ; Enc28j60_gateway_ip_adress(1) ; "." ; Enc28j60_gateway_ip_adress(2) ; "." ; Enc28j60_gateway_ip_adress(3) ; "." ; Enc28j60_gateway_ip_adress(4) Print "MAC-Adresse Router : " ; Hex(enc28j60_router_mac_adress(1)) ; ":" ; Hex(enc28j60_router_mac_adress(2)) ; ":" ; Hex(enc28j60_router_mac_adress(3)) ; ":" ; Hex(enc28j60_router_mac_adress(4)) ; ":" ; Hex(enc28j60_router_mac_adress(5)) ; ":" ; Hex(enc28j60_router_mac_adress(6)) Print "NTP-Adresse : " ; Enc28j60_ntp_ip_adress(1) ; "." ; Enc28j60_ntp_ip_adress(2) ; "." ; Enc28j60_ntp_ip_adress(3) ; "." ; Enc28j60_ntp_ip_adress(4) Print "TCP-Port : " ; Enc28j60_tcp_port Return '-- End Enc28j60_print_konfig ----------------------------------------------- ' ***************************** ' * IR Hintergrundbeleuchtung * ' ***************************** '------------------------------------------------------------------------------ ' IR - Gosub-Routine: Ir_konfig ' ' Subroutine zur Konfiguration des Ir-Display inkl. der dafür ' notwendigen Timer. ' ' Parameter: keiner ' Rückgabe: keiner ' ' Globale Variable: ' Control_irhelligkeit = globale Variable für Helligkeitswert '------------------------------------------------------------------------------ Ir_konfig: ' ----- Programmcode ----- #if Ir_testmodus Print "Enter Ir_konfig" #endif ' ----- Konfiguration IR-Helligkeit (PWM) ----- ' Variable für Helligkeit in Timerregister laden Ocr2 = Control_irhelligkeit 'Port D.7 ist Timer-Ausgang OC2 Config Pind.3 = Output Return '-- End Ir_konfig ------------------------------------------------------------- '------------------------------------------------------------------------------ ' IR - Gosub-Routine: Ir_beleuchtung_an ' ' Routine schaltet die Beleuchtung ein ' ' Parameter: keiner ' Rückgabe: keiner ' ' Globale Variable: ' Control_irhelligkeit = globale Variable für Helligkeitswert '------------------------------------------------------------------------------ Ir_beleuchtung_an: ' ##MaFu## ' Wenn System soweit funktioniert besteht noch die Möglichkeit, hier die PWM ' sauber ein- und auszuschalten. Aktuell wird PWM durch entsprechenden Wert ' eingeschaltet. Eine Saubere Einschaltung wäre den Timer zu aktivieren ' und Ausgang OC2 zu konfigurieren. ' Umsetzung eventuell so .... Achtung, ungetestet!!! ' Enable Timer2 ' Set Ir_gpio ' Noch zu prüfen ist ob PIN als Output konfiguriert werden muss bzw. wie sich ' Konfiguration auf Betrieb mit PWM auswirkt. ' ----- Programmcode ----- #if Ir_testmodus Print "Enter Ir_beleuchtung_an" #endif ' PWM-Wert in Timerregister laden Ocr2 = Control_irhelligkeit ' Globales Statusflag setzen Ir_status_flag = Ein ' LED einschalten Ir_led = Led_ein Return '-- End Ir_beleuchtung_an ----------------------------------------------------- '------------------------------------------------------------------------------ ' IR - Gosub-Routine: Ir_beleuchtung_aus ' ' Routine schaltet die Beleuchtung aus ' ' Parameter: keiner ' Rückgabe: keiner ' ' Globale Variable: ' Control_irhelligkeit = globale Variable für Helligkeitswert '------------------------------------------------------------------------------ Ir_beleuchtung_aus: ' ##MaFu## ' Wenn System soweit funktioniert besteht noch die Möglichkeit, hier die PWM ' sauber ein- und auszuschalten. Aktuell wird PWM durch entsprechenden Wert ' abgeschaltet. Eine Saubere Abschaltung wäre den Timer zu deaktivieren und ' Ausgang explizit auf Ausgang = 0 zu programmieren. ' Umsetzung eventuell so .... Achtung, ungetestet!!! ' Disable Timer2 ' Reset Ir_gpio ' Noch zu prüfen ist ob PIN als Output konfiguriert werden muss bzw. wie sich ' Konfiguration auf Betrieb mit PWM auswirkt. ' ----- Programmcode ----- #if Ir_testmodus Print "Enter Ir_beleuchtung_aus" #endif ' PWM-Wert in Timerregister laden Ocr2 = Ir_helligkeit_aus ' Globales Statusflag setzen Ir_status_flag = Aus ' LED einschalten Ir_led = Led_aus Return '-- End Ir_beleuchtung_aus ---------------------------------------------------- ' *********** ' * Console * ' *********** '------------------------------------------------------------------------------ ' Consol: Consol_poll ' ' Routine dient zum Einlesen von Konsolenkommandos via RS232 und ggf. zur ' Verarbeitung derselbigen ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' Consol_char_flag = Flag ob Zeichen im RS232-Buffer wartet ' Consol_inchar = Ausgelesenes einzelnes Zeichen ' Consol_instring = Eingabe-String ' Consol_outstring = Ausgabe-String '------------------------------------------------------------------------------ Consol_poll: ' ----- Programmcode ----- ' Prüfen ob ein Zeichen im UART Eingangsbuffer wartet Consol_char_flag = Ischarwaiting() If Consol_char_flag = 1 Then ' JA, es wartet ein Zeichen im Empfangsbuffer ' Einleseschleife Do ' Ein Zeichen vom Buffer einlesen. Ist kein Zeichen mehr vorhanden liefert Inkey = 0 Consol_inchar = Inkey() ' Prüfen ob es sich bei dem eingelesenen Zeichen um ein gültiges Zeichen handelt? ' ==> Steuerzeichen werden nicht im String verarbeitet If Consol_inchar > &H1F Then ' JA, das Zeichen ist ein gültiges Zeichen ' Zeichen zur Eingabe via RS232 Echo'n damit Benutzer Eingabe auch erkennen kann Print Chr(consol_inchar) ; ' Eingabestring zusammensetzen und eingelesenes Zeichen hinten anhängen Consol_instring = Consol_instring + Chr(consol_inchar) Else ' NEIN, das Zeichen ist kein gültiges Zeichen ' Prüfen ob RETURN betätigt wurde. If Consol_inchar = &H0D Then ' JA, es wurde RETURN betätigt, damit ist Stringeingabe fertig und die Verarbeitung kann beginnen. ' Stringeingabe abschließen Print ' Eingegebener String komplett in Grossbuchstaben wandeln Consol_instring = Ucase(consol_instring) ' Führende Leerzeichen entfernen Consol_instring = Ltrim(consol_instring) ' Nachfolgende Leerzeichen entfernen Consol_instring = Rtrim(consol_instring) ' Stringeingabe bearbeiten und String parsen. ' Rückgabewert enthält boolsche Variable ob Verarbeitung erfolgreich war oder Fehler aufgetreten ist. ' Entsprechende Rückgaben und Meldungen werden im globalen string Console_outstring von der Funktion zurückgegeben. Temp_byte_1 = Consol_process_command(consol_instring , Source_rs232) ' Eingabestring für erneute Eingabe vorbereiten und zurücksetzen Consol_instring = "" ' Ggf. Rückgabeparameter auswerten und Rückgabestring hier zu Testzwecken erneut ausgeben #if Consol_trace If Temp_byte_1 = True Then Print "** OK" Else Print "**NOK" End If #endif ' Ausgabe des Ergebnisstrings Print Consol_outstring End If ' Zeichenprüfung auf Return End If ' Zeichenprüfung auf valides Zeichen Loop Until Consol_inchar = 0 ' Einleseschleife solange Zeichen noch im Buffer End If ' Es wartete ein Zeichen Return '-- End Consol_poll ----------------------------------------------------------- '------------------------------------------------------------------------------ ' Consol-Gosubroutine: Consol_print_konfig ' ' Routine gibt die folgenden Betriebsdaten auf RS232-Schnittstelle aus: ' - Betriebsmodus ' - PWM für Hintergrundbeleuchtung ' - obere Helligkeitsgrenze ' - untere Helligkeitsgrenze ' - Schaltzeit Timer ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' Die Gosubroutine verwendet sehr viele globale Variablen die hier nicht ' einzeln aufgeführt werden. '------------------------------------------------------------------------------ Consol_print_konfig: ' ----- Programmcode ----- Print "--------------------" Print "Betriebsmodus : " ; Select Case Control_runningmode Case Mode_manuell : Print "Manuell" Case Mode_zeit : Print "Zeit" Case Mode_licht : Print "Licht" End Select Print "PWM IR-Hintergrund : " ; Control_irhelligkeit Print "IR-Hintergrund : " ; Select Case Ir_status_flag Case Ein : Print "eingeschaltet" Case Aus : Print "ausgeschaltet" End Select Print "Helligkeit Oben : " ; Control_ldr_upper Print "Helligkeit Unten : " ; Control_ldr_lower Print "Schaltzeit Timer : " ; Control_videotimer Print "--------------------" Print "Aktive Kamera : " ; Select Case Control_kamera_flag Case Kamera_1 : Print "Kamera 1" Case Kamera_2 : Print "Kamera 2" End Select Print "Spannung Kamera 1 : " ; Select Case Control_kamera1_pwr_flag Case Aus : Print "ausgeschaltet" Case Ein : Print "eingeschaltet" End Select Print "Spannung Kamera 2 : " ; Select Case Control_kamera2_pwr_flag Case Aus : Print "ausgeschaltet" Case Ein : Print "eingeschaltet" End Select Print "Umschaltzeit : " ; Switch_delay Print "--------------------" Print "Aktueller LDR-Wert : " ; Light_value Print "Relaisstatus : " ; Select Case Relais_status_flag Case Relais_aus : Print "ausgeschaltet" Case Relais_ein : Print "eingeschaltet" End Select Print "DHCP Status : " ; Select Case Enc28j60_dhcp_flag Case Dhcp_aus : Print "ausgeschaltet" Case Dhcp_ein : Print "eingeschaltet" End Select Print Return '-- End Consol_print_konfig --------------------------------------------------- '------------------------------------------------------------------------------ ' Consol-Gosubroutine: Consol_print_help ' ' Routine gibt Hilfstext für alle möglichen Kommandos aus ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' Consol_instring und Consol_outstring weden al temporäre Arbeitsvariablen ' missbraucht!! ' Ansonsten wir die Datenstruktur Hilfstext benötigt '------------------------------------------------------------------------------ Consol_print_help: ' ----- Programmcode ----- ' Hilfstext aus DATA-Speicher auslesen und auf RS232 ausgeben Restore Hilfstext ' Lesepointer initialisieren Do ' Endlosschleife Read Consol_outstring ' String auslesen. Bei jedem Lesen sprint Pointer ein DATA-Feld weiter Consol_instring = Right(consol_outstring , 8) ' 8 Zeichen von Rechts in Arbeitsvariable kopieren ' Prüfen ob Datenende erreicht If Consol_instring = "endblock" Then ' JA Exit Do ' Schleife verlassen End If 'Datenende Print Consol_outstring ; Loop Consol_instring = "" Consol_outstring = "" Return '-- End Consol_print_help ----------------------------------------------------- '------------------------------------------------------------------------------ ' Consol-Gosubroutine: Consol_tcp_text_output ' ' Routine befüllt den Sendebuffer mit entsprechenden Status und Hilfstexten. ' Die Steuerung erfolt über die globalen Variablen. ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' Com_array() = Sende und Empfangsbuffer ' Consol_tcp_multipartflag = Steuerung der Sequence selbst ' Consol_tcp_partcounter = Teilsteuerung ' Consol_tcp_sequence_nummer = Welche Sequence ' Consol_outstring = String mit 100 Zeichen als Temp-Variable '------------------------------------------------------------------------------ Consol_tcp_text_output: ' ----- Programmcode ----- ' Ggf. Traces ausgeben #if Enc28j60_tcp_output Print "Enter Consol_tcp_text_output" Print "Consol_tcp_sequence_nummer = " ; Consol_tcp_sequence_nummer Print "Start PacketLength : " ; Packetlength #endif Select Case Consol_tcp_sequence_nummer ' ===== Textsequence-Steuerung für Statusinformationen ===== Case Sequence_status: ' Ggf. Traces ausgeben #if Enc28j60_tcp_output Print "Sequence STATUS erkannt" #endif Temp_word_3 = 54 ' ----- TEIL 1 ----- Consol_outstring = "Eigene IP-Adresse : " + Str(enc28j60_my_ip_adress(1)) + "." + Str(enc28j60_my_ip_adress(2)) + "." + Str(enc28j60_my_ip_adress(3)) + "." + Str(enc28j60_my_ip_adress(4)) + "{013}{010}" Consol_outstring = Consol_outstring + "Eigene MAC-Adresse : " + Hex(enc28j60_my_mac_adress(1)) + ":" + Hex(enc28j60_my_mac_adress(2)) + ":" + Hex(enc28j60_my_mac_adress(3)) + ":" + Hex(enc28j60_my_mac_adress(4)) + ":" + Hex(enc28j60_my_mac_adress(5)) + ":" + Hex(enc28j60_my_mac_adress(6)) + "{013}{010}" ' Ggf. Traces ausgeben #if Enc28j60_tcp_output Print "String [1.1] = " ; Len(consol_outstring) #endif ' Text in Buffer kopieren (ab Position Tcp_data = 55) For Temp_word_1 = 1 To Len(consol_outstring) Temp_word_2 = Temp_word_3 + Temp_word_1 Temp_char_1 = Mid(consol_outstring , Temp_word_1 , 1) Com_array(temp_word_2) = Asc(temp_char_1) Next Temp_word_1 ' Zwischenpointer für nächsten Stringteil berechnen Temp_word_3 = Temp_word_3 + Len(consol_outstring) ' Paketlänge um Länge des String ergänzen der gerade eingeladen wurde Packetlength = Packetlength + Len(consol_outstring) ' ----- TEIL 2 ----- Consol_outstring = "Subnetzmaske : " + Str(enc28j60_subnetmask(1)) + "." + Str(enc28j60_subnetmask(2)) + "." + Str(enc28j60_subnetmask(3)) + "." + Str(enc28j60_subnetmask(4)) + "{013}{010}" Consol_outstring = Consol_outstring + "IP-Adresse Router : " + Str(enc28j60_gateway_ip_adress(1)) + "." + Str(enc28j60_gateway_ip_adress(2)) + "." + Str(enc28j60_gateway_ip_adress(3)) + "." + Str(enc28j60_gateway_ip_adress(4)) + "{013}{010}" ' Ggf. Traces ausgeben #if Enc28j60_tcp_output Print "String [1.2] = " ; Len(consol_outstring) #endif ' Text in Buffer kopieren For Temp_word_1 = 1 To Len(consol_outstring) Temp_word_2 = Temp_word_3 + Temp_word_1 Temp_char_1 = Mid(consol_outstring , Temp_word_1 , 1) Com_array(temp_word_2) = Asc(temp_char_1) Next Temp_word_1 ' Zwischenpointer für nächsten Stringteil berechnen Temp_word_3 = Temp_word_3 + Len(consol_outstring) ' Paketlänge um Länge des String ergänzen der gerade eingeladen wurde Packetlength = Packetlength + Len(consol_outstring) ' ----- TEIL 3 ----- Consol_outstring = "MAC-Adresse Router : " + Hex(enc28j60_router_mac_adress(1)) + ":" + Hex(enc28j60_router_mac_adress(2)) + ":" + Hex(enc28j60_router_mac_adress(3)) + ":" + Hex(enc28j60_router_mac_adress(4)) + ":" + Hex(enc28j60_router_mac_adress(5)) + ":" + Hex(enc28j60_router_mac_adress(6)) + "{013}{010}" Consol_outstring = Consol_outstring + "NTP-Adresse : " + Str(enc28j60_ntp_ip_adress(1)) + "." + Str(enc28j60_ntp_ip_adress(2)) + "." + Str(enc28j60_ntp_ip_adress(3)) + "." + Str(enc28j60_ntp_ip_adress(4)) + "{013}{010}" ' Ggf. Traces ausgeben #if Enc28j60_tcp_output Print "String [1.3] = " ; Len(consol_outstring) #endif ' Text in Buffer kopieren For Temp_word_1 = 1 To Len(consol_outstring) Temp_word_2 = Temp_word_3 + Temp_word_1 Temp_char_1 = Mid(consol_outstring , Temp_word_1 , 1) Com_array(temp_word_2) = Asc(temp_char_1) Next Temp_word_1 ' Zwischenpointer für nächsten Stringteil berechnen Temp_word_3 = Temp_word_3 + Len(consol_outstring) ' Paketlänge um Länge des String ergänzen der gerade eingeladen wurde Packetlength = Packetlength + Len(consol_outstring) ' ----- TEIL 4 ----- Consol_outstring = "TCP-Port : " + Str(enc28j60_tcp_port) + "{013}{010}" Consol_outstring = Consol_outstring + "--------------------" + "{013}{010}" ' Ggf. Traces ausgeben #if Enc28j60_tcp_output Print "String [1.4] = " ; Len(consol_outstring) #endif ' Text in Buffer kopieren For Temp_word_1 = 1 To Len(consol_outstring) Temp_word_2 = Temp_word_3 + Temp_word_1 Temp_char_1 = Mid(consol_outstring , Temp_word_1 , 1) Com_array(temp_word_2) = Asc(temp_char_1) Next Temp_word_1 ' Zwischenpointer für nächsten Stringteil berechnen Temp_word_3 = Temp_word_3 + Len(consol_outstring) ' Paketlänge um Länge des String ergänzen der gerade eingeladen wurde Packetlength = Packetlength + Len(consol_outstring) ' ----- TEIL 5 ----- Consol_outstring = "Betriebsmodus : " Select Case Control_runningmode Case Mode_manuell : Consol_outstring = Consol_outstring + "Manuell" + "{013}{010}" Case Mode_zeit : Consol_outstring = Consol_outstring + "Zeit" + "{013}{010}" Case Mode_licht : Consol_outstring = Consol_outstring + "Licht" + "{013}{010}" End Select Consol_outstring = Consol_outstring + "PWM IR-Hintergrund : " + Str(control_irhelligkeit) + "{013}{010}" ' Ggf. Traces ausgeben #if Enc28j60_tcp_output Print "String [1.5] = " ; Len(consol_outstring) #endif ' Text in Buffer kopieren (ab Position 55 = Tcp_data) For Temp_word_1 = 1 To Len(consol_outstring) Temp_word_2 = Temp_word_3 + Temp_word_1 Temp_char_1 = Mid(consol_outstring , Temp_word_1 , 1) Com_array(temp_word_2) = Asc(temp_char_1) Next Temp_word_1 ' Zwischenpointer für nächsten Stringteil berechnen Temp_word_3 = Temp_word_3 + Len(consol_outstring) ' Paketlänge um Länge des String ergänzen der gerade eingeladen wurde Packetlength = Packetlength + Len(consol_outstring) ' ----- TEIL 6 ----- Consol_outstring = "IR-Hintergrund : " Select Case Ir_status_flag Case Ein : Consol_outstring = Consol_outstring + "eingeschaltet" + "{013}{010}" Case Aus : Consol_outstring = Consol_outstring + "ausgeschaltet" + "{013}{010}" End Select Consol_outstring = Consol_outstring + "Helligkeit Oben : " + Str(control_ldr_upper) + "{013}{010}" ' Ggf. Traces ausgeben #if Enc28j60_tcp_output Print "String [1.6] = " ; Len(consol_outstring) #endif ' Text in Buffer kopieren For Temp_word_1 = 1 To Len(consol_outstring) Temp_word_2 = Temp_word_3 + Temp_word_1 Temp_char_1 = Mid(consol_outstring , Temp_word_1 , 1) Com_array(temp_word_2) = Asc(temp_char_1) Next Temp_word_1 ' Zwischenpointer für nächsten Stringteil berechnen Temp_word_3 = Temp_word_3 + Len(consol_outstring) ' Paketlänge um Länge des String ergänzen der gerade eingeladen wurde Packetlength = Packetlength + Len(consol_outstring) ' ----- TEIL 7 ----- Consol_outstring = "Helligkeit Unten : " + Str(control_ldr_lower) + "{013}{010}" Consol_outstring = Consol_outstring + "Schaltzeit Timer : " + Str(control_videotimer) + "{013}{010}" Consol_outstring = Consol_outstring + "--------------------" + "{013}{010}" ' Ggf. Traces ausgeben #if Enc28j60_tcp_output Print "String [1.7] = " ; Len(consol_outstring) #endif ' Text in Buffer kopieren For Temp_word_1 = 1 To Len(consol_outstring) Temp_word_2 = Temp_word_3 + Temp_word_1 Temp_char_1 = Mid(consol_outstring , Temp_word_1 , 1) Com_array(temp_word_2) = Asc(temp_char_1) Next Temp_word_1 ' Zwischenpointer für nächsten Stringteil berechnen Temp_word_3 = Temp_word_3 + Len(consol_outstring) ' Paketlänge um Länge des String ergänzen der gerade eingeladen wurde Packetlength = Packetlength + Len(consol_outstring) ' ----- TEIL 8 ----- Consol_outstring = "Aktive Kamera : " Select Case Control_kamera_flag Case Kamera_1 : Consol_outstring = Consol_outstring + "Kamera 1" + "{013}{010}" Case Kamera_2 : Consol_outstring = Consol_outstring + "Kamera 2" + "{013}{010}" End Select Consol_outstring = Consol_outstring + "Spannung Kamera 1 : " Select Case Control_kamera1_pwr_flag Case Aus : Consol_outstring = Consol_outstring + "ausgeschaltet" + "{013}{010}" Case Ein : Consol_outstring = Consol_outstring + "eingeschaltet" + "{013}{010}" End Select ' Ggf. Traces ausgeben #if Enc28j60_tcp_output Print "String [1.8] = " ; Len(consol_outstring) #endif ' Text in Buffer kopieren For Temp_word_1 = 1 To Len(consol_outstring) Temp_word_2 = Temp_word_3 + Temp_word_1 Temp_char_1 = Mid(consol_outstring , Temp_word_1 , 1) Com_array(temp_word_2) = Asc(temp_char_1) Next Temp_word_1 ' Zwischenpointer für nächsten Stringteil berechnen Temp_word_3 = Temp_word_3 + Len(consol_outstring) ' Paketlänge um Länge des String ergänzen der gerade eingeladen wurde Packetlength = Packetlength + Len(consol_outstring) ' ----- TEIL 9 ----- Consol_outstring = "Spannung Kamera 2 : " Select Case Control_kamera2_pwr_flag Case Aus : Consol_outstring = Consol_outstring + "ausgeschaltet" + "{013}{010}" Case Ein : Consol_outstring = Consol_outstring + "eingeschaltet" + "{013}{010}" End Select ' Ggf. Traces ausgeben #if Enc28j60_tcp_output Print "String [1.9] = " ; Len(consol_outstring) #endif ' Text in Buffer kopieren For Temp_word_1 = 1 To Len(consol_outstring) Temp_word_2 = Temp_word_3 + Temp_word_1 Temp_char_1 = Mid(consol_outstring , Temp_word_1 , 1) Com_array(temp_word_2) = Asc(temp_char_1) Next Temp_word_1 ' Zwischenpointer für nächsten Stringteil berechnen Temp_word_3 = Temp_word_3 + Len(consol_outstring) ' Paketlänge um Länge des String ergänzen der gerade eingeladen wurde Packetlength = Packetlength + Len(consol_outstring) ' ----- TEIL 10 ----- Temp_byte_1 = Switch_delay Consol_outstring = "Umschaltzeit : " + Str(temp_byte_1) + "{013}{010}" Consol_outstring = Consol_outstring + "--------------------" + "{013}{010}" Consol_outstring = Consol_outstring + "Aktueller LDR-Wert : " + Str(light_value) + "{013}{010}" ' Ggf. Traces ausgeben #if Enc28j60_tcp_output Print "String [1.10] = " ; Len(consol_outstring) #endif ' Text in Buffer kopieren For Temp_word_1 = 1 To Len(consol_outstring) Temp_word_2 = Temp_word_3 + Temp_word_1 Temp_char_1 = Mid(consol_outstring , Temp_word_1 , 1) Com_array(temp_word_2) = Asc(temp_char_1) Next Temp_word_1 ' Zwischenpointer für nächsten Stringteil berechnen Temp_word_3 = Temp_word_3 + Len(consol_outstring) ' Paketlänge um Länge des String ergänzen der gerade eingeladen wurde Packetlength = Packetlength + Len(consol_outstring) ' ----- TEIL 11 ----- Consol_outstring = "Relaisstatus : " Select Case Relais_status_flag Case Relais_aus : Consol_outstring = Consol_outstring + "ausgeschaltet" + "{013}{010}" Case Relais_ein : Consol_outstring = Consol_outstring + "eingeschaltet" + "{013}{010}" End Select Consol_outstring = Consol_outstring + "DHCP Status : " Select Case Enc28j60_dhcp_flag Case Dhcp_aus : Consol_outstring = Consol_outstring + "ausgeschaltet" + "{013}{010}{010}" Case Dhcp_ein : Consol_outstring = Consol_outstring + "eingeschaltet" + "{013}{010}{010}" End Select ' Ggf. Traces ausgeben #if Enc28j60_tcp_output Print "String [1.11] = " ; Len(consol_outstring) #endif ' Text in Buffer kopieren For Temp_word_1 = 1 To Len(consol_outstring) Temp_word_2 = Temp_word_3 + Temp_word_1 Temp_char_1 = Mid(consol_outstring , Temp_word_1 , 1) Com_array(temp_word_2) = Asc(temp_char_1) Next Temp_word_1 ' Zwischenpointer für nächsten Stringteil berechnen Temp_word_3 = Temp_word_3 + Len(consol_outstring) ' Paketlänge um Länge des String ergänzen der gerade eingeladen wurde Packetlength = Packetlength + Len(consol_outstring) ' ===== Textsequence-Steuerung für Hilfstext ===== Case Sequence_help: ' Ggf. Traces ausgeben #if Enc28j60_tcp_output Print "Sequence HELP erkannt" Print "Start PacketLength : " ; Packetlength #endif ' Bufferindex auf Sendespeicher an richtige Stelle setzen Temp_word_3 = Tcp_data ' Hilfstext aus DATA-Speicher auslesen und auf RS232 ausgeben Restore Hilfstext ' Lesepointer initialisieren Do ' Endlosschleife Read Consol_outstring ' String auslesen. Bei jedem Lesen sprint Pointer ein DATA-Feld weiter Consol_instring = Right(consol_outstring , 8) ' 8 Zeichen von Rechts in Arbeitsvariable kopieren ' Prüfen ob Datenende erreicht If Consol_instring = "endblock" Then ' JA Exit Do ' Schleife verlassen End If 'Datenende ' Temporärer Arbeitsstring in ethernet buffer übertragen For Temp_word_1 = 1 To Len(consol_outstring) ' Schleife über Anzahl ausgelesene Zeichen Temp_char_1 = Mid(consol_outstring , Temp_word_1 , 1) ' String in Arbeitsstring umkopieren Com_array(temp_word_3) = Asc(temp_char_1) ' Kopiere ein Zeichen aus String in Ethernetbuffer Incr Temp_word_3 ' Zeiger auf Ethernetbuffer erhöhen Incr Packetlength Next Temp_word_1 ' Schleife weiterzählen Loop ' ===== Testsequence für Spezialstatus für BirdView-PC-Applikation ===== Case Sequence_xstatus: ' Ggf. Traces ausgeben #if Enc28j60_tcp_output Print "Sequence XSTATUS erkannt" Print "Start PacketLength : " ; Packetlength #endif Temp_word_3 = 54 ' ----- TEIL 1 ----- Consol_outstring = "{" + Str(enc28j60_my_ip_adress(1)) + "." + Str(enc28j60_my_ip_adress(2)) + "." + Str(enc28j60_my_ip_adress(3)) + "." + Str(enc28j60_my_ip_adress(4)) + ";" Consol_outstring = Consol_outstring + Hex(enc28j60_my_mac_adress(1)) + ":" + Hex(enc28j60_my_mac_adress(2)) + ":" + Hex(enc28j60_my_mac_adress(3)) + ":" + Hex(enc28j60_my_mac_adress(4)) + ":" + Hex(enc28j60_my_mac_adress(5)) + ":" + Hex(enc28j60_my_mac_adress(6)) + ";" Consol_outstring = Consol_outstring + Str(enc28j60_subnetmask(1)) + "." + Str(enc28j60_subnetmask(2)) + "." + Str(enc28j60_subnetmask(3)) + "." + Str(enc28j60_subnetmask(4)) + ";" Consol_outstring = Consol_outstring + Str(enc28j60_gateway_ip_adress(1)) + "." + Str(enc28j60_gateway_ip_adress(2)) + "." + Str(enc28j60_gateway_ip_adress(3)) + "." + Str(enc28j60_gateway_ip_adress(4)) + ";" Consol_outstring = Consol_outstring + Hex(enc28j60_router_mac_adress(1)) + ":" + Hex(enc28j60_router_mac_adress(2)) + ":" + Hex(enc28j60_router_mac_adress(3)) + ":" + Hex(enc28j60_router_mac_adress(4)) + ":" + Hex(enc28j60_router_mac_adress(5)) + ":" + Hex(enc28j60_router_mac_adress(6)) + ";" Consol_outstring = Consol_outstring + Str(enc28j60_ntp_ip_adress(1)) + "." + Str(enc28j60_ntp_ip_adress(2)) + "." + Str(enc28j60_ntp_ip_adress(3)) + "." + Str(enc28j60_ntp_ip_adress(4)) + ";" ' Ggf. Traces ausgeben #if Enc28j60_tcp_output Print "String [2.1] = " ; Len(consol_outstring) #endif ' Text in Buffer kopieren (ab Position Tcp_data = 55) For Temp_word_1 = 1 To Len(consol_outstring) Temp_word_2 = Temp_word_3 + Temp_word_1 Temp_char_1 = Mid(consol_outstring , Temp_word_1 , 1) Com_array(temp_word_2) = Asc(temp_char_1) Next Temp_word_1 ' Zwischenpointer für nächsten Stringteil berechnen Temp_word_3 = Temp_word_3 + Len(consol_outstring) ' Paketlänge um Länge des String ergänzen der gerade eingeladen wurde Packetlength = Packetlength + Len(consol_outstring) ' ----- TEIL 2 ----- Temp_byte_1 = Switch_delay Consol_outstring = Str(enc28j60_tcp_port) + ";" + Str(control_runningmode) + ";" + Str(control_irhelligkeit) + ";" + Str(ir_status_flag) + ";" + Str(control_ldr_upper) + ";" Consol_outstring = Consol_outstring + Str(control_ldr_lower) + ";" + Str(control_videotimer) + ";" + Str(control_kamera_flag) + ";" + Str(control_kamera1_pwr_flag) + ";" Consol_outstring = Consol_outstring + Str(control_kamera2_pwr_flag) + ";" + Str(temp_byte_1) + ";" + Str(light_value) + ";" + Str(relais_status_flag) + ";" + Str(enc28j60_dhcp_flag) + "}{013}{010}{010}" ' Ggf. Traces ausgeben #if Enc28j60_tcp_output Print "String [2.2] = " ; Len(consol_outstring) #endif ' Text in Buffer kopieren For Temp_word_1 = 1 To Len(consol_outstring) Temp_word_2 = Temp_word_3 + Temp_word_1 Temp_char_1 = Mid(consol_outstring , Temp_word_1 , 1) Com_array(temp_word_2) = Asc(temp_char_1) Next Temp_word_1 ' Zwischenpointer für nächsten Stringteil berechnen Temp_word_3 = Temp_word_3 + Len(consol_outstring) ' Paketlänge um Länge des String ergänzen der gerade eingeladen wurde Packetlength = Packetlength + Len(consol_outstring) End Select ' ----- Restarbeiten ----- Consol_tcp_sequence_nummer = Sequence_nix ' Sequence zurücksetzen Consol_instring = "" ' String leere Consol_outstring = "" ' String leere Return '-- End Consol_tcp_text_output ------------------------------------------------ ' ************* ' * Scheduler * ' ************* '------------------------------------------------------------------------------ ' Consol: Scheduler_poll ' ' Routine ist zentrale Zeitsteuerungsfunktion mittels derer zeitgesteuerte ' Aufgaben abrearbeitet werden. Zentraler Zeitbezug ist globale Variable ' Scheduler_timer_counter welche pro Sekunde durch Timerinterrupt um 1 erhöht ' wird. ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' Scheduler_timer_counter = globaler Zeitbezug ' '------------------------------------------------------------------------------ Scheduler_poll: ' ----- Programmcode ----- ' [1] ===== Verarbeitung Zeitsteuerung für Messung LDR Hintergrundbeleuchtung ===== ' Prüfen ob Zeit für neue Messung bereit abgelaufen If Scheduler_timer_counter >= Light_timer Then ' JA ' Neue Messung durchführen Light_value = Light_measurement() ' Timer neu setzen Light_timer = Scheduler_timer_counter + Light_timer_intervall ' Prüfen ob Betriebmodus LICHT aktiv If Control_runningmode = Mode_licht Then ' JA ' Prüfen ob aktuelle Kamera noch gültig oder ob Grenzwerte über/unter-Schritten Gosub Control_check_licht ' Korrekte Kamera auswählen End If ' Betriebsmodus LICHT aktiv End If ' Zeit abgelaufen ' [1] ===== Ende ' [2] ===== Zeitgesteuerte Umschaltung der Kameras ===== ' Prüfen ob Umschaltung aktiv If Control_switch_kamera_status = Switch_powered Then ' Ja ' Prüfen ob Zeit für nächsten Schaltschritt abgelaufen If Scheduler_timer_counter >= Control_switch_counter Then ' Ja ' Funktion nochmals aufrufen und nächsten Arbeisschritt durchführen Gosub Control_switch_kamera End If ' Zeit abgelaufen End If ' Umschaltung aktiv ' [2] ===== Ende ' [3] ===== Betriebsmodus ZEIT ===== ' Prüfen ob Betriebsmodus = Zeitsteuerung If Control_runningmode = Mode_zeit Then ' JA ' Prüfen ob Zeit für nächste Kameraumschaltung abgelaufen ist If Scheduler_timer_counter >= Control_timer_mode_counter Then ' Ja ' In Abhängigkeit der aktuellen Zuständ Umschalten Select Case Control_kamera_flag Case Kamera_1 : ' Jetz auf Kamera 2 umschalten Control_switch_kamera_request = Switch_from_cam1_to_cam2 Gosub Control_switch_kamera ' Umschaltung einleiten Case Kamera_2 : ' Jetzt auf Kamera 1 umschalten Control_switch_kamera_request = Switch_from_cam2_to_cam1 Gosub Control_switch_kamera ' Umschaltung einleiten End Select ' Timer neu setzen Control_timer_mode_counter = Scheduler_timer_counter + Control_videotimer End If ' Zeit abgelaufen End If ' zeitsteuerung ' [3] ===== Ende Return '-- End Scheduler_poll -------------------------------------------------------- ' *************************************** ' * Kamerasteuerung und Hilfsfunktionen * ' *************************************** '------------------------------------------------------------------------------ ' Hilfsfunktionen: Control_kamera1_aktiv ' ' Routine schaltet den Videomultiplexer auf Kamera 1, steuert die zugehörigen ' LED's und setzt die entsprechenden Systemflags. ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' Control_kamera_flag = Flag zeigt die aktive geschaltete Videoquelle an ' '------------------------------------------------------------------------------ Control_kamera1_aktiv: ' ----- Programmcode ----- ' ggf Trace ausgeben #if Control_trace Print "Enter Control_kamera1_aktiv" #endif ' Videomultiplexer auf Kamera 1 schalten Video_select = Kanal_1 ' LED für Kamera 1 ein und für Kamera 2 aus Video1_led = Led_ein Video2_led = Led_aus ' Globales Flag umschalten Control_kamera_flag = Kamera_1 ' Kamera 1 aktiv Return '-- End Control_kamera1_aktiv ------------------------------------------------- '------------------------------------------------------------------------------ ' Hilfsfunktionen: Control_kamera2_aktiv ' ' Routine schaltet den Videomultiplexer auf Kamera 2, steuert die zugehörigen ' LED's und setzt die entsprechenden Systemflags. ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' Control_kamera_flag = Flag zeigt die aktive geschaltete Videoquelle an ' '------------------------------------------------------------------------------ Control_kamera2_aktiv: ' ----- Programmcode ----- ' ggf Trace ausgeben #if Control_trace Print "Enter Control_kamera2_aktiv" #endif ' Videomultiplexer auf Kamera 2 schalten Video_select = Kanal_2 ' LED für Kamera 2 ein und für Kamera 1 aus Video2_led = Led_ein Video1_led = Led_aus ' Globales Flag umschalten Control_kamera_flag = Kamera_2 ' Kamera 2 aktiv Return '-- End Control_kamera2_aktiv ------------------------------------------------- '------------------------------------------------------------------------------ ' Hilfsfunktionen: Control_key1 ' ' Routine verarbeitet die Tasteneingabe für Taste 1. Die Taste 1 ist für das ' Ein- und Ausschalten der Hintergrundbeleuchtung verantwortlich. ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' Ir_status_flag = Statusflag ob IR ein- oder ausgeschaltet ' Control_runningmode = Flag für Betriebsart '------------------------------------------------------------------------------ Control_key1: ' ----- Programmcode ----- ' ggf Trace ausgeben #if Control_key_trace Print "Enter Control_key1" #endif Select Case Ir_status_flag Case Aus: Gosub Ir_beleuchtung_an ' IR einschalten Control_runningmode = Mode_manuell ' Aufgrund manuellem Eingriff wir temporär auf manuellen Betriebmodus geschaltet Mode_led = Led_aus ' Status für Betriebsart anpassen Case Ein: Gosub Ir_beleuchtung_aus ' IR ausschalten Control_runningmode = Mode_manuell ' Aufgrund manuellem Eingriff wir temporär auf manuellen Betriebmodus geschaltet Mode_led = Led_aus ' Status für Betriebsart anpassen End Select Return '-- End Control_key1 ---------------------------------------------------------- '------------------------------------------------------------------------------ ' Hilfsfunktionen: Control_key2 ' ' Routine verarbeitet die Tasteneingabe für Taste 2. Die Taste zwei ist für die ' manuelle Auswahl der Videokanals verantwortlich. ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' Control_runningmode = Flag für Betriebsart ' Control_switch_kamera_status = Status welche Kamera gerade aktiv ' Control_switch_kamera_request = Schalter wie geschaltet werden soll '------------------------------------------------------------------------------ Control_key2: ' ----- Programmcode ----- ' ggf Trace ausgeben #if Control_key_trace Print "Enter Control_key2" #endif ' Prüfe ob gerade noch eine Umschaltung läuft, dann verriegeln If Control_switch_kamera_status = Switch_idle Then ' NEIN, es läuft keine Umschaltung Select Case Control_kamera_flag Case Kamera_1: ' --> Auf Kamera 2 umschalten Control_switch_kamera_request = Switch_from_cam1_to_cam2 Gosub Control_switch_kamera ' Umschaltung einleiten Control_runningmode = Mode_manuell ' Aufgrund manuellem Eingriff wir temporär auf manuellen Betriebmodus geschaltet Mode_led = Led_aus ' Status für Betriebsart anpassen Case Kamera_2: ' --> Auf Kamera 1 umschalten Control_switch_kamera_request = Switch_from_cam2_to_cam1 Gosub Control_switch_kamera ' Umschaltung einleiten Control_runningmode = Mode_manuell ' Aufgrund manuellem Eingriff wir temporär auf manuellen Betriebmodus geschaltet Mode_led = Led_aus ' Status für Betriebsart anpassen End Select End If ' Check Umschaltung Return '-- End Control_key2 ---------------------------------------------------------- '------------------------------------------------------------------------------ ' Hilfsfunktionen: Control_key3 ' ' Routine verarbeitet die Tasteneingabe für Taste 3. Die Taste drei wählt die ' Betriebsmodi aus. ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' Control_runningmode = Flag für Betriebsart ' Control_timer_mode_counter = Variable für zeitgesteuertes Umschalten ' ' Anmerkung: ' Die Betriebsart wird in der aktuellen Implementierung nicht persitent im ' EEPROM gespeichert. '------------------------------------------------------------------------------ Control_key3: ' ----- Programmcode ----- ' ggf Trace ausgeben #if Control_key_trace Print "Enter Control_key3" #endif Select Case Control_runningmode Case Mode_manuell : ' --> Umschalten auf Betriebsart LICHT Control_runningmode = Mode_licht Light_value = Light_measurement() ' Neue Lichtmessung durchführen Gosub Control_check_licht ' Korrekte Kamera auswählen Mode_led = Led_ein ' LED-Anzeige für Betriebsart einschalten Case Mode_licht : ' --> Umschalten auf Betriebsart ZEIT Control_runningmode = Mode_zeit ' Timer neu setzen für die Zeit in der das nächste mal Umgeschaltet werden soll Control_timer_mode_counter = Scheduler_timer_counter + Control_videotimer ' Bei Betriebsart ZEIT wird LED durch Sekunden-Tick getoggelt!!! Case Mode_zeit : ' --> Umschalten auf Betriebsart MANUELL Control_runningmode = Mode_manuell Mode_led = Led_aus ' LED-Anzeige für Betriebsart ausschalten End Select Return '-- End Control_key3 ---------------------------------------------------------- '------------------------------------------------------------------------------ ' Hilfsfunktionen: Control_switch_kamera ' ' Funktion steuert das zeitliche Umschalten der Kameras. Die Funktion wird aus ' der Programmcode heraus zunächst aufgerufen und schaltet die Spannungen der ' Kameras damit diese starten können. Bei der SW-Kamera wird gleichzeitig die ' IR Hintergrundbeleuchtung eingeschaltet. Sobald die Kameras gestartet sind ' und sich ihr Bild stabilisiert hat wird über einen Timer gesteuert die Funk- ' tion erneut aufgerufen. Beim 2. Aufruf wird die Videoquelle umgeschaltet und ' die entsprechenden Stati für die LED-Anzeigen gesetzt. ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' Control_switch_kamera_request = Schalter wie geschaltet werden soll ' Control_switch_counter = zeitzähler für automatisches Aufrufen ' ' Anmerkung: ' Auf eine Verriegelung durch fälschliches doppeltes aufrufen der Funktionen ' durch die Applikation wird zunächst verzichtet. '------------------------------------------------------------------------------ Control_switch_kamera: ' ----- Programmcode ----- ' ggf Trace ausgeben #if Control_trace Print "Enter Control_switch_kamera" Select Case Control_switch_kamera_request Case Switch_from_cam1_to_cam2: Print "Schalte von Kamera 1 auf Kamera 2" Case Switch_from_cam2_to_cam1: Print "Schalte von Kamera 2 auf Kamera 1" End Select #endif ' Prüfen ob Funktion das erste Mal aufgerufen wurde um Umzuschalten If Control_switch_kamera_status = Switch_idle Then ' JA, Umschaltung kann eingeleitet werden ' ggf Trace ausgeben #if Control_trace Print "Zustand 1: Schalte Spannungen" #endif ' Spannungen schalten Select Case Control_switch_kamera_request Case Switch_from_cam1_to_cam2: Call Control_pwr_cam2(ein) ' Spannung Kamera 2 einschalten Case Switch_from_cam2_to_cam1: Call Control_pwr_cam1(ein) ' Spannungs Kamera 1 einschalten Gosub Ir_beleuchtung_an ' IR Hintergrundbeleuchtung einschalten ' End Select ' Timer setzen Control_switch_counter = Scheduler_timer_counter + Switch_delay ' Flags setzen Control_switch_kamera_status = Switch_powered ' Spannung geschaltet, nun muss automatisch noch Video geschaltet werden Else ' NEIN, Funktion wurde während Umschaltvorgang aufgerufen, vermutlich durch Timer => weiterschalten ' ggf Trace ausgeben #if Control_trace Print "Zustand 2: Schalte Multiplexer und Stati" #endif ' Videomultiplexer schalten Select Case Control_switch_kamera_request Case Switch_from_cam1_to_cam2: Gosub Control_kamera2_aktiv ' Schalte auf Kamera 2 Gosub Ir_beleuchtung_aus ' Schalte IR Hintergrundbeleuchtung aus Call Control_pwr_cam1(aus) ' Spannungs Kamera 1 einschalten Case Switch_from_cam2_to_cam1: Gosub Control_kamera1_aktiv ' Schalte auf Kamera 1 Call Control_pwr_cam2(aus) ' Spannung Kamera 2 einschalten End Select ' Flags setzen Control_switch_kamera_status = Switch_idle ' Nun auch Video geschaltet, damit Sequenz fertig durchlaufen End If ' ggf Trace ausgeben #if Control_trace Print ' CR+LF #endif Return '-- End Control_switch_kamera ------------------------------------------------- '------------------------------------------------------------------------------ ' Hilfsfunktionen: Control_check_licht ' ' Die Funktion überprüft ob aufgrund der aktuellen Helligkeit eine Obergrenze ' überschritten oder eine Untergrenze unterschritten wird um ggf. die Kameras ' umzuschalten. ' ' Parameter: keiner ' Rückgabe: keine ' ' Globale Variablen: ' Light_value = Variable die aktuelle Helligkeit beinhaltet ' Control_ldr_lower = Untergrenze für Beleuchtung ' Control_ldr_upper = Obergrenze für Beleuchtung ' Control_switch_kamera_request = Schalter wie geschaltet werden soll ' '------------------------------------------------------------------------------ Control_check_licht: ' ----- Programmcode ----- #if Control_trace Print "Enter Control_check_licht" #endif ' Prüfen ob aktuelle Helligkeit größer als obere Grenze If Light_value > Control_ldr_upper Then ' JA --> auf Farbkamera umschalten ' Prüfen ob Umschaltung schon auf Farbkamera If Control_kamera_flag <> Kamera_2 Then ' NEIN --> dann schalten Control_switch_kamera_request = Switch_from_cam1_to_cam2 Gosub Control_switch_kamera ' Umschaltung einleiten End If ' Prüfen ob aktuelle Helligkeit kleiner als untere Grenze Elseif Light_value < Control_ldr_lower Then ' JA --> auf SW-Kamera umschalten ' Prüfen ob Umschaltung schon auf SW-Kamera If Control_kamera_flag <> Kamera_1 Then ' NEIN --> dann schalten Control_switch_kamera_request = Switch_from_cam2_to_cam1 Gosub Control_switch_kamera ' Umschaltung einleiten End If End If Return '-- End Control_check_licht --------------------------------------------------- '------------------------------------------------------------------------------ ' Devices schließend und ggf. "Terminate Programm execution" '------------------------------------------------------------------------------ ' System halt End 'end program '------------------------------------------------------------------------------ ' Datenstruktur fuer Hilfstext '------------------------------------------------------------------------------ ' Hilfstext ' ' 1 ' 1 2 3 4 5 6 7 8 9 0 ' 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 Hilfstext: Data "Allgemeines:{013}{010}" Data " REBOOT{013}{010} VERSION{013}{010} RESETPARAM{013}{010} GETSTATUS{013}{010} HELP{013}{010}" Data " GETDHCP{013}{010} GETIP{013}{010} GETGW{013}{010} GETSUBNET{013}{010} GETMAC{013}{010}" Data " GETNTP{013}{010} GETROUTERMAC{013}{010} GETPORT{013}{010} GETMODE{013}{010} GETPWMVALUE{013}{010}" Data " GETLDRLOWER{013}{010} GETLDRUPPER{013}{010} GETTIMER{013}{010} GETIR{013}{010} GETSOURCE{013}{010}" Data " GETPWRCAM1{013}{010} GETPWRCAM2{013}{010} GETLDR{013}{010} DOMEASUREMENT{013}{010}" Data " GETRELAIS{013}{010}{013}{010}" Data "IP-Settings:{013}{010}" Data " SETIP x.x.x.x{013}{010} SETGW x.x.x.x{013}{010} SETSUBNET x.x.x.x{013}{010} SETNTP x.x.x.x{013}{010}" Data "{013}{010}" Data "MAC-Settings:{013}{010} SETMAC y:y:y:y:y:yy{013}{010} SETROUTERMAC y:y:y:y:y:y{013}{010}{013}{010}" Data "Sonstige Konfiguration:{013}{010}" Data " SETDHCP [0=Aus,1=Ein]{013}{010} SETPORT x [0-65535]{013}{010} SETMODE [0=Manuell,1=Licht,2=Zeit]{013}{010}" Data " SETPWMVALUE x [0-255]{013}{010} SETLDRLOWER x [0-1023]{013}{010} SETLDRUPPER x [0-1023]{013}{010}" Data " SETTIMER x [0-65535]{013}{010} SETIR x [0=Aus,1=Ein]{013}{010} SETSOURCE x [1=Kamera1,2=Kamera2]{013}{010}" Data " SETPWRCAM1 x [0=Aus,1=Ein]{013}{010} SETPWRCAM2 x [0=Aus,1=Ein]{013}{010}" Data " SETRELAIS x [0=Aus, 1=Ein]{013}{010}{013}{010}" Data "endblock" '###################################### END ################################### '################################### Historie ################################# ' 19.04.2012 : Version 0.0 ' Beginn der Implementierungen ' 13.05.2012 : Version 1.0 ' Fertigstellung Erstimplementierung und Start eingehender Tests ' 13.05.2012 : Version 1.1 ' Umstellung auf Voll-Duplex-Betrieb ' Bei Tests wurde ein sporadischer Hängenbleiber der Senderoutine ' bzw. der Sendebearbeitung des Chips festgestellt. Der Fehler ' zeigt sich, dass die Botschaft welche zum ENC28J60 übertragen ' wurde nur unvollständig gesendet wird und der Chip dann im ' Status Senden hängen bleibt, was am ECON1.TXRTS Bit zu erkennen ' ist welches normalerweise nach einem erfolgreichen Senden auf ' NULL zurückgesetzt wird. ' Die Ursache des Fehlers konnte bis jetzt nicht ermittelt werden. ' Die Arbeitshypothese ist, das es zu einer Kollision zwischen ' Daten die gesendet- und Daten die empfangen werden sollen kommt. ' Der ENC28J60 wurde auf Voll-Duplex-Betrieb umkonfiguriert. Bis ' jetzt verliefen die Tests positiv was die Arbeitshypothese etwas ' bestätigt. ' Sollte der Fehler erneut auftreten wäre eine Überwachung der ' Sendung mit Timeout und anschließendem Reset des Controllers ' eine weitere mögliche Maßnahme um den Hänger zu lösen. ' Sicherlich nur eine Hammermethode aber mir fällt aktuell nix ' besseres ein. ' 17.05.2012 : Version 1.2 ' Für die Steuerung mit der BirdView-PC-Applikation wird ein neuer ' Spezialbefehlt "xstatus" umgesetzt welche den Status zusammen- ' gefasst in Form {x;y;z;...} an die Applikation sendet. Der ' Befehl ist über RS232-Konsole nicht erreichbar. ' 27.05.2012 : Version 1.3 ' Es zeigte sich das Problem, dass häufig beim Aufbau der TCP- ' Kommunikation das SYN, ACK doppelt gesendet wurde obwohl die ' Funktion TCP-Processing und auch die Sendroutine nur einmal ' aufgerufen wurde. Unklar ist der Grund. Es wurde von mir jedoch ' die While-Schleife auskommentiert welche auf die erfolgreiche ' Sendung der Botschaft wartet und damit trat bei 20 Versuchen der ' Fehler nicht mehr erneut auf. ' 10.06.2012 : Für die Steuerung des Relais wurde noch der Befehl SETRELAIS und ' GETRELAIS eingebaut. ' Die Ansteuerung der MagJack-LED's wurde projektspezifisch an- ' gepasst da GELBund GRÜN gegenüber EVA-Board verdreht sind. ' 15.06.2012 : Fehler in Längenberechnung der Nutzdaten für das TCP-Datenpaket ' gefunden und korrigiert. ' Nachdem Videomultiplexer mit MAX nicht funktioniert wurde Steu- ' erung komplett auf Relais umgestellt. Video_SHDN entfällt! ' 24.06.2012 : Für die Ausgabe von XSTATUS wurde Relaisstatus und DHCP-Status ' ergänzt. ' Logik für die Ausgabe des Status bei mit/ohne DHCP geändert. '##############################################################################