program dsPIC33EP_NMRAnetCommandStation; // ****************************************************************************** // // * Copyright: // (c) Mustangpeak Software 2012. // // The contents of this file are subject to the GNU GPL v3 licence/ you maynot use // this file except in compliance with the License. You may obtain a copy of the // License at http://www.gnu.org/licenses/gpl.html // // * Revision History: // 2012-02-01: Created // 2012-11-13: Converted to the dsPIC33EP // 2012-11-13: Updated to v2 of the NMRAbus Library // 2013-3-31 : Service Mode completed // // * Description: // Implements a NMRABus based Command Station // // //* TODO // - Packet Refresh // - Traction Protocol Results: implement // - Implement "stupid throttle" (Lenz/NCE) // - When in Service Mode it is blocked and will cause issues with the node CAN if other chatter is on the bus // - Can't detect no loco on the track in Byte by Bit mode because a lack of an ACK is interperted as it "must be a 0" // - Operations Service Mode needs implementing // // // * Improvements // - Optimize how Service Mode looks for values (check 0, 255, 64, 192 first) // // * Fixes // - 128/14 Step Mode 4/1/13: Fixed 128 step mode not working with short address // - Auto Allocate vTrainNodes 4/1/13: Added configuration option to turn this on off. // - Reworked the Overcurrent to use ADC Interrupts. Much faster and less overhead needed (12us every 5.5ms with 16x oversampling) 4/13/2013 // - Reworked statemachine to allow Binary Searching of Nodes for fast access of vNodes 4/13/2013 // - Reworked Free Node to release vNodes when Train is released; 4/20/13 // // ****************************************************************************** {$I Options.inc} uses dsPIC33_Traps, NMRAnetStateMachine, NMRAnetDefines, NMRAnetAppCallbacks, NMRAnetDCC, MCU_Setup_dsPIC33EP64GP502, // _25AAxxxx, TCPStorage, NMRAnetBufferPools, NMRAnetNode, HelperFunctions, NodeIDs, NMRAnetServiceMode, TractionProtocol, ServiceModeDefines; const MAX_CONNECT_TRY_COUNT = 1; var // EEPROM SPI PINS // CS_Bank_0 : sbit at LATB6_bit; // CS_Bank_0_Direction : sbit at TRISB6_bit; // EE_PROM_Hold : sbit at LATB5_bit; // EEPROM_Hold_Direction : sbit at TRISB5_bit; // DCC SIGNAL PINS H_Bridge_A_Lo : sbit at LATA1_bit; H_Bridge_A_Hi : sbit at LATB0_bit; H_Bridge_B_Lo : sbit at LATB1_bit; H_Bridge_B_Hi : sbit at LATB4_bit; H_Bridge_A_Lo_Direction : sbit at TRISA1_bit; H_Bridge_A_Hi_Direction : sbit at TRISB0_bit; H_Bridge_B_Lo_Direction : sbit at TRISB1_bit; H_Bridge_B_Hi_Direction : sbit at TRISB4_bit; DCC_Programming_ACK_Pin : sbit at RB2_bit; // Input so use the port and not the latch DCC_Programming_ACK_Direction : sbit at TRISB2_bit; DCC_NMRA_Tranmitter_Lo : sbit at LATB15_bit; // DCC Bus Transmitter DCC_NMRA_Tranmitter_Hi : sbit at LATB14_bit; // DCC Bus Transmitter DCC_NMRA_Tranmitter_Lo_Direction : sbit at TRISB15_bit; // DCC Bus Transmitter DCC_NMRA_Tranmitter_Hi_Direction : sbit at TRISB14_bit; // DCC Bus Transmitter Ack_TimerEnabled_Bit : sbit at TON_T5CON_bit; // DCC Service Mode ACK Timer Dcc_Timer_PR : Word at PR1; // DCC Interrupt Rollover TrapFlagPin : sbit at LATB3_bit; // OVERLOADING THE NMRA DCC TRANSMITTER CURRENT SENSE // Ethernet SPI Interface ENC_CS: sbit at LATB6_bit; // for writing to output pin always use latch ENC_CS_dir: sbit at TRISB6_bit; LastSocketState: Integer; // ***************************************************************************** // INTERRUPTS // ***************************************************************************** DCCTime: Word; procedure RunServiceMode; begin // Toggle the Bridge off H_Bridge_A_Lo := 0; // Bridge Off H_Bridge_A_Hi := 0; // Bridge Off H_Bridge_B_Lo := 0; // Bridge Off H_Bridge_B_Hi := 0; // Bridge Off if ServiceModeInfo.iStateMachine > STATE_SERVICEMODE_IDLE then begin if Programming.TX_Flags.TRANSMITTING_FLAG_DCC_PIN_BIT = 1 then begin H_Bridge_A_Lo := 1; H_Bridge_B_Hi := 1; end else begin H_Bridge_A_Hi := 1; H_Bridge_B_Lo := 1; end; // Now we can update the xxxx_DCC_PIN_BIT flags for the next 56us time slot ServiceMode_56us_TimeTick; NMRA_DCC_TransmitterStateMachine(@Programming, True, False); ServiceMode_StateMachine(@Programming); end end; procedure RunNmraDccTranmitter; begin DCC_NMRA_Tranmitter_Lo := 0; // DCC Bus Transmitter DCC_NMRA_Tranmitter_Hi := 0; // DCC Bus Transmitter if Track.TX_Flags.TRANSMITTING_FLAG_DCC_PIN_BIT = 1 then DCC_NMRA_Tranmitter_Lo := 1 else DCC_NMRA_Tranmitter_Hi := 1; end; procedure ToggleBridge; begin H_Bridge_A_Lo := 0; // Bridge Off H_Bridge_A_Hi := 0; // Bridge Off H_Bridge_B_Lo := 0; // Bridge Off H_Bridge_B_Hi := 0; // Bridge Off if Track.TX_Flags.TRANSMITTING_FLAG_DCC_PIN_BIT = 1 then begin H_Bridge_A_Lo := 1; H_Bridge_B_Hi := 1; end else begin H_Bridge_A_Hi := 1; H_Bridge_B_Lo := 1; end; end; procedure INTERRUPT_DCC_Timer(); iv IVT_ADDR_T1INTERRUPT; begin T1IF_bit := 0; // Clear the Flag if CommandStationRamData.OverloadDetected then begin // Toggle the Bridge off H_Bridge_A_Lo := 0; // Bridge Off H_Bridge_A_Hi := 0; // Bridge Off H_Bridge_B_Lo := 0; // Bridge Off H_Bridge_B_Hi := 0; // Bridge Off end else begin if CommandStationConfigurationShadowRam.OutputMode = CONFIG_OUTPUTMODE_SERVICE_MODE then begin RunServiceMode // Command Station is in Service Mode end else begin // Command Station is in Main Line Mode if CommandStationConfigurationShadowRam.DccBusMode = CONFIG_NMRA_DCC_TRANSMITTER then // If we are a DCC Transmitter then handle that RunNmraDccTranmitter; if CommandStationConfigurationShadowRam.RailComEnable = CONFIG_RAILCOM_ENABLED then begin if Track.TX_Flags.TRANSMITTING_FLAG_RAIL_COM_CUTOUT_BIT = 1 then begin H_Bridge_A_Lo := 1; // Short the Rails H_Bridge_B_Lo := 1; end else ToggleBridge end else ToggleBridge; // Now we can update the xxxx_DCC_PIN_BIT flags for the next 56us time slot NMRA_DCC_58us_TimeTick(@Track); // < 1us NMRA_DCC_TransmitterStateMachine(@Track, False, CommandStationConfigurationShadowRam.RailComEnable = CONFIG_RAILCOM_ENABLED); // < 5us NMRA_DCC_LoadPacketIntoTransmitterStateMachine(@Track, PREAMBLE_BIT_COUNT_NORMAL); // < 11us Max end end end; procedure INTERRUPT_100ms_Timer(); iv IVT_ADDR_T2INTERRUPT; // Called once every 100m var i: Integer; begin T2IF_bit := 0; // Clear the Flag for i := 0 to Nodes.AllocatedCount - 1 do NMRAnetStateMachine_100ms_Timer(Nodes.AllocatedList[i]); NMRAnetBufferPools_100ms_TimeTick; ServiceMode_100ms_TimeTick end; procedure INTERRUPT_1ms_Ethernet_Stack_Timer(); iv IVT_ADDR_T3INTERRUPT; ics ICS_AUTO; begin T3IF_bit := 0; CounterTask; end; procedure INTERRUPT_5ms_Timer(); iv IVT_ADDR_T5INTERRUPT; // Called once every 5m during Service MOde begin T5IF_bit := 0; // Clear the Flag ServiceMode_5ms_TimeTick end; procedure INTERRUPT_ADC1(); iv IVT_ADDR_AD1INTERRUPT; ics ICS_AUTO; const CLAMP_UPPER_LIMIT = 7; CLAMP_LOWER_LIMIT = 0; var i: Integer; begin AD1IF_bit := 0; case OverCurrent.iStateMachine of STATE_OVERCURRENT_NORMAL : begin NMRAnetTractionProtocol_OvercurrentUpdateCountersWithAdcBuffers(@ADC1BUF0, 8, CLAMP_LOWER_LIMIT, CLAMP_UPPER_LIMIT); if OverCurrent.Counter = CLAMP_UPPER_LIMIT then begin // Potential OC detected in this Sampling time frame if OverCurrent.SampleTimeStepLimitCounter = OverCurrent.SampleTimeStepLimitShutDown then Inc(OverCurrent.iStateMachine) // Have found N Sampling frames that all said an overcurrent occured, start the fault sequence else Inc(OverCurrent.SampleTimeStepLimitCounter); // Have not found N sampling frames that have all said an overcurrent occured, increase the sampling counter end else OverCurrent.SampleTimeStepLimitCounter := 0; // If we get one Sampling time frame that is not an OC then reset the timer end; STATE_OVERCURRENT_DETECTED : begin i := 1; CommandStationRamData.OverloadDetected := True; OverCurrent.Counter := CLAMP_LOWER_LIMIT; // Reset the Counters OverCurrent.SampleTimeStepLimitCounter := 0; Inc(OverCurrent.iStateMachine); end; STATE_OVERCURRENT_OFF : begin NMRAnetTractionProtocol_OvercurrentUpdateCountersWithAdcBuffers(@ADC1BUF0, 8, CLAMP_LOWER_LIMIT, CLAMP_UPPER_LIMIT); if OverCurrent.Counter = CLAMP_LOWER_LIMIT then begin // Potential recovery detected in this Sampling time frame if OverCurrent.SampleTimeStepLimitCounter = OverCurrent.SampleTimeStepLimitRestart then Inc(OverCurrent.iStateMachine) // Have found N Sampling frames that all said an overcurrent occured, start the fault sequence else Inc(OverCurrent.SampleTimeStepLimitCounter); // Have not found N sampling frames that have all said an overcurrent occured, increase the sampling counter end else OverCurrent.SampleTimeStepLimitCounter := 0; // If we get one Sampling time frame that is an OC then reset the timer end; STATE_OVERCURRENT_REMOVED : begin i := 0; CommandStationRamData.OverloadDetected := False; OverCurrent.Counter := CLAMP_LOWER_LIMIT; // Reset the Counters OverCurrent.SampleTimeStepLimitCounter := 0; OverCurrent.iStateMachine := STATE_OVERCURRENT_NORMAL; end; end; end; function IsPrintableChar(C: Char): Boolean; begin Result := ((Ord( C) >= 32) and (Ord( C) <= 126)) or ((Ord( C) >= 128) and (Ord( C) <= 255)) end; procedure DumpEEProm(ASCII: Boolean); var Buffer: array[0..15] of byte; i, j, Offset: Integer; s: string[64]; Output: string[256]; begin { i := 0; Offset := 0; while i < 1024 do // Max is 8192 but that is too much begin _25AAxxxx_Read(EEPROM_BANK_0, Offset, 16, @Buffer[0]); WordToHex(Offset, s); Output := s + ' | '; for j := 0 to 15 do begin s := '' ; if ASCII then s := s + Char(Buffer[j]) else ByteToHex(Buffer[j], s); Output := Output + s + ' '; end; UART1_Write_Text(Output + LF); Offset := Offset + 16; Inc(i); end; } end; procedure PrintMenu; begin UART1_Write_Text(LF+'Menu:'+LF); UART1_Write_Text('****************************************************************'+LF); UART1_Write_Text('s xxx.xxx.xxx.xxx; - Connect to Server with IP given IP Address'+LF); UART1_Write_Text('u; - Disconnect from server'+LF); UART1_Write_Text('a; - Allocate Train Node'+LF); UART1_Write_Text('d; - Deallocate Train Node'+LF); UART1_Write_Text('****************************************************************'+LF); UART1_Write_Text('Don''t forget to terminate UART commands with a semicolon!'+LF); UART1_Write_Text('****************************************************************'+LF); end; // ******************* // MAIN LOOP // ******************* var ActiveNode, TempNode: PNMRAnetNode; i, IpCount, ConnectTryCount: Integer; Cmd: array[128] of char; str: string[6]; ProxyData: PTrainProxyRamData; TempIP: TIPAddressStr; TempIpServer: TIPAddress; TempChar: char; ipPortClient, ipPortServer: Word; Delay, OldHead, OldTail: Integer; OldFull: Boolean; TempIPHeader: TIPAddress; PingTime: word; DNS_Path: string[64]; ipDest: TIPAddress; Running: Boolean; begin SR := SR and $FF1F; // Bug in silicon? Clear the IPL bits (CPU Priority is lowest possible) ANSELA := 0; ANSELB := 0; TRISA4_bit := 0; LATA4_bit := 0; OldHead := -1; OldTail := -1; OldFull := True; Delay := 0; Running := False; // Output // _25AAxxxx_Initialize; NMRAnetStateMachine_Initialize(MUSTANGPEAK_ID_0_HI, {MUSTANGPEAK_SERVICETRACK_NODE_ID_0_LO} MUSTANGPEAK_COMMANDSTATION_ID_0_LO); MCU_Setup_Initialize; // Start the timers and perpherials last NMRA_DCC_Initialize; ServiceMode_Initialize; AppCallback_Configuration_Zeroize(False); AppCallback_Sync_Config_Ram_with_EEPROM; H_Bridge_A_Lo := 0; // Bridge Off H_Bridge_A_Hi := 0; // Bridge Off H_Bridge_B_Lo := 0; // Bridge Off H_Bridge_B_Hi := 0; // Bridge Off H_Bridge_A_Lo_Direction := 0; // Output H_Bridge_A_Hi_Direction := 0; // Output H_Bridge_B_Lo_Direction := 0; // Output H_Bridge_B_Hi_Direction := 0; // Output DCC_NMRA_Tranmitter_Lo := 1; DCC_NMRA_Tranmitter_Hi := 0; DCC_NMRA_Tranmitter_Lo_Direction := 0; // Output DCC_NMRA_Tranmitter_Hi_Direction := 0; // Output ipPortClient := 12022; UART1_Write_Text('Starting DCC Packets'+LF); // TON_T3CON_bit := 1; // Turn on current limit AD1IE_bit := 1; // Turn on ADC1 interrupt TON_T2CON_bit := 1; // Turn on the 100ms timer {$IFNDEF DCCTIMER_DISABLE} TON_T1CON_bit := 1; // Start the DCC Timer Delay_ms(10); NMRA_DCC_Packet_Init; // Send our 20 Idle Packets per the spec, note we are not on the OLCB bus yet so this will block until done. {$ENDIF} UART1_Write_Text('Initializing OlcbBus'+LF); MCU_Setup_Enable_OlcbBus; delay_ms(1000); while not DHCP_Request(ENC_ReceivedPacketAddr) do; delay_ms(1000); if Port_Open_TCP(12022) then UART1_Write_Text('Port Opened' +LF) else UART1_Write_Text('Port Open failed'+LF); UART1_Write_Text('DHCP Results' + LF); Ip2Str(Settings.eth_ip_addr, s1); UART1_Write_Text('Ip Address: ' + s1 + LF); Ip2Str(Settings.eth_gateway, s1); UART1_Write_Text('Gateway Address: ' + s1 + LF); Ip2Str(Settings.eth_mask, s1); UART1_Write_Text('Mask: ' + s1 + LF); Ip2Str(Settings.eth_dns_addr, s1); UART1_Write_Text('DNS Address: ' + s1 + LF); SocketManager.TCP_Wait := 1000; SocketManager.UDP_Wait := 1000; LastSocketState := -1; PrintMenu; while (TRUE) do begin if Running then begin // Global updates // Allcoate a proxy if needed if (CommandStationRamData.EnableAutoAllocateProxy = 0) and (CommandStationRamData.AllocateProxy > 0) then begin { LockCANInterrupt; // There may be dangling nodes that have been allocated then released if NMRAnetTractionProtocol_FindFirstNonDCCAllocatedNode = nil then NMRAnetNode_Allocate; Dec(CommandStationRamData.AllocateProxy); UnLockCANInterrupt; } end; ActiveNode := NMRAnetNode_NextNode; if ActiveNode <> PNMRAnetNode( nil) then NMRAnetStateMachine_Process(ActiveNode); if CANStorage_HighPriorityBufferReady then begin Do_Storage_Send; // Send it NOW end else begin if (Delay = 20) or CAN_Engine.TransmitImmediately then begin if CANStorage_LowPriorityBufferReady then Do_Storage_Send; Delay := 0; end; end; Inc(Delay); end; EthernetProcess(1); // Do the Ethernet Procedure one iteration DHCP_Process(ENC_ReceivedPacketAddr); if NTP_Sync then begin if NTP_Sec = 0 then begin NTP_GetTime; UART1_Write_Text('Time = ' + TTime.Str + LF); end end; if UART1_Data_Ready = 1 then begin UART_Read_Text(Cmd, ';', 128); UART_Write_Text('Echo Cmd: ' + Cmd + LF); case Cmd[0] of 'u', 'U' : begin TCP_Close_Connection(ipDest, OLCB_SERVER_PORT); { if OlcbSocketOpen then begin UART_Write_Text('Disconnecting' + LF); if Close_TCP_Connection(TempIPServer, ipPortServer) then begin TCP_Close_Port(ipPortClient); OlcbSocketOpen := False; UART1_Write_Text('Socket closed'+LF); end else UART1_Write_Text('Unable to close Socket'+LF); end else UART_Write_Text('Socket was not connected' + LF); } end; 's', 'S' : begin Running := True; Str2IP(OLCB_SERVER_IP, ipDest); WordToStr(OLCB_SERVER_PORT, s1); UART1_Write_Text('Connecting to IP: '+ OLCB_SERVER_IP + ' Port: ' + s1 + LF); case TCP_Open_Connection(ipDest, OLCB_SERVER_PORT, 12022) of RESULT_OPEN_TCP_CONNECTION_OK : begin UART1_Write_Text('TCP Connection Opened'+LF); // Close_TCP_Connection(ipDest, OLCB_SERVER_PORT); end; RESULT_OPEN_TCP_CONNECTION_ARP_FAILED : UART1_Write_Text('TCP Connection ARP failed'+LF); RESULT_OPEN_TCP_CONNECTION_NO_SOCKETS : UART1_Write_Text('TCP Connection No Sockets'+LF); RESULT_OPEN_TCP_CONNECTION_SEND_FAILED : UART1_Write_Text('TCP Connection "Send" Failed'+LF) else UART1_Write_Text('TCP Connection unknown Result'+LF); end; { if not OlcbSocketOpen then begin TempIP := ''; ipCount := 0; i := 1; // Skip over the 's' while (Cmd[i] = ' ') and (Cmd[i] <> #0) do Inc(i); while IsValidIPChar(Cmd[i]) and (ipCount < MAX_IP_ADDRESS_LEN) do begin TempIP[ipCount] := Cmd[i]; Inc(i); Inc(ipCount); end; TempIP[ipCount] := #0; if strLen(TempIP) > 0 then begin if StrToIPAddress(TempIP, TempIpServer, ipPortServer) then begin if ipPortServer = 0 then ipPortServer := DEFAULT_SERVER_PORT; ConnectTryCount := 0; WordToStr(ipPortServer, s1); TrimValue(@s1); WordToStr(ipPortClient, str); TrimValue(@str); TCP_Open_Port(ipPortClient); while not OlcbSocketOpen and (ConnectTryCount < MAX_CONNECT_TRY_COUNT) do begin UART1_Write_Text('Connecting to IP Address: ' + IPAddressToStr(TempIpServer) + ':' + s1 + ' Client port: ' + str+ LF); OlcbSocketOpen := Open_TCP_Connection(TempIpServer, ipPortServer, ipPortClient); if not OlcbSocketOpen then Inc(ConnectTryCount); end; Inc(ipPortClient); if ConnectTryCount = MAX_CONNECT_TRY_COUNT then UART_Write_Text('Failed to Connect'+LF) else UART_Write_Text('Connected'+LF); end else UART_Write_Text('Invalid IP Address'+LF); end else UART_Write_Text('Please enter a IP Address'+LF); end else UART_Write_Text('Already Connected' + LF); } end; 'P' : begin //PrintDMABuffers end; 'X' : begin NMRAnetStateMachine_TrySendVerifyNodeID(ActiveNode, 0); end; 'A', 'a' : begin LockCANInterrupt; NMRAnetNode_Allocate; UnLockCANInterrupt; end; 'D', 'd' : begin LockCANInterrupt; TempNode := NMRAnetNode_FindFirstVirtualNode; if TempNode <> nil then begin ProxyData := NMRAnetTractionProtocol_ExtractTrainProxyRamData( TempNode); ProxyData^.State := ProxyData^.State and not PS_DCC_ADDRESS_ALLOCATED; end; UnLockCANInterrupt end; 'F', 'f' : begin LockCANInterrupt; TempNode := NMRAnetNode_FindFirstVirtualNode; if TempNode <> nil then NMRAnetNode_MarkForRelease(TempNode); UnLockCANInterrupt end; 'Z', 'z' : begin // _25AAxxxx_Erase(EEPROM_BANK_0); end; 'V' : begin DumpEEProm(True); // Print in ASCII end; 'v' : begin DumpEEProm(False); // Print in Hex end; 'M', 'm' : begin for i := 0 to MAX_NODE_COUNT - 1 do begin LongWordToStr(Nodes.RawList[i].ConfigurationAddress, s1); UART1_Write_Text('Offset: ' + s1 +LF); end; for i := 0 to MAX_NODE_COUNT - 1 do begin LongWordToStr(Nodes.RawList[i].RAMAddress, s1); UART1_Write_Text('RAM Offset: ' + s1 +LF); end; end; '9' : begin ByteToStr(CommandStationConfigurationShadowRam.OutputMode, s1); UART1_Write_Text('Output Mode: ' + s1 + LF); ByteToStr(CommandStationConfigurationShadowRam.ProgrammingMode, s1); UART1_Write_Text('Programming Mode: ' + s1 + LF); ByteToStr(CommandStationConfigurationShadowRam.DccBusMode, s1); UART1_Write_Text('DCC Bus Mode: ' + s1 + LF); end; '1' : ServiceMode_Print; '2' : begin IntToStr(OverCurrent.SampleTimeStepLimitShutDown, s1); UART1_Write_Text('SampleTimeStepLimitShutDown: ' + s1 + LF); IntToStr(OverCurrent.SampleTimeStepLimitRestart, s1); UART1_Write_Text('SampleTimeStepLimitRestart: ' + s1 + LF); IntToStr(OverCurrent.SampleTimeStepLimitCounter, s1); UART1_Write_Text('SampleTimeStepLimitCounter: ' + s1 + LF); IntToStr(OverCurrent.Limit, s1); UART1_Write_Text('Over Current Limit: ' + s1 + LF); IntToStr(OverCurrent.Counter, s1); UART1_Write_Text('Over Current Counter: ' + s1 + LF); IntToStr(OverCurrent.BitValue, s1); UART1_Write_Text('BitValue: ' + s1 + LF); FloatToStr(Double( OverCurrent.BitValue) * 1.9230769 * 0.00322266, s1); // .00322266 V/Bit * 1.9230769A/V * Bits = UART1_Write_Text('Measured Current: ' + s1 + 'A' + LF); WordToStr(CommandStationConfigurationShadowRam.OverCurrentLevel, s1); UART1_Write_Text('I Level: ' + s1 + LF); WordToStr(CommandStationConfigurationShadowRam.OverCurrentTime, s1); UART1_Write_Text('I Time: ' + s1 + LF); WordToStr(CommandStationRamData.OverloadDetected, s1); UART1_Write_Text('OverloadDetected: ' + s1 + LF); end; '3' : begin for i := 0 to Nodes.AllocatedCount - 1 do begin NMRAnetNode_PrintNodeData( i, Nodes.AllocatedList[i]); NMRAnetTractionProtocol_PrintNodeRamData(Nodes.AllocatedList[i], False); UART1_Write_Text(LF + LF); end; end; '4' : begin NMRAnetNode_PrintRawNodeData end; '5' : begin CAN_Engine.TX_NMRAnetBufferSent := 0; CAN_Engine.TX_NMRAnetBufferLoaded := 0; end; '7' : begin Str2Ip('192.168.0.127', TempIPHeader); PingTime := Ping_Send(TempIPHeader , 0); case PingTime of PING_SEND_RESULT_TIMEOUT : begin UART1_Write_Text('Ping time for 192.168.0.127 = no response' + LF); end; PING_SEND_RESULT_INVALID_SLOT : begin UART1_Write_Text('Invalid Ping Slot' + LF); end else begin WordToStr(PingTime, s1); UART1_Write_Text('Ping time for 192.168.0.127 = ' + s1 + 'ms' + LF); end; end; Str2Ip('192.168.0.8', TempIPHeader); PingTime := Ping_Send(TempIPHeader , 0); case PingTime of PING_SEND_RESULT_TIMEOUT : begin UART1_Write_Text('Ping time for 192.168.0.8 = no response' + LF); end; PING_SEND_RESULT_INVALID_SLOT : begin UART1_Write_Text('Invalid Ping Slot' + LF); end else begin WordToStr(PingTime, s1); UART1_Write_Text('Ping time for 192.168.0.8 = ' + s1 + 'ms' + LF); end; end; Str2Ip('192.168.0.234', TempIPHeader); PingTime := Ping_Send(TempIPHeader , 0); case PingTime of PING_SEND_RESULT_TIMEOUT : begin UART1_Write_Text('Ping time for 192.168.0.234 = no response' + LF); end; PING_SEND_RESULT_INVALID_SLOT : begin UART1_Write_Text('Invalid Ping Slot' + LF); end else begin WordToStr(PingTime, s1); UART1_Write_Text('Ping time for 192.168.0.234 = ' + s1 + 'ms' + LF); end; end; end; '8' : begin if NTP_Query then begin UART1_Write_Text('NTP_Query successful' + LF); end; end; 'k' : begin DNS_Path := 'www.mustangpeak.net'; UART1_Write_Text('DNS resolving: ' + DNS_Path + LF); if Dns_Resolve(DNS_Path, TempIPHeader) then begin UART1_Write_Text('DNS Resolve successful' + LF); Ip2Str(TempIPHeader, s1); UART1_Write_Text(DNS_Path + ' = ' + s1 + LF); end else UART1_Write_Text('DNS Resolve failed' + LF); end; end; while UART1_Data_Ready = 1 do UART1_Read; end; end; end.