From: <jim...@us...> - 2013-03-17 00:28:54
|
Revision: 3048 http://openlcb.svn.sourceforge.net/openlcb/?rev=3048&view=rev Author: jimkueneman626 Date: 2013-03-17 00:28:43 +0000 (Sun, 17 Mar 2013) Log Message: ----------- Updated mikroPascal Libraries and Command Station Code for use with dsPIC33256EP502 Modified Paths: -------------- trunk/prototypes/mikroPascal/Library/NMRAnet/NMRAnetDefinesShared.mpas trunk/prototypes/mikroPascal/Library/NMRAnet/NMRAnetStateMachine.mpas trunk/prototypes/mikroPascal/Library/NMRAnetDCCSystem/NMRAnetDCC.mpas trunk/prototypes/mikroPascal/Library/NMRAnetDCCSystem/PagedServiceMode.mpas trunk/prototypes/mikroPascal/dsPIC33EP_CommandStation/MCU_Setup_dsPIC33EP64GP502.mpas trunk/prototypes/mikroPascal/dsPIC33EP_CommandStation/MemoryMapping.ods trunk/prototypes/mikroPascal/dsPIC33EP_CommandStation/NMRAnetAppCallbacks.mpas trunk/prototypes/mikroPascal/dsPIC33EP_CommandStation/NMRAnetAppDefines.mpas trunk/prototypes/mikroPascal/dsPIC33EP_CommandStation/Options.inc trunk/prototypes/mikroPascal/dsPIC33EP_CommandStation/dsPIC33EP_NMRABusCommandStation.hex trunk/prototypes/mikroPascal/dsPIC33EP_CommandStation/dsPIC33EP_NMRABusCommandStation.mppds trunk/prototypes/mikroPascal/dsPIC33EP_CommandStation/dsPIC33EP_NMRAnetCommandStation.mpas trunk/prototypes/mikroPascal/dsPIC33FJ_Visual TFT_BasicThrottle/Throttle.vtft Added Paths: ----------- trunk/prototypes/mikroPascal/dsPIC33EP256_CommandStation/ trunk/prototypes/mikroPascal/dsPIC33EP256_CommandStation/MCU_Setup_dsPIC33EP64GP502.mpas trunk/prototypes/mikroPascal/dsPIC33EP256_CommandStation/NMRAnetAppCallbacks.mpas trunk/prototypes/mikroPascal/dsPIC33EP256_CommandStation/NMRAnetAppDefines.mpas trunk/prototypes/mikroPascal/dsPIC33EP256_CommandStation/Options.inc trunk/prototypes/mikroPascal/dsPIC33EP256_CommandStation/dsPIC33EP_NMRABusCommandStation.hex trunk/prototypes/mikroPascal/dsPIC33EP256_CommandStation/dsPIC33EP_NMRABusCommandStation.mppds trunk/prototypes/mikroPascal/dsPIC33EP256_CommandStation/dsPIC33EP_NMRAnetCommandStation.mpas trunk/prototypes/mikroPascal/dsPIC33EP256_CommandStation/dsPIC33F_CommandStation.xml trunk/prototypes/mikroPascal/dsPIC33EP256_CommandStation/dsPIC33F_ProxyNode.xml Modified: trunk/prototypes/mikroPascal/Library/NMRAnet/NMRAnetDefinesShared.mpas =================================================================== --- trunk/prototypes/mikroPascal/Library/NMRAnet/NMRAnetDefinesShared.mpas 2013-03-16 05:25:05 UTC (rev 3047) +++ trunk/prototypes/mikroPascal/Library/NMRAnet/NMRAnetDefinesShared.mpas 2013-03-17 00:28:43 UTC (rev 3048) @@ -26,9 +26,8 @@ const CV_READWRITE_MODE_ADDRESS = 0; // CV's are then indexed 1-MAX_DCC_CV_ADDRESSES_SUPPORTED - MAX_DCC_CV_ADDRESSES_SUPPORTED = 512; - + // ***************************************************************************** // Shared Protocol Identification Protocol Defines // ***************************************************************************** @@ -92,7 +91,6 @@ MSI_ACDI_MFG = $FC; // MemorySpaceIdentifer - Access the ACDI Manfacturers Info MSI_ACDI_USER = $FB; // MemorySpaceIdentifer - Access the ACDI User definable Info MSI_FDI = $FA; // MemorySpaceIdentifer - Access the Function Definition Information (FDI) - MSI_CvDI = $F9; // MemorySpaceIdentifer - Access the CV Definition Information (CvDI) MCO_WRITE_UNDER_MASK = $8000; // MemoryConfigurationOptions - Write under mask supported MCO_UNALIGNED_READS = $4000; // MemoryConfigurationOptions - Unaligned memory Reads supported Modified: trunk/prototypes/mikroPascal/Library/NMRAnet/NMRAnetStateMachine.mpas =================================================================== --- trunk/prototypes/mikroPascal/Library/NMRAnet/NMRAnetStateMachine.mpas 2013-03-16 05:25:05 UTC (rev 3047) +++ trunk/prototypes/mikroPascal/Library/NMRAnet/NMRAnetStateMachine.mpas 2013-03-17 00:28:43 UTC (rev 3048) @@ -77,11 +77,6 @@ procedure AppCallback_FDI_Write(Node: PNMRAnetNode; DataTarget: ^Byte; StartAddress: DWord; MaxCount: Byte); external; function AppCallback_FDI_Read(Node: PNMRAnetNode; DataTarget: ^Byte; StartAddress: DWord; MaxCount: Byte): Byte; external; {$ENDIF} - {$IFDEF SUPPORT_CvDI} - function AppCallback_CvDI_AddressSpaceSize(Node: PNMRAnetNode): Word; external; - procedure AppCallback_CvDI_Write(Node: PNMRAnetNode; DataTarget: ^Byte; StartAddress: DWord; MaxCount: Byte); external; - function AppCallback_CvDI_Read(Node: PNMRAnetNode; DataTarget: ^Byte; StartAddress: DWord; MaxCount: Byte): Byte; external; - {$ENDIF} // Address Space Support @@ -458,9 +453,6 @@ {$IFDEF SUPPORT_FDI} MSI_FDI : Result := AppCallback_FDI_AddressSpaceSize(Node); {$ENDIF} // SUPPORT_FDI - {$IFDEF SUPPORT_FDI} - MSI_CvDI : Result := AppCallback_CvDI_AddressSpaceSize(Node); - {$ENDIF} // SUPPORT_CvDI MSI_CDI : begin {$IFDEF SUPPORT_VIRTUAL_NODES} if Node^.State and NS_VIRTUAL <> 0 then Modified: trunk/prototypes/mikroPascal/Library/NMRAnetDCCSystem/NMRAnetDCC.mpas =================================================================== --- trunk/prototypes/mikroPascal/Library/NMRAnetDCCSystem/NMRAnetDCC.mpas 2013-03-16 05:25:05 UTC (rev 3047) +++ trunk/prototypes/mikroPascal/Library/NMRAnetDCCSystem/NMRAnetDCC.mpas 2013-03-17 00:28:43 UTC (rev 3048) @@ -30,6 +30,8 @@ MAX_NMRA_DCC_DATA = 5; // Number of Bytes in a valid NMRA DCC Message MAX_NMRA_DCC_STARTUP_IDLE = 20; + + DEFAULT_RAILCOM_COUNT = 7; // Give a 477us "Te" timing PREAMBLE_BIT_COUNT_NORMAL = 14; // Normal message preamble bit count PREAMBLE_BIT_COUNT_SERVICEMODE = 20; // Service Mode message count @@ -58,6 +60,8 @@ STATE_NMRA_DCC_PIN_1 = 1; // Second 56us (for a "0") STATE_NMRA_DCC_PIN_2 = 2; // First 56us STATE_NMRA_DCC_PIN_3 = 3; // Second 56us (for a "0") + STATE_NMRA_DCC_PIN_0_RAILCOM = 4; + STATE_NMRA_DCC_PIN_1_RAILCOM = 5; type // *************************************************************************** @@ -120,9 +124,11 @@ // (if not nil) and the transmitter state // *************************************************************************** const - TRANSMITTING_FLAG_CURRENT_BIT = 0; // Bit 0 = Current bit being transmitted - TRANSMITTING_FLAG_STOP_BIT = 1; // Bit 1 = Transmitting the last bit ("1" stop) - TRANSMITTING_FLAG_DCC_PIN_BIT = 2; // Bit 2 = State of the I/O Pin + TRANSMITTING_FLAG_CURRENT_BIT = 0; // Bit 0 = Current bit being transmitted + TRANSMITTING_FLAG_STOP_BIT = 1; // Bit 1 = Transmitting the last bit ("1" stop) + TRANSMITTING_FLAG_DCC_PIN_BIT = 2; // Bit 2 = State of the I/O Pin + TRANSMITTING_FLAG_RAIL_COM_CUTOUT_BIT = 3; // Bit 3 = RailCom Cutout Time + TRANSMITTING_FLAG_RAIL_COM_ENABLED = 4; // Bit 4 = Enable/Disable RailCom cutout type TDCCBufferInfo = record @@ -131,6 +137,7 @@ TX_TransmittingPacket: TDCCPacket; // Message that is being currently transmitted TX_PreambleBitCount: Byte; // Number of Preamble Bits to send, the value is destroyed when the state machine is run + TX_RailComBitCount: Word; // TX_iStateMachine: Byte; // Main State machine TX_iBit: Byte; // Index of the current Bit being sent TX_iDCC_Pin_StateMachine: Byte; // Index of the running the I/O Pin state @@ -152,6 +159,7 @@ var Track: TDCCBufferInfo; Programming: TDCCBufferInfo; + RailComCount: Word; // Call once on start up procedure NMRA_DCC_Initialize; forward; @@ -226,6 +234,7 @@ begin InitializeBuffer(@Track, @TrackQueue, @TrackQueuePriority, MAX_TRACK_BUFFER_DEPTH, MAX_TRACK_PRIORITY_BUFFER_DEPTH); InitializeBuffer(@Programming, nil, nil, 0, 0); + RailComCount := DEFAULT_RAILCOM_COUNT; end; // **************************************************************************** @@ -754,6 +763,9 @@ // **************************************************************************** procedure NMRA_DCC_TransmitterStateMachineHandleStopBit(ABuffer: PDCCBufferInfo); begin + +LATA4_bit := 1; + ABuffer^.TX_iBit := STATE_NMRA_DCC_BIT_7; // Reset Bit index for the next Byte ABuffer^.TX_Flags.TRANSMITTING_FLAG_CURRENT_BIT := 1; // Current Bit = 1 (stop bit) ABuffer^.TX_Flags.TRANSMITTING_FLAG_STOP_BIT := 1; // Flag we are transmitting the Stop Bit @@ -821,8 +833,21 @@ if ABuffer^.TX_Flags.TRANSMITTING_FLAG_STOP_BIT = 1 then // If transmitting the second half of the stop bit then reset everything and get ready for the next message begin + + LATA4_bit := 1; + + ABuffer^.TX_Flags.TRANSMITTING_FLAG_RAIL_COM_CUTOUT_BIT := 0; ABuffer^.TX_Flags.TRANSMITTING_FLAG_STOP_BIT := 0; ABuffer^.TX_iStateMachine := STATE_NMRA_DCC_PREAMBLE; // New message starting + + if ABuffer^.TX_Flags.TRANSMITTING_FLAG_RAIL_COM_ENABLED = 1 then + ABuffer^.TX_iDCC_Pin_StateMachine := STATE_NMRA_DCC_PIN_0_RAILCOM + else begin + ABuffer^.TX_Flags.TRANSMITTING_FLAG_RAIL_COM_CUTOUT_BIT := 0; + ABuffer^.TX_iDCC_Pin_StateMachine := STATE_NMRA_DCC_PIN_0; + end; + + LATA4_bit := 0; end end; end; @@ -830,6 +855,24 @@ begin ABuffer^.TX_iDCC_Pin_StateMachine := STATE_NMRA_DCC_PIN_0; // Pin State 3 is the second "negative" 56us of a new "0" bit being sent on the DCC line, if the bit was a 1 in Pin State 2 then this state is skipped end; + STATE_NMRA_DCC_PIN_0_RAILCOM : + begin + ABuffer^.TX_Flags.TRANSMITTING_FLAG_DCC_PIN_BIT := 1; + ABuffer^.TX_Flags.TRANSMITTING_FLAG_RAIL_COM_CUTOUT_BIT := 1; + ABuffer^.TX_RailComBitCount := RailComCount; + ABuffer^.TX_iDCC_Pin_StateMachine := STATE_NMRA_DCC_PIN_1_RAILCOM + end; + STATE_NMRA_DCC_PIN_1_RAILCOM : + begin + ABuffer^.TX_Flags.TRANSMITTING_FLAG_DCC_PIN_BIT := 0; + // Need to reset the timer interrupt for the normal 58us bit, see the spec + Dec(ABuffer^.TX_RailComBitCount); + if ABuffer^.TX_RailComBitCount = 0 then + begin + ABuffer^.TX_Flags.TRANSMITTING_FLAG_RAIL_COM_CUTOUT_BIT := 0; + ABuffer^.TX_iDCC_Pin_StateMachine := STATE_NMRA_DCC_PIN_0; + end; + end; end; end; Modified: trunk/prototypes/mikroPascal/Library/NMRAnetDCCSystem/PagedServiceMode.mpas =================================================================== --- trunk/prototypes/mikroPascal/Library/NMRAnetDCCSystem/PagedServiceMode.mpas 2013-03-16 05:25:05 UTC (rev 3047) +++ trunk/prototypes/mikroPascal/Library/NMRAnetDCCSystem/PagedServiceMode.mpas 2013-03-17 00:28:43 UTC (rev 3048) @@ -116,7 +116,7 @@ begin ServiceModeInfo.iInstructionCountSent := 1; NMRA_DCC_LoadResetPacketIntoTransmitter(BufferPtr, PREAMBLE_BIT_COUNT_SERVICEMODE); - ServiceModeInfo.iStateMachine := STATE_SERVICEMODE_PAGED_WRITE_PAGE_REGISTER_RECOVER; + ServiceModeInfo.iStateMachine := STATE_SERVICEMODE_PAGED_INSTRUCTION_RESET; end end; Property changes on: trunk/prototypes/mikroPascal/dsPIC33EP256_CommandStation ___________________________________________________________________ Added: svn:ignore + *.txt *.bmk *.cfg *.bdg *.ini *.dlt *.dct *.log *.mcl *.asm *.dbg *.brk *.lst *.dic Added: trunk/prototypes/mikroPascal/dsPIC33EP256_CommandStation/MCU_Setup_dsPIC33EP64GP502.mpas =================================================================== --- trunk/prototypes/mikroPascal/dsPIC33EP256_CommandStation/MCU_Setup_dsPIC33EP64GP502.mpas (rev 0) +++ trunk/prototypes/mikroPascal/dsPIC33EP256_CommandStation/MCU_Setup_dsPIC33EP64GP502.mpas 2013-03-17 00:28:43 UTC (rev 3048) @@ -0,0 +1,199 @@ +unit MCU_Setup_dsPIC33EP64GP502; + +uses + NMRAnetDefinesShared, + CANBuffers, + dsPIC33_CAN, + dsPIC33_DMA; + +{$I Options.inc} + +const + CAN_SWJ = 0; // Set up for 125Khz Baud Rate with a 8Mhz Crystal + CAN_BRP = 7; // Baud Rate Prescaler = 15 Quanta (125000 * 16 = 20Meg) + CAN_PHASESEG_1 = 4; // 16 - (1 + 6 + 5) = 4 + CAN_PHASESEG_2 = 5; // + CAN_PROP_SEG = 3; // + + DCC_TIMER_56US = 1792; // Clock ticks every 31.25ns * 1792 = 56us interrupts + DCC_TIMER_29US = 928; // Clock ticks every 31.25ns * 928 = 29us interrupts + + + procedure MCU_Setup_Initialize; + +implementation + +procedure MCU_Setup_Initialize; +var + i: Integer; + WordPtr: ^Word; +begin + ANSELA := 0; + ANSELB := 0; + + + OSCCON := OSCCON and $F8FF; // Clear NOSC bits (set to FRC mode) + OSCCON.0 := 1; // Tell it to change modes + while OSCCON.0 = 1 do; // wait for it to take effect + + CLKDIV := CLKDIV and 0xFFE0; // PLLPRE<4:0> = 0 -> N1 = 2 8MHz / 2 = 4MHz + // (must be within 0.8 MHz to 8 MHz range) + PLLFBD := 30; // PLLDIV<8:0> = 30 -> M = 32 4MHz * 32 = 128MHz + // (must be within 100 MHz to 200 MHz range) + PLLPOST_1_bit := 0; + PLLPOST_0_bit := 0; // PLLPOST<1:0> = 0 -> N2 = 2 128MHz / 2 = 64MHz + + OSCCON := OSCCON or $0300; // Set COSC to 011 = XT with PLL + OSCCON.0 := 1; // Tell it to change modes + while OSCCON.0 = 1 do; // wait for it to take effect + while LOCK_bit = 0 do; + + Delay_ms(10); + + dsPIC33_CAN_EnterConfigMode; // Place the module in Configuration Mode + // Setup the CAN Baud Rate + dsPIC33_CAN_SetBaud(CAN_SWJ, CAN_BRP, CAN_PHASESEG_2, CAN_PHASESEG_1, CAN_PROP_SEG, True); // Setup the Baud Rate for 125kHz with a 64Mhz Clock + + // Setup the CAN Receive Filters, AN1249 says this should be done in Config Mode + dsPIC33_CAN_SetMask(2, $08000000, True); // Mask 2 looks only at bit 27 for the Filters + dsPIC33_CAN_SetFilter(0, $00000000, True); // Look for a 0 in bit 27 (CAN Layer Messsage) + dsPIC33_CAN_SetFilter(1, $08000000, True); // Look for a 1 in bit 27 (NMRABus Layer Message) + dsPIC33_CAN_AssociateFilterWithMask(0, 2); // Link Filter 0 and Mask 2 which looks only at bit 27 = 0 + dsPIC33_CAN_AssociateFilterWithMask(1, 2); // Link Filter 1 and Mask 2 which looks only at bit 27 = 1 + dsPIC33_CAN_EnableDisableRXFilters($0003); // Enable Filters 0 and 1 + dsPIC33_CAN_RegisterBufferWithFilter(0, CAN_RX_0_BUFFER); // Filter 0 to be sent to Buffer + dsPIC33_CAN_RegisterBufferWithFilter(1, CAN_RX_0_BUFFER); // Filter 1 to be sent to Buffer + + dsPIC33_CAN_EnterNormalMode; // Place the module in Normal Mode + + // Setup the CAN Transmitter + dsPIC33_CAN_SetBufferAsTransmitter(CAN_TX_0_BUFFER, True); // Setup Buffer 0 as a Transmit Buffer + + // Set up Normal Transmit 0 DMA + dsPIC33_DMA_Enable(CAN_TX_0_DMA_CHANNEL, False); + dsPIC33_DMA_DataSize(CAN_TX_0_DMA_CHANNEL, DATASIZE_WORD); // DMA Data Size is a Word + dsPIC33_DMA_Direction(CAN_TX_0_DMA_CHANNEL, DIRECTION_RAM_TO_PERIPHERAL); // Transmit move data from RAM to the Module + dsPIC33_DMA_AddressMode(CAN_TX_0_DMA_CHANNEL, ADDRESS_MODE_PERIPHERAL_INDIRECT); // Don't use the buggy Perpherial Addressing Mode + dsPIC33_DMA_OperatingMode(CAN_TX_0_DMA_CHANNEL, OPERATING_MODE_CONTINIOUS); // Continious Mode (as apposed to one shot) + dsPIC33_DMA_TransferCount(CAN_TX_0_DMA_CHANNEL, 8); // 0...7 + dsPIC33_DMA_ManualDMATransfer(CAN_TX_0_DMA_CHANNEL, False); // Automatic DMA Transfers + dsPIC33_DMA_PeripheralAddress(CAN_TX_0_DMA_CHANNEL, Word( @C1TXD)); // Assign the DMA Channel to the Transmit Register of the CAN module + dsPIC33_DMA_InterruptSelect(CAN_TX_0_DMA_CHANNEL, IRQ_ECAN1_TX_DATA_READY); // Assign the DMA Channel to the ECAN 1 TX to Trigger the Transfer + dsPIC33_DMA_AddressOffsetA(CAN_TX_0_DMA_CHANNEL, Word( @TX_Main_RawBufferArray[CAN_TX_0_BUFFER])); // Enable DMA Channel + dsPIC33_DMA_Enable(CAN_TX_0_DMA_CHANNEL, True); + + + // Setup the CAN Transmitter + dsPIC33_CAN_SetBufferAsTransmitter(CAN_TX_1_BUFFER, True); // Setup Buffer 0 as a Transmit Buffer + + // Set up Normal Transmit 1 DMA + dsPIC33_DMA_Enable(CAN_TX_1_DMA_CHANNEL, False); + dsPIC33_DMA_DataSize(CAN_TX_1_DMA_CHANNEL, DATASIZE_WORD); // DMA Data Size is a Word + dsPIC33_DMA_Direction(CAN_TX_1_DMA_CHANNEL, DIRECTION_RAM_TO_PERIPHERAL); // Transmit move data from RAM to the Module + dsPIC33_DMA_AddressMode(CAN_TX_1_DMA_CHANNEL, ADDRESS_MODE_PERIPHERAL_INDIRECT); // Don't use the buggy Perpherial Addressing Mode + dsPIC33_DMA_OperatingMode(CAN_TX_1_DMA_CHANNEL, OPERATING_MODE_CONTINIOUS); // Continious Mode (as apposed to one shot) + dsPIC33_DMA_TransferCount(CAN_TX_1_DMA_CHANNEL, 8); // 0...7 + dsPIC33_DMA_ManualDMATransfer(CAN_TX_1_DMA_CHANNEL, False); // Automatic DMA Transfers + dsPIC33_DMA_PeripheralAddress(CAN_TX_1_DMA_CHANNEL, Word( @C1TXD)); // Assign the DMA Channel to the Transmit Register of the CAN module + dsPIC33_DMA_InterruptSelect(CAN_TX_1_DMA_CHANNEL, IRQ_ECAN1_TX_DATA_READY); // Assign the DMA Channel to the ECAN 1 TX to Trigger the Transfer + dsPIC33_DMA_AddressOffsetA(CAN_TX_1_DMA_CHANNEL, Word( @TX_Main_RawBufferArray[CAN_TX_1_BUFFER])); // Enable DMA Channel + dsPIC33_DMA_Enable(CAN_TX_1_DMA_CHANNEL, True); + + // Setup the CAN Receiver + dsPIC33_CAN_SetBufferAsTransmitter(CAN_RX_0_BUFFER, False); // Setup Buffer 0 as a Receive Buffer + + // Setup the Receive DMA + dsPIC33_DMA_DataSize(CAN_RX_0_DMA_CHANNEL, DATASIZE_WORD); // DMA Data Size is a Word + dsPIC33_DMA_Direction(CAN_RX_0_DMA_CHANNEL, DIRECTION_PERIPHERAL_TO_RAM); // Transmit move data from the Module to RAM + dsPIC33_DMA_AddressMode(CAN_RX_0_DMA_CHANNEL, ADDRESS_MODE_REG_INDIRECT_POST_INCREMENT); // Don't use the buggy Perpherial Addressing Mode + dsPIC33_DMA_OperatingMode(CAN_RX_0_DMA_CHANNEL, OPERATING_MODE_CONTINIOUS); // Continious Mode (as apposed to one shot) + dsPIC33_DMA_TransferCount(CAN_RX_0_DMA_CHANNEL, 8); // Transfers 8 Words (0 counts as 1) + dsPIC33_DMA_ManualDMATransfer(CAN_RX_0_DMA_CHANNEL, False); // Automatic DMA Transfers + dsPIC33_DMA_PeripheralAddress(CAN_RX_0_DMA_CHANNEL, Word( @C1RXD)); // Assign the DMA Channel to the Receive Register of the CAN module + dsPIC33_DMA_InterruptSelect(CAN_RX_0_DMA_CHANNEL, IRQ_ECAN1_RX_DATA_READY); // Assign the DMA Channel to the ECAN 1 RX to Trigger the Transfer + dsPIC33_DMA_AddressOffsetA(CAN_RX_0_DMA_CHANNEL, Word( @RX_Main_RawBufferArray[0])); // Point the Receive Buffer Offset into the CAN Layer Buffer + dsPIC33_DMA_Enable(CAN_RX_0_DMA_CHANNEL, True); // Enable DMA Channel 2 + +(* // Setup the CAN Receiver + dsPIC33_CAN_SetBufferAsTransmitter(CAN_RX_1_BUFFER, False); // Setup Buffer 0 as a Receive Buffer + + // Setup the Receive DMA + dsPIC33_DMA_DataSize(CAN_RX_1_DMA_CHANNEL, DATASIZE_WORD); // DMA Data Size is a Word + dsPIC33_DMA_Direction(CAN_RX_1_DMA_CHANNEL, DIRECTION_PERIPHERAL_TO_RAM); // Transmit move data from the Module to RAM + dsPIC33_DMA_AddressMode(CAN_RX_1_DMA_CHANNEL, ADDRESS_MODE_REG_INDIRECT_POST_INCREMENT); // Don't use the buggy Perpherial Addressing Mode + dsPIC33_DMA_OperatingMode(CAN_RX_1_DMA_CHANNEL, OPERATING_MODE_CONTINIOUS); // Continious Mode (as apposed to one shot) + dsPIC33_DMA_TransferCount(CAN_RX_1_DMA_CHANNEL, 8); // Transfers 8 Words (0 counts as 1) + dsPIC33_DMA_ManualDMATransfer(CAN_RX_1_DMA_CHANNEL, False); // Automatic DMA Transfers + dsPIC33_DMA_PeripheralAddress(CAN_RX_1_DMA_CHANNEL, @C1RXD); // Assign the DMA Channel to the Receive Register of the CAN module + dsPIC33_DMA_InterruptSelect(CAN_RX_1_DMA_CHANNEL, IRQ_ECAN1_RX_DATA_READY); // Assign the DMA Channel to the ECAN 1 RX to Trigger the Transfer + dsPIC33_DMA_AddressOffsetA(CAN_RX_1_DMA_CHANNEL, @RX_Main_RawBufferArray[0]); // Point the Receive Buffer Offset into the CAN Layer Buffer + dsPIC33_DMA_Enable(CAN_RX_1_DMA_CHANNEL, True); // Enable DMA Channel 2 + *) + + dsPIC33_CAN_InterruptFlagRXBufferOverflow(True); // Clear the flag + dsPIC33_CAN_InterruptFlagRXBuffer(True); // RX Interrupt Flag Reset + dsPIC33_CAN_InterruptFlagTXBuffer(True); // TX Interrupt Flag Reset + dsPIC33_CAN_RXBufferOverflowInterrupt(True); // If we don't enable this and an interrupt occurs then it hangs the loop because you can't clear the Rx Interrupt until this is serviced + dsPIC33_CAN_TXBufferInterrupt(True); // Enable the TX Done Event Interrupt + dsPIC33_CAN_RXBufferInterrupt(True); // Enable the RX Done Event Interrupt + + dsPIC33_CAN_GlobalInterruptCAN_EventPriority(6); // CAN Event Interrupt has a priority of 6 out of 7 + dsPIC33_CAN_GlobalInterruptCAN_Event(True); // Enable the CAN Event Interrupt + + Unlock_IOLOCK; + {$IFDEF UART_ENABLE} + PPS_Mapping_NoLock(44, _INPUT, _U1RX); // Set RPI44 to the UART Receive + PPS_Mapping_NoLock(42, _OUTPUT, _U1TX); // Set RP42 to the UART Transmit + {$ENDIF} + PPS_Mapping_NoLock(45, _INPUT, _C1RX); // Set RPI45 to the CAN Receive + PPS_Mapping_NoLock(43, _OUTPUT, _C1TX); // Set RP43 to the CAN Transmit + Lock_IOLOCK; + + + {$IFDEF UART_ENABLE} + // Initialize UART + + UART1_Init(230400); // Initialize UART module a + Delay_ms(100); // Wait for UART module to stabilize + {$ENDIF} + + SPI1_Init(); // Initialize SPI1 module + SPIEN_bit := 0; // Disable SPI + SPI1CON := SPI1CON and $FFE0; // Clear the prescaler bits + SPI1CON := SPI1CON or $0003 or $0018; // Setup for 5 Mhz (with the CAN plug in boards) $10=5Mhz, $14=6.67Mhz, $18 = 10Mhz + SPIEN_bit := 1; // Enable the SPI + + {$IFNDEF DCCTIMER_DISABLE} + TCS_T1CON_bit := 0; // internal cycle clock + T1IP_0_bit := 1; // Timer 1 Interrupt Priority = 7 (1 means off) + T1IP_1_bit := 1; + T1IP_2_bit := 1; + PR1 := DCC_TIMER_56US; + T1IF_bit := 0; // Clear T1IF + T1IE_bit := 1; // Enable the Interrupt + {$ENDIF} + + TCS_T2CON_bit := 0; // Disable + T2IP_0_bit := 0; // Timer 2 Interrupt Priority = 2 (1 means off) + T2IP_1_bit := 1; + T2IP_2_bit := 0; + TCKPS_0_T2CON_bit := 1; // 256 Prescaler + TCKPS_1_T2CON_bit := 1; + PR2 := 12500; // Clock ticks every 31.25ns * 256 * 12500 = 100ms interrupts + T2IF_bit := 0; // Clear T2IF + T2IE_bit := 1; // Enable the Interrupt + TON_T2CON_bit := 1; // Turn on + + TCS_T5CON_bit := 0; // Disable + T5IP_0_bit := 1; // Timer 5 Interrupt Priority = 5 (1 means off) + T5IP_1_bit := 0; + T5IP_2_bit := 1; + TCKPS_0_T5CON_bit := 1; // 256 Prescaler + TCKPS_1_T5CON_bit := 1; + PR5 := 625; // Clock ticks every 31.25ns * 256 * 625 = 5ms interrupts + T5IF_bit := 0; // Clear T2IF + T5IE_bit := 1; // Enable the Interrupt + +end; + +end. \ No newline at end of file Added: trunk/prototypes/mikroPascal/dsPIC33EP256_CommandStation/NMRAnetAppCallbacks.mpas =================================================================== --- trunk/prototypes/mikroPascal/dsPIC33EP256_CommandStation/NMRAnetAppCallbacks.mpas (rev 0) +++ trunk/prototypes/mikroPascal/dsPIC33EP256_CommandStation/NMRAnetAppCallbacks.mpas 2013-03-17 00:28:43 UTC (rev 3048) @@ -0,0 +1,753 @@ +unit NMRAnetAppCallbacks; + +// ****************************************************************************** +// +// * 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 +// +// * Description: +// Implements program specific callbacks for memory configuration etc. +// +// AppCallbacks for the Mustangpeak Command Station +// +// ****************************************************************************** + +{$I Options.inc} + +uses + _25AAxxxx, + NMRAnetStateMachine, + NMRAnetDCC, + CANStorage, + NMRAnetAppDefines, + NMRAnetDefines, + NMRAnetNode, + NMRAnetUtilities, + Float16, + NMRAnetDefinesShared; + +const + TRACTION_PROTOCOL_MASK = $F0; + TRACTION_OLCB = $00; + TRACTION_DCC = $80; + + TRACTION_OP_MASK = $0F; + TRACTION_OP_SPEED_DIR = $00; + TRACTION_OP_FUNCTION = $01; + TRACTION_OP_E_STOP = $02; + + TRACTION_OP_PROXY_MGMT = $02; + + DCC_ALLOCATE_ADDRESS = $01; + DCC_DEALLOCATE_ADDRESS = $02; + DCC_FUNCTION_28 = $00; + DCC_FUNCTION_32k = $01; + + const + _28_STEP_TABLE: array[0..28] of Byte = ( + %00000000, // Stop + %00000010, // Step 1 + %00010010, // Step 2 + %00000011, // Step 3 + %00010011, // Step 4 + %00000100, // Step 5 + %00010100, // Step 6 + %00000101, // Step 7 + %00010101, // Step 8 + %00000110, // Step 9 + %00010110, // Step 10 + %00000111, // Step 11 + %00010111, // Step 12 + %00001000, // Step 13 + %00011000, // Step 14 + %00001001, // Step 15 + %00011001, // Step 16 + %00001010, // Step 17 + %00011010, // Step 18 + %00001011, // Step 19 + %00011011, // Step 20 + %00001100, // Step 21 + %00011100, // Step 22 + %00001101, // Step 23 + %00011101, // Step 24 + %00001110, // Step 25 + %00011110, // Step 26 + %00001111, // Step 27 + %00011111 // Step 28 + ); + + _14_STEP_TABLE: array[0..14] of Byte = ( + %00000000, // Stop + %00000010, // Step 1 + %00000011, // Step 3 + %00000100, // Step 5 + %00000101, // Step 7 + %00000110, // Step 9 + %00000111, // Step 11 + %00001000, // Step 13 + %00001001, // Step 15 + %00001010, // Step 17 + %00001011, // Step 19 + %00001100, // Step 21 + %00001101, // Step 23 + %00001110, // Step 25 + %00001111 // Step 27 + ); + +const + PS_DCC_ADDRESS_ALLOCATED = $01; // The Proxy is Allocated + + MSG_SEND_DCC_ADDRESS_ALLOCATED = $01; // Need to send a Message for the DCC Address was Allocated + +type + TDccProxyData = record // Structure stored in RAM on a node and vnode basis + State: Byte; // State of the Proxy Node + MsgFlags: Byte; // Message Flags for messages that need to be sent in the Statemachine + Speed: Word; // Float 16 so negative is reverse (including -0) + SpeedSteps: Byte; // TEMPORARY - PUT IN CONFIGURATION + Functions: DWord; // Function State (F0..F28) + Address: Word; // DCC Address + end; + PDccProxyData = ^TDccProxyData; + +const + MAX_NODE_CFG_DATA = 128; // This allows the EEPROM to never get out of sync and need to be erased and rebuilt, just grow TDCCConfigurationData up to 1024 + MAX_VNODE_CFG_DATA = 2304; // This allows the EEPROM to never get out of sync and need to be erased and rebuilt, just grow TDCCConfigurationData up to 1024 + +type + TDCCConfigurationData = record + ConsistNext, // // 4 Bytes + ConsistPrev: TNodeID; // // 4 Bytes + end; + PDCCConfigurationData = ^TDCCConfigurationData; + +procedure NMRAnetAppCallbacks_Initialize; +procedure AppCallback_AssignRAMAddress(Node: PNMRANetNode; iNode: Word); +function AppCallback_ProducerIdentify(Node: PNMRAnetNode; Event: PEventID): Boolean; +function AppCallback_ConsumerIdentify(Node: PNMRAnetNode; Event: PEventID): Boolean; +function AppCallback_EventsIdentify: Boolean; +function AppCallback_EventsIdentifyByDest(Node: PNMRAnetNode): Boolean; +procedure AppCallback_TractionControl(Node: PNMRAnetNode; CANBuffer: PCANBuffer); +function AppCallback_StateMachine(Node: PNMRAnetNode; CANBuffer: PCANBuffer; DataBytesPtr: PCAN_DataBytes): Boolean; +procedure AppCallback_NodeAllocate(Node: PNMRAnetNode); + +// Address Space Support +// ***************************************************************************** +procedure AppCallback_AssignConfigurationAddress(Node: PNMRANetNode; iNode: Word); + +function AppCallback_AddressSpacePresent(Node: PNMRAnetNode; AddressSpace: Byte): Boolean; +function AppCallback_AddressSpaceReadOnly(Node: PNMRAnetNode; AddressSpace: Byte): Boolean; + +function AppCallback_Configuration_AddressSpaceSize(Node: PNMRAnetNode): Word; +function AppCallback_Configuration_Read(Node: PNMRAnetNode; DataTarget: ^Byte; StartAddress: DWord; MaxCount: Byte): Byte; +procedure AppCallback_Configuration_Write(Node: PNMRAnetNode; DataTarget: ^Byte; StartAddress: DWord; MaxCount: Byte); + +function AppCallback_FDI_AddressSpaceSize(Node: PNMRAnetNode): Word; +procedure AppCallback_FDI_Write(Node: PNMRAnetNode; DataTarget: ^Byte; StartAddress: DWord; MaxCount: Byte); +function AppCallback_FDI_Read(Node: PNMRAnetNode; DataTarget: ^Byte; StartAddress: DWord; MaxCount: Byte): Byte; + +// ***************************************************************************** + +// Local to Train Nodes +function GetProxyData(Node: PNMRAnetNode): PDccProxyData; + +implementation + +// Array of records that contain Volatile Data (RAM only) for each Node. The address of the record is assigned to the +// node in the AssignRAMAddress function below +var + VolatileData: array[0..MAX_NODE_COUNT - 1] of TDccProxyData; + +procedure UpdateFunctionsAndSendDCCMessage(AddressHi, AddressLo, FunctionAddress, FunctionValue: Byte; var DCCPacket: TDCCPacket; ProxyData: PDccProxyData); +var + WideFunctionMask: DWord; + FunctionMask, FunctionExtendedCode: Byte; +begin + WideFunctionMask := $00000001; + WideFunctionMask := WideFunctionMask shl FunctionAddress; // Set the correct Function Bit + ProxyData^.Functions := ProxyData^.Functions and not WideFunctionMask; // Clear the bit + if FunctionValue > 0 then + ProxyData^.Functions := ProxyData^.Functions or WideFunctionMask; // Set the bit if needed + + if FunctionAddress < 29 then + begin + if FunctionAddress < 5 then + begin + FunctionMask := (ProxyData^.Functions shr 1) and $0F; + FunctionMask.4 := ProxyData^.Functions.0; + FunctionMask := FunctionMask or %10000000; // Opcode bits + end else + if FunctionAddress < 9 then + begin + FunctionMask := (ProxyData^.Functions shr 5) and $0F; + FunctionMask := FunctionMask or %10110000; // Opcode bits + end else + if FunctionAddress < 13 then + begin + FunctionMask := (ProxyData^.Functions shr 9) and $0F; + FunctionMask := FunctionMask or %10100000; // Opcode bits + end else + if FunctionAddress < 21 then + begin + FunctionMask := ProxyData^.Functions shr 13; + FunctionExtendedCode := %11011110 + end + end else + begin + FunctionMask := ProxyData^.Functions shr 21; + FunctionExtendedCode := %11011111 + end; + + // Now create the DCC Packet + if AddressHi and $C0 = $C0 then + begin // UART1_Write_Text('Long Address'+LF); + if FunctionAddress < 13 then + NMRA_DCC_LoadPacket(@DCCPacket, AddressHi, AddressLo, FunctionMask, 0, 0, 3) + else + NMRA_DCC_LoadPacket(@DCCPacket, AddressHi, AddressLo, FunctionExtendedCode, FunctionMask, 0, 4) + end else + begin + if FunctionAddress < 13 then + NMRA_DCC_LoadPacket(@DCCPacket, AddressLo, FunctionMask, 0, 0, 0, 3) + else + NMRA_DCC_LoadPacket(@DCCPacket, AddressLo, FunctionExtendedCode, FunctionMask, 0, 0, 4) + end; + + NMRA_DCC_QueuePacket(@Track, @DCCPacket, False); +end; + +function GetProxyData(Node: PNMRAnetNode): PDccProxyData; +begin + Result := nil; + if Node <> nil then + Result := PDccProxyData( Node^.RAMAddress); +end; + +// ***************************************************************************** +// procedure NMRAnetNode_FindFirstNonAllocatedVirtualNode; +// +// Parameters: +// +// Result: +// +// Description: +// READ ME: +// Currently this uses a dog slow search. +// ***************************************************************************** +function FindFirstNonDCCAllocatedNode: PNMRAnetNode; +var + i: Integer; + DCCProxyData: PDccProxyData; +begin + Result := nil; + i := Nodes.AllocatedCount - 1; + while (i > -1) do + begin + if NMRAnetNode_TestStateFlag(Nodes.AllocatedList[i], NS_VIRTUAL) then + begin + DCCProxyData := GetProxyData(Nodes.AllocatedList[i]); + if DCCProxyData^.State and PS_DCC_ADDRESS_ALLOCATED = 0 then + begin + Result := Nodes.AllocatedList[i]; + Break; + end + end; + Dec(i); + end; +end; + +// ***************************************************************************** +// Returns The Is Present Attribute about the Address Space +// Node: The Node to write the Configuration Data for +// AddressSpace: The Address Space to return the information about +// +// Result : True if Is Present else False +// ***************************************************************************** +function AppCallback_AddressSpacePresent(Node: PNMRAnetNode; AddressSpace: Byte): Boolean; +begin + if NMRAnetNode_TestStateFlag(Node, NS_VIRTUAL) then + Result := (AddressSpace <= MSI_CDI) and (AddressSpace >= MSI_FDI) + else + Result := (AddressSpace <= MSI_CDI) and (AddressSpace >= MSI_ACDI_USER) +end; + +// ***************************************************************************** +// Returns The Is ReadOnly Attribute about the Address Space +// Node: The Node to write the Configuration Data for +// AddressSpace: The Address Space to return the information about +// +// Result : True if Is ReadOnly else False +// ***************************************************************************** +function AppCallback_AddressSpaceReadOnly(Node: PNMRAnetNode; AddressSpace: Byte): Boolean; +begin + case AddressSpace of + MSI_CDI, + MSI_ALL, + MSI_ACDI_MFG, + MSI_ACDI_USER, // I am not supporting writing to this space, do it through the configuration addresss space + MSI_FDI : Result := True + else + Result := False; + end; +end; + +//****************************************************************************** +// Associates the offset of the EEPROM for the Configuration Data for the Node +//****************************************************************************** +procedure AppCallback_AssignConfigurationAddress(Node: PNMRANetNode; iNode: Word); +begin + // The first node is the Physical Node so this math works, iNode = 0 is the Physical node and al vNodes > 0 for iNode + if NMRAnetNode_TestStateFlag(Node, NS_VIRTUAL) then + Node^.ConfigurationAddress := Generic32BitPointer( MAX_NODE_CFG_DATA + ((iNode - 1) * MAX_VNODE_CFG_DATA)) + else + Node^.ConfigurationAddress := Generic32BitPointer( 0) ; +end; + +//****************************************************************************** +// Returns the overall size of the Configuration Data +//****************************************************************************** +function AppCallback_Configuration_AddressSpaceSize(Node: PNMRAnetNode): Word; +begin + if NMRAnetNode_TestStateFlag(Node, NS_VIRTUAL) then + Result := MAX_VNODE_CFG_DATA + else + Result := MAX_NODE_CFG_DATA +end; + +// ***************************************************************************** +// Writes the Configuration Memory from the App defined storage device +// Node: The Node to write the Configuration Data for +// DataTarget : A pointer memory space to read the Configuration Data to, this could be a Datagram, CAN Bytes, etc. The Length defines how much to write +// StartAddress: Offset from 0x00 in the Configuration Memory to start from +// MaxCount : Maximum number of Bytes to move into the EEPROM +// +// Result : Number of Bytes actually moved in to the DataTarget +// ***************************************************************************** +procedure AppCallback_Configuration_Write(Node: PNMRAnetNode; DataTarget: ^Byte; StartAddress: DWord; MaxCount: Byte); +begin + while _25AAxxxx_Busy(EEPROM_BANK_0) do + Delay_us(10); + _25AAxxxx_Write(EEPROM_BANK_0, Node^.ConfigurationAddress + StartAddress, MaxCount, DataTarget); +end; + +// ***************************************************************************** +// Reads the Configuration Memory from the App defined storage device +// Node: The Node to read the Configuration Data for +// DataTarget : A pointer memory space to write the Configuration Data to, this could be a Datagram, CAN Bytes, etc. The Length defines how much to write +// StartAddress: Offset from 0x00 in the Configuration Memory to start from +// MaxCount : Maximum number of Bytes to move into the DataTarget +// +// Result : Number of Bytes actually moved in to the DataTarget +// ***************************************************************************** +function AppCallback_Configuration_Read(Node: PNMRAnetNode; DataTarget: ^Byte; StartAddress: DWord; MaxCount: Byte): Byte; +begin + while _25AAxxxx_Busy(EEPROM_BANK_0) do + Delay_us(10); + + Result := MaxCount; + _25AAxxxx_Read(EEPROM_BANK_0, Node^.ConfigurationAddress + StartAddress, MaxCount, DataTarget); +end; + +function AppCallback_FDI_AddressSpaceSize(Node: PNMRAnetNode): Word; +begin + if NMRAnetNode_TestStateFlag(Node, NS_VIRTUAL) then + Result := MAX_FDI_ADDRESS_SPACE_SIZE + else + Result := 0; +end; + +procedure AppCallback_FDI_Write(Node: PNMRAnetNode; DataTarget: ^Byte; StartAddress: DWord; MaxCount: Byte); +begin + while _25AAxxxx_Busy(EEPROM_BANK_0) do + Delay_us(10); + _25AAxxxx_Write(EEPROM_BANK_0, Node^.ConfigurationAddress + StartAddress + OFFSET_FDI_DATA, MaxCount, DataTarget); +end; + +function AppCallback_FDI_Read(Node: PNMRAnetNode; DataTarget: ^Byte; StartAddress: DWord; MaxCount: Byte): Byte; +var + i: Integer; +begin + while _25AAxxxx_Busy(EEPROM_BANK_0) do + Delay_us(10); + Result := MaxCount; + _25AAxxxx_Read(EEPROM_BANK_0, Node^.ConfigurationAddress + StartAddress + OFFSET_FDI_DATA, MaxCount, DataTarget); +end; + +//****************************************************************************** +// Associates the Address of the RAM for Volatile Node Data +//****************************************************************************** +procedure AppCallback_AssignRAMAddress(Node: PNMRANetNode; iNode: Word); +begin + Node^.RAMAddress := Generic32BitPointer( @VolatileData[iNode]); +end; + +//****************************************************************************** +// Initialize the VolatileData structure +//****************************************************************************** +procedure NMRAnetAppCallbacks_Initialize; +var + i: Integer; +begin + for i := 0 to MAX_NODE_COUNT - 1 do + begin + VolatileData[i].State := 0; + VolatileData[i].Speed := 0; + VolatileData[i].Functions := 0; + VolatileData[i].MsgFlags := 0; + VolatileData[i].Address := 0; + VolatileData[i].SpeedSteps := 28; // Default + end +end; + +procedure AppCallback_NodeAllocate(Node: PNMRAnetNode); +var + ProxyData: PDccProxyData; +begin + ProxyData := GetProxyData(Node); + ProxyData^.State := 0; + ProxyData^.Address := 0; + ProxyData^.MsgFlags := 0; + ProxyData^.Speed := 0; + ProxyData^.Functions := 0; +end; + +// ***************************************************************************** +// +// ***************************************************************************** +procedure SetProxyNodeDccAddressFlags(Node: PNMRAnetNode; Event: PEventID); +var + TestForSetFlag: Boolean; + ProxyData: PDccProxyData; + Address: Word; +begin + TestForSetFlag := True; + if Event <> nil then + TestForSetFlag := (Event^[0] = $06) and (Event^[1] = $01); + + if TestForSetFlag then + begin + ProxyData := GetProxyData(Node); + if ProxyData^.State and PS_DCC_ADDRESS_ALLOCATED = PS_DCC_ADDRESS_ALLOCATED then + begin + Address := (Event^[4] shl 8) or Event^[5]; + if ProxyData^.Address = Address then + ProxyData^.MsgFlags := ProxyData^.MsgFlags or MSG_SEND_DCC_ADDRESS_ALLOCATED; + end + end +end; + +// ***************************************************************************** +// +// ***************************************************************************** +procedure SetProxyNodeProducerFlags(Node: PNMRAnetNode; EventIndex: Integer); +begin + // This uses the fact that there are hard coded will known Event ID offsets in the Event Arrays + case EventIndex of + EVENT_TRAIN_INDEX : NMRAnetNode_SetProducerEventFlag(Node, EventIndex, EVENT_STATE_VALID); + EVENT_TRAIN_DCC_IDLE_INDEX : begin + if GetProxyData(Node)^.State and PS_DCC_ADDRESS_ALLOCATED = PS_DCC_ADDRESS_ALLOCATED then + NMRAnetNode_SetProducerEventFlag(Node, EventIndex, EVENT_STATE_INVALID) + else + NMRAnetNode_SetProducerEventFlag(Node, EventIndex, EVENT_STATE_VALID); + end; + EVENT_TRAIN_DCC_INUSE_INDEX : begin + if GetProxyData(Node)^.State and PS_DCC_ADDRESS_ALLOCATED = PS_DCC_ADDRESS_ALLOCATED then + NMRAnetNode_SetProducerEventFlag(Node, EventIndex, EVENT_STATE_VALID) + else + NMRAnetNode_SetProducerEventFlag(Node, EventIndex, EVENT_STATE_INVALID); + end + else + NMRAnetNode_SetProducerEventFlag(Node, EventIndex, EVENT_STATE_UNKOWN); + end +end; + + +// ***************************************************************************** +// +// ***************************************************************************** +function AppCallback_ProducerIdentify(Node: PNMRAnetNode; Event: PEventID): Boolean; +var + i, VNodeEventIndex, NodeEventIndex: Integer; + VNodeEvent, NodeEvent: Boolean; +begin + Result := True; // We handle the message + VNodeEventIndex := -1; + NodeEventIndex := -1; + VNodeEvent := NMRAnetUtilities_SupportsVNodeEventAsProducer(Event, VNodeEventIndex); + NodeEvent := NMRAnetUtilities_SupportsEventAsProducer(Event, NodeEventIndex); + for i := 0 to Nodes.AllocatedCount - 1 do + begin + if NMRAnetNode_TestStateFlag(Nodes.AllocatedList[i], NS_VIRTUAL) then + begin + if VNodeEvent then + SetProxyNodeProducerFlags(Nodes.AllocatedList[i], VNodeEventIndex); + SetProxyNodeDccAddressFlags(Nodes.AllocatedList[i], Event); + end else + begin + if NodeEvent then + NMRAnetNode_SetProducerEventFlag(Nodes.AllocatedList[0], NodeEventIndex, EVENT_STATE_UNKOWN); + end + end; +end; + +// ***************************************************************************** +// +// ***************************************************************************** +function AppCallback_ConsumerIdentify(Node: PNMRAnetNode; Event: PEventID): Boolean; +begin + Result := False; // Do the default +end; + +function AppCallback_EventsIdentify: Boolean; +var + j, ProducerIndex: Integer; + Node: PNMRAnetNode; +begin + Result := True; // We handled it + for j := 0 to Nodes.AllocatedCount - 1 do + begin + Node := Nodes.AllocatedList[j]; + if NMRAnetNode_TestStateFlag(Node, NS_VIRTUAL) then + begin + NMRAnetNode_SetConsumerEventFlags(Node, EVENT_STATE_UNKOWN); // Consumers are eaay. + for ProducerIndex := 0 to MAX_VNODE_SUPPORTED_EVENTS_PRODUCED - 1 do // Producers take some work + begin + SetProxyNodeProducerFlags(Node, ProducerIndex); + SetProxyNodeDccAddressFlags(Node, nil); + end + end else + begin + NMRAnetNode_SetProducerEventFlags(Node, EVENT_STATE_UNKOWN); + NMRAnetNode_SetConsumerEventFlags(Node, EVENT_STATE_UNKOWN); + end + end; +end; + +// ***************************************************************************** +// +// ***************************************************************************** +function AppCallback_EventsIdentifyByDest(Node: PNMRAnetNode): Boolean; +var + ProducerIndex: Integer; +begin + Result := True; // We handled it + NMRAnetNode_SetConsumerEventFlags(Node, EVENT_STATE_UNKOWN); // Consumers are eaay. + + if NMRAnetNode_TestStateFlag(Node, NS_VIRTUAL) then + begin + for ProducerIndex := 0 to MAX_VNODE_SUPPORTED_EVENTS_PRODUCED - 1 do // Producers take some work + SetProxyNodeProducerFlags(Node, ProducerIndex); + SetProxyNodeDccAddressFlags(Node, nil); + end else + begin + NMRAnetNode_SetProducerEventFlags(Node, EVENT_STATE_UNKOWN); + NMRAnetNode_SetConsumerEventFlags(Node, EVENT_STATE_UNKOWN); + end; +end; + +// ***************************************************************************** +// +// ***************************************************************************** +procedure AppCallback_TractionControl(Node: PNMRAnetNode; CANBuffer: PCANBuffer); +var + ProxyData: PDccProxyData; + FunctionAddress: DWord; + FunctionValue: Word; + AbsoluteSpeed: real; + SpeedStep: Word; + DCCPacket: TDCCPacket; + AddressHi, AddressLo: Byte; + IsForward: Boolean; +begin + ProxyData := GetProxyData(Node); + AddressHi := (ProxyData^.Address shr 8) and $00FF; // Split the address to make clear when loading bytes + AddressLo := ProxyDAta^.Address and $00FF; + case CANBuffer^.DataBytes[2] and TRACTION_PROTOCOL_MASK of + TRACTION_OLCB : + begin // OLCB Train Protocol + case CANBuffer^.DataBytes[2] and TRACTION_OP_MASK of + TRACTION_OP_SPEED_DIR : + begin + ProxyData^.Speed := (CANBuffer^.DataBytes[3] shl 8) or (CANBuffer^.DataBytes[4]); + IsForward := ProxyData^.Speed and $8000 <> $8000; + AbsoluteSpeed := HalfToFloat(ProxyData^.Speed and not $8000); + case ProxyData^.SpeedSteps of + 14 : begin + AbsoluteSpeed := (14/100) * AbsoluteSpeed; + SpeedStep := Word( AbsoluteSpeed); + SpeedStep := _14_STEP_TABLE[SpeedStep]; + if IsForward then + SpeedStep := SpeedStep or $60 + else + SpeedStep := SpeedStep or $40; + if AddressHi and $C0 = $C0 then + NMRA_DCC_LoadPacket(@DCCPacket, AddressHi, AddressLo, SpeedStep, 0, 0, 3) + else + NMRA_DCC_LoadPacket(@DCCPacket, AddressLo, SpeedStep, 0, 0, 0, 2); + NMRA_DCC_QueuePacket(@Track, @DCCPacket, False); + end; + 28 : begin + AbsoluteSpeed := (28/100) * AbsoluteSpeed; + SpeedStep := Word( AbsoluteSpeed); + SpeedStep := _28_STEP_TABLE[SpeedStep]; + if IsForward then + SpeedStep := SpeedStep or $60 + else + SpeedStep := SpeedStep or $40; + if AddressHi and $C0 = $C0 then + NMRA_DCC_LoadPacket(@DCCPacket, AddressHi, AddressLo, SpeedStep, 0, 0, 3) + else + NMRA_DCC_LoadPacket(@DCCPacket, AddressLo, SpeedStep, 0, 0, 0, 2); + NMRA_DCC_QueuePacket(@Track, @DCCPacket, False); + end; + 128 : begin + if AddressHi and $C0 = $C0 then + begin + AbsoluteSpeed := (127/100) * AbsoluteSpeed; + SpeedStep := Word( AbsoluteSpeed); + if SpeedStep > 0 then + Inc(SpeedStep); // 1 = EStop + if IsForward then + SpeedStep := SpeedStep or $80; + NMRA_DCC_LoadPacket(@DCCPacket, AddressHi, AddressLo, %00111111, SpeedStep, 0, 4); + NMRA_DCC_QueuePacket(@Track, @DCCPacket, False); + end; + end; + end; + end; + TRACTION_OP_E_STOP : + begin + IsForward := ProxyData^.Speed and $8000 <> $8000; + if IsForward then + ProxyData^.Speed := $0000 + else + ProxyData^.Speed := $8000; + case ProxyData^.SpeedSteps of + 14, 28 : + begin + SpeedStep := $01; + if IsForward then + SpeedStep := SpeedStep or $60 + else + SpeedStep := SpeedStep or $40; + if AddressHi and $C0 = $C0 then + NMRA_DCC_LoadPacket(@DCCPacket, AddressHi, AddressLo, SpeedStep, 0, 0, 3) + else + NMRA_DCC_LoadPacket(@DCCPacket, AddressLo, SpeedStep, 0, 0, 0, 2); + NMRA_DCC_QueuePacket(@Track, @DCCPacket, False); + end; + 128 : + begin + SpeedStep := $01; + if IsForward then + SpeedStep := SpeedStep or $80; + NMRA_DCC_LoadPacket(@DCCPacket, AddressHi, AddressLo, %00111111, SpeedStep, 0, 4); + NMRA_DCC_QueuePacket(@Track, @DCCPacket, False); + end; + end + end; + TRACTION_OP_FUNCTION : + begin + FunctionAddress := (DWord( CANBuffer^.DataBytes[3]) shl 16) or (DWord( CANBuffer^.DataBytes[4]) shl 8) or DWord( CANBuffer^.DataBytes[5]); + FunctionValue := (DWord( CANBuffer^.DataBytes[6]) shl 8) or DWord( CANBuffer^.DataBytes[7]); + UpdateFunctionsAndSendDCCMessage(AddressHi, AddressLo, Byte( FunctionAddress), Byte( FunctionValue), DCCPacket, ProxyData); + end; + end; + end; + TRACTION_DCC : + begin // DCC Train Protocol + case CANBuffer^.DataBytes[2] and $0F of + { TRACTION_OP_SPEED_DIR : + begin + ProxyData^.Speed := CANBuffer^.DataBytes[3]; + if AddressHi and $C0 = $C0 then + begin // Extended Address + if CANBuffer^.DataBytes[4] = 128 then + NMRA_DCC_LoadPacket(@DCCPacket, AddressHi, AddressLo, %00111111, ProxyData^.Speed, 0, 4) + else + NMRA_DCC_LoadPacket(@DCCPacket, AddressHi, AddressLo, ProxyData^.Speed, 0, 0, 3); + NMRA_DCC_QueuePacket(@Track, @DCCPacket, False); + end else + begin // Short Address + if CANBuffer^.DataBytes[4] < 128 then // Can't do short address with 128 Step + begin + NMRA_DCC_LoadPacket(@DCCPacket, AddressLo, ProxyData^.Speed, 0, 0, 0, 2); + NMRA_DCC_QueuePacket(@Track, @DCCPacket, False); + end + end; + end; + TRACTION_OP_FUNCTION : + begin + FunctionAddress := (CANBuffer^.DataBytes[4] shl 8) or CANBuffer^.DataBytes[5]; + FunctionValue := CANBuffer^.DataBytes[6]; + case CANBuffer^.DataBytes[3] of + DCC_FUNCTION_28 : UpdateFunctionsAndSendDCCMessage(AddressHi, AddressLo, Byte( FunctionAddress), Byte( FunctionValue), DCCPacket, ProxyData); + DCC_FUNCTION_32k : begin end; // UART1_Write_Text('DCC_FUNCTION_32k'+LF); + end; + end; } + TRACTION_OP_PROXY_MGMT : + begin + case CANBuffer^.DataBytes[3] of + DCC_ALLOCATE_ADDRESS : + begin + ProxyData^.State := ProxyData^.State or PS_DCC_ADDRESS_ALLOCATED; + ProxyData^.MsgFlags := ProxyData^.MsgFlags or MSG_SEND_DCC_ADDRESS_ALLOCATED; // Changed State so notify the system + SetProxyNodeProducerFlags(Node, EVENT_TRAIN_DCC_IDLE_INDEX); // Changed State so notify the system + SetProxyNodeProducerFlags(Node, EVENT_TRAIN_DCC_INUSE_INDEX); // Changed State so notify the system + ProxyData^.SpeedSteps := CANBuffer^.DataBytes[4]; // TO DO: NEED TO WRITE TO CONFIGURATION + ProxyData^.Address := Word ((CANBuffer^.DataBytes[5] shl 8)) or CANBuffer^.DataBytes[6]; // This is in NMRA DCC format for short/long address + // if FindFirstNonDCCAllocatedNode = nil then + // NMRAnetNode_Allocate; // Need a proxy that is free to allocate + end; + DCC_DEALLOCATE_ADDRESS : + begin + ProxyData^.State := ProxyData^.State and not PS_DCC_ADDRESS_ALLOCATED; + ProxyData^.MsgFlags := ProxyData^.MsgFlags and not MSG_SEND_DCC_ADDRESS_ALLOCATED; // Changed State so notify the system + SetProxyNodeProducerFlags(Node, EVENT_TRAIN_DCC_IDLE_INDEX); // Changed State so notify the system + SetProxyNodeProducerFlags(Node, EVENT_TRAIN_DCC_INUSE_INDEX); // Changed State so notify the system + end; + end; + end; + end; + end; + end +end; + +// ***************************************************************************** +// +// ***************************************************************************** +function AppCallback_StateMachine(Node: PNMRAnetNode; CANBuffer: PCANBuffer; DataBytesPtr: PCAN_DataBytes): Boolean; +var + ProxyData: PDccProxyData; +begin + // We are in a CAN Lock block already + Result := False; + ProxyData := GetProxyData(Node); + + // Handle the oddball DCC Address Event that can come and go + if ProxyData^.MsgFlags and MSG_SEND_DCC_ADDRESS_ALLOCATED = MSG_SEND_DCC_ADDRESS_ALLOCATED then + begin + DataBytesPtr^[0] := $06; + DataBytesPtr^[1] := $01; + DataBytesPtr^[2] := $00; + DataBytesPtr^[3] := $00; + DataBytesPtr^[4] := (ProxyData^.Address shr 8) and $00FF; + DataBytesPtr^[5] := ProxyData^.Address and $00FF; + DataBytesPtr^[6] := $00; + DataBytesPtr^[7] := $01; + if TransmitNMRABusLayerMsg(Node, CANBUffer, MTI_PRODUCER_IDENTIFIED_SET, 0, 8, DataBytesPtr, False) then + begin + ProxyData^.MsgFlags := ProxyData^.MsgFlags and not MSG_SEND_DCC_ADDRESS_ALLOCATED; + Result := True; + end + end; +end; + +end. \ No newline at end of file Added: trunk/prototypes/mikroPascal/dsPIC33EP256_CommandStation/NMRAnetAppDefines.mpas =================================================================== --- trunk/prototypes/mikroPascal/dsPIC33EP256_CommandStation/NMRAnetAppDefines.mpas (rev 0) +++ trunk/prototypes/mikroPascal/dsPIC33EP256_CommandStation/NMRAnetAppDefines.mpas 2013-03-17 00:28:43 UTC (rev 3048) @@ -0,0 +1,426 @@ +unit NMRAnetAppDefines; + +// ****************************************************************************** +// +// * 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 +// +// * Description: +// Implements program specific information such as Consumer/Producer EventIDs, +// Buffer allocation sizes, CDI and ACDI Information, Protocol Support IDs, vNode +// counts, etc. +// +// AppDefines for the Mustangpeak Command Station +// +// ****************************************************************************** +uses + NMRAnetDefinesShared; + +{$I Options.inc} + +// ************************************************************************************************************************************************************** +// Virtual Nodes +// ************************************************************************************************************************************************************** + +const + MAX_NODE_COUNT = 57; // The number of Physical and vNodes this physical node support. Note that these nodes are defin... [truncated message content] |