#include #include #include #include "ti_drivers_config.h" #include "FreeRTOS.h" #include "FreeRTOS_IP.h" #include "FreeRTOS_IP_private.h" #include "FreeRTOSIPConfigDefaults.h" #include "NetworkBufferManagement.h" #include "task.h" #include "constants.h" #include "ethernet.h" #include "uart_debug.h" #include "adc_rand.h" #include "main.h" /* The setup is done using driverlib to use the FreeRTOS+TCP port. This ensures that the interface operates in a consistent fashion and also allows for multiple IP addresses to be assigned using FreeRTOS multi. In the vReleaseNetworkBufferAndDescriptor() function in the BufferAllocation1.c file, I had to add the following line to check for a null pointer. if(pxNetworkBuffer == NULL) return; This is not a zero copy interface, but the code can be updated to create a zero-copy interface. REFERENCES: https://e2e.ti.com/support/microcontrollers/other/f/908/t/534375?Reading-MAC-address-using-FlashUserGet-function file:///C:/ti/simplelink_msp432e4_sdk_4_20_00_12/docs/driverlib/msp432e4/api_guide/html/group__emac__api.html https://www.freertos.org/FreeRTOS-Plus/FreeRTOS_Plus_TCP/Embedded_Ethernet_Porting.html https://e2e.ti.com/support/microcontrollers/other/f/908/t/498224?TM4C129-Tiva-C-Series-Ethernet-Rj45-cable-link-disconnection-interrupt- https://e2e.ti.com/support/microcontrollers/msp430/f/166/t/898167 https://e2e.ti.com/support/microcontrollers/msp430/f/166/t/782195?MSP432E401Y-ICMP-ping-checksum-is-set-to-0 https://github.com/FreeRTOS/FreeRTOS/issues/87 https://www.freertos.org/FreeRTOS_Support_Forum_Archive/June_2018/freertos_FreeRTOS_TCP_and_FreeRTOS_NetworkDown_b3d90820j.html https://forums.freertos.org/t/freertos-tcp-frame-check-sequence/7269/2 https://www.freertos.org/FreeRTOS_Support_Forum_Archive/May_2016/freertos_TCP_zero_copy_implementation_486219ddj.html */ // Turn on this define for debugging to print the Ethernet RX and TX events // #define PRINT_ETHERNET_RX_TX //-------------------------------------------------------------------- // DMA descriptors tEMACDMADescriptor g_psRxDescriptor[NUM_TX_DESCRIPTORS]; tEMACDMADescriptor g_psTxDescriptor[NUM_RX_DESCRIPTORS]; uint32_t g_ui32RxDescIndex; uint32_t g_ui32TxDescIndex; // transmit and receive buffers uint8_t g_ppui8RxBuffer[NUM_RX_DESCRIPTORS][RX_BUFFER_SIZE]; // task handle indicating that the Ethernet has received an RX packet TaskHandle_t xTaskToNotifyEthernetRX = NULL; BaseType_t xHigherPriorityTaskWoken = pdFALSE; // MAC address for the stack uint8_t pui8MACAddr[6]; // name of the device char DEV_NAME[MAX_NAME_LLMNR]; #define MAX_BUFF_SIZ 1500 uint8_t ethBuffer[MAX_BUFF_SIZ]; // buffer uint32_t i32FrameLen_received; // length of received frame #define ETH_UP_DELAY_MS 2000 // check every 1 s to see if the network is up or down // indicates whether the network is up or down bool networkUP = false; //-------------------------------------------------------------------- // Call this function to setup the Ethernet interface // Using FreeRTOS, the hardware is setup by the network stack. void setup_emac() { uint32_t ui32User0, ui32User1, ui32Loop; // Read the MAC address from internal flash. Bit[23:0] are stored in user register0, and Bit[47:24] are stored in user register1. // The MAC address can be loaded from an external IC or can be loaded from the internal registers if the registers are not zero. FlashUserGet(&ui32User0, &ui32User1); if((ui32User0 == 0xffffffff) || (ui32User1 == 0xffffffff)) { // TODO: load from external IC over the I2C bus } // re-arrange the MAC address pui8MACAddr[0] = ((ui32User0 >> 0) & 0xff); pui8MACAddr[1] = ((ui32User0 >> 8) & 0xff); pui8MACAddr[2] = ((ui32User0 >> 16) & 0xff); pui8MACAddr[3] = ((ui32User1 >> 0) & 0xff); pui8MACAddr[4] = ((ui32User1 >> 8) & 0xff); pui8MACAddr[5] = ((ui32User1 >> 16) & 0xff); // enable and reset the ethernet modules SysCtlPeripheralEnable(SYSCTL_PERIPH_EMAC0); SysCtlPeripheralEnable(SYSCTL_PERIPH_EPHY0); SysCtlPeripheralReset(SYSCTL_PERIPH_EMAC0); SysCtlPeripheralReset(SYSCTL_PERIPH_EPHY0); // wait for the MAC to be ready while(!SysCtlPeripheralReady(SYSCTL_PERIPH_EMAC0)){} // configure the internal PHY EMACPHYConfigSet(EMAC0_BASE, (EMAC_PHY_TYPE_INTERNAL | EMAC_PHY_INT_MDIX_EN | EMAC_PHY_AN_100B_T_FULL_DUPLEX)); // reset the MAC to latch the configuration EMACReset(EMAC0_BASE); // init the EMAC EMACInit(EMAC0_BASE, get_clock_speed(), EMAC_BCONFIG_MIXED_BURST | EMAC_BCONFIG_PRIORITY_FIXED, 4, 4, 0); // set the MAC configuration options /* Since the checksum is computed in the hardware using EMAC_CONFIG_CHECKSUM_OFFLOAD, there is also a need to define these in the FreeRTOS+TCP as well. See the xNetworkInterfaceOutput function below as well. #define ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM 1 #define ipconfigDRIVER_INCLUDED_RX_IP_CHECKSUM 1 */ EMACConfigSet(EMAC0_BASE, (EMAC_CONFIG_FULL_DUPLEX | EMAC_CONFIG_CHECKSUM_OFFLOAD | EMAC_CONFIG_7BYTE_PREAMBLE | EMAC_CONFIG_IF_GAP_96BITS | EMAC_CONFIG_USE_MACADDR0 | EMAC_CONFIG_SA_FROM_DESCRIPTOR | EMAC_CONFIG_BO_LIMIT_1024), (EMAC_MODE_RX_STORE_FORWARD | EMAC_MODE_TX_STORE_FORWARD | EMAC_MODE_TX_THRESHOLD_64_BYTES | EMAC_MODE_RX_THRESHOLD_64_BYTES), 0); // DMA descriptors init InitDescriptors(EMAC0_BASE); // program MAC address EMACAddrSet(EMAC0_BASE, 0, pui8MACAddr); // Set address filtering EMACAddrFilterSet(EMAC0_BASE, 0, EMAC_FILTER_ADDR_ENABLE | EMAC_FILTER_SOURCE_ADDR); // Set MAC filtering options if required EMACFrameFilterSet(EMAC0_BASE, EMAC_FRMFILTER_PASS_ADDR_CTRL | EMAC_FRMFILTER_BROADCAST); // Clear any interrupts EMACIntClear(EMAC0_BASE, EMACIntStatus(EMAC0_BASE, false)); // indicate that the receive descriptors are available to the DMA to start the receive processing for(ui32Loop = 0; ui32Loop < NUM_RX_DESCRIPTORS; ui32Loop++) { g_psRxDescriptor[ui32Loop].ui32CtrlStatus |= DES0_RX_CTRL_OWN; } // Enable the Ethernet MAC transmitter and receiver EMACTxEnable(EMAC0_BASE); EMACRxEnable(EMAC0_BASE); // enable the Ethernet interrupt IntPrioritySet(INT_EMAC0, 0x20); // (0x01 << 5) into the last three bits for Cortex M4F // register the interrupt handler for the Ethernet MAC EMACIntRegister(EMAC0_BASE, EthernetIntHandler); // enable the interrupts IntEnable(INT_EMAC0); // enable the Ethernet receive interrupt EMACIntEnable(EMAC0_BASE, EMAC_INT_RECEIVE); } // end // This function only turns off the Ethernet EMAC if it is not required. This function does not turn off any // of the tasks that process the Ethernet packets. void off_emac() { EMACIntClear(EMAC0_BASE, EMACIntStatus(EMAC0_BASE, false)); IntDisable(INT_EMAC0); EMACIntUnregister(EMAC0_BASE); EMACTxDisable(EMAC0_BASE); EMACRxDisable(EMAC0_BASE); SysCtlPeripheralDisable(SYSCTL_PERIPH_EMAC0); SysCtlPeripheralDisable(SYSCTL_PERIPH_EPHY0); SysCtlPeripheralDisable(SYSCTL_PERIPH_EMAC0); SysCtlPeripheralDisable(SYSCTL_PERIPH_EPHY0); } // end // Init the DMA descriptors void InitDescriptors(uint32_t ui32Base) { uint32_t ui32Loop; // init transmit for(ui32Loop = 0; ui32Loop < NUM_TX_DESCRIPTORS; ui32Loop++) { g_psTxDescriptor[ui32Loop].ui32Count = DES1_TX_CTRL_SADDR_INSERT; g_psTxDescriptor[ui32Loop].DES3.pLink = (ui32Loop == (NUM_TX_DESCRIPTORS - 1)) ? g_psTxDescriptor : &g_psTxDescriptor[ui32Loop + 1]; g_psTxDescriptor[ui32Loop].ui32CtrlStatus = (DES0_TX_CTRL_LAST_SEG | DES0_TX_CTRL_FIRST_SEG | DES0_TX_CTRL_INTERRUPT | DES0_TX_CTRL_CHAINED | DES0_TX_CTRL_IP_ALL_CKHSUMS); } // init receive for(ui32Loop = 0; ui32Loop < NUM_RX_DESCRIPTORS; ui32Loop++) { g_psRxDescriptor[ui32Loop].ui32CtrlStatus = 0; g_psRxDescriptor[ui32Loop].ui32Count = (DES1_RX_CTRL_CHAINED | (RX_BUFFER_SIZE << DES1_RX_CTRL_BUFF1_SIZE_S)); g_psRxDescriptor[ui32Loop].pvBuffer1 = g_ppui8RxBuffer[ui32Loop]; g_psRxDescriptor[ui32Loop].DES3.pLink = (ui32Loop == (NUM_RX_DESCRIPTORS - 1)) ? g_psRxDescriptor : &g_psRxDescriptor[ui32Loop + 1]; } // set the pointers in the hardware EMACRxDMADescriptorListSet(ui32Base, g_psRxDescriptor); EMACTxDMADescriptorListSet(ui32Base, g_psTxDescriptor); // start from the beginning of the descriptor chains g_ui32RxDescIndex = 0; g_ui32TxDescIndex = NUM_TX_DESCRIPTORS - 1; } // end // Transmit a packet - call this function from the network stack // pui8Buf = the buffer // i32BufLen = length of the buffer uint32_t PacketTransmit(uint8_t *pui8Buf, uint32_t i32BufLen) { #ifdef PRINT_ETHERNET_RX_TX vLoggingPrintf("TX:%d\r\n", i32BufLen); #endif if(pui8Buf==NULL) vLoggingPrintf("NullTX\r\n"); // Move to the next descriptor. g_ui32TxDescIndex++; if(g_ui32TxDescIndex == NUM_TX_DESCRIPTORS) { g_ui32TxDescIndex = 0; } // Fill in the packet size and pointer, and tell the transmitter to start work g_psTxDescriptor[g_ui32TxDescIndex].ui32Count = i32BufLen; g_psTxDescriptor[g_ui32TxDescIndex].pvBuffer1 = pui8Buf; g_psTxDescriptor[g_ui32TxDescIndex].ui32CtrlStatus = (DES0_TX_CTRL_LAST_SEG | DES0_TX_CTRL_FIRST_SEG | DES0_TX_CTRL_INTERRUPT | DES0_TX_CTRL_IP_ALL_CKHSUMS | DES0_TX_CTRL_CHAINED | DES0_TX_CTRL_OWN); // Tell the DMA to reaquire the descriptor and send the packet EMACTxDMAPollDemand(EMAC0_BASE); // return the number of bytes sent since by this time we have been successful return(i32BufLen); } // end // Interrupt handler void EthernetIntHandler(void) { uint32_t ui32Temp; ui32Temp = EMACIntStatus(EMAC0_BASE, true); // Check to see if an RX interrupt has occurred if(ui32Temp & EMAC_INT_RECEIVE) { ProcessReceivedPacket(); } EMACIntClear(EMAC0_BASE, ui32Temp); portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); } // end // Function to process the received packet uint32_t ProcessReceivedPacket(void) { uint32_t i32FrameLen; // By default, we assume we got a bad frame. i32FrameLen = 0; // Make sure that we own the receive descriptor. if(!(g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus & DES0_RX_CTRL_OWN)) { // Does it have a valid frame? if(!(g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus & DES0_RX_STAT_ERR)) { if(g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus & DES0_RX_STAT_LAST_DESC) { // get the frame length i32FrameLen = ((g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus & DES0_RX_STAT_FRAME_LENGTH_M) >> DES0_RX_STAT_FRAME_LENGTH_S); // call the function that sends the data to the task ApplicationProcessFrame(i32FrameLen, g_psRxDescriptor[g_ui32RxDescIndex].pvBuffer1, g_ui32RxDescIndex); } } // Now that we are finished dealing with this descriptor, hand // it back to the hardware. g_psRxDescriptor[g_ui32RxDescIndex].ui32CtrlStatus = DES0_RX_CTRL_OWN; // Move on to the next descriptor in the chain ready for the next RX packet g_ui32RxDescIndex++; if(g_ui32RxDescIndex == NUM_RX_DESCRIPTORS) { g_ui32RxDescIndex = 0; } } // end if // ensure that the task is called portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); // return the frame length return(i32FrameLen); } // end // This function passes the framelength and the buffer into the FreeRTOS task. // The function is called from the ISR. void ApplicationProcessFrame(uint32_t i32FrameLen, uint8_t *pui8Buf, uint32_t index ) { // copy the buffer and the length of the frame i32FrameLen_received = i32FrameLen; if(i32FrameLen == 0 || pui8Buf == NULL) return; memcpy(ethBuffer, pui8Buf, i32FrameLen); // Signal to the consumer task that data has been received... // this is called from an ISR. vTaskNotifyGiveFromISR( xTaskToNotifyEthernetRX, &xHigherPriorityTaskWoken); } // end //------------------------------------------------------------- // FREERTOS+TCP FUNCTIONS //------------------------------------------------------------- // Call this function to setup the Ethernet Interrupt handler task. // The task must be called once on startup and never stopped. void setup_ethernet_tasks() { xTaskCreate(prvEMACDeferredInterruptHandlerTask, "EthInt", 1000, NULL, ipconfigIP_TASK_PRIORITY, &xTaskToNotifyEthernetRX ); } // end // FreeRTOS task that handles the interrupt using task handle xTaskToNotifyEthernetRX void prvEMACDeferredInterruptHandlerTask( void *pvParameters ) { NetworkBufferDescriptor_t *pxDescriptor = NULL; IPStackEvent_t xRxEvent; for(;;) { ulTaskNotifyTake( pdTRUE, portMAX_DELAY ); #ifdef PRINT_ETHERNET_RX_TX vLoggingPrintf("RX:%d\r\n", i32FrameLen_received); #endif if(i32FrameLen_received == 0) continue; pxDescriptor = pxGetNetworkBufferWithDescriptor(i32FrameLen_received-4, 0 ); if (pxDescriptor == NULL) continue; memcpy(pxDescriptor->pucEthernetBuffer, ethBuffer, i32FrameLen_received); pxDescriptor->xDataLength = i32FrameLen_received-4; // frame length does not include the checksum at the end if( eConsiderFrameForProcessing( pxDescriptor->pucEthernetBuffer ) == eProcessBuffer ) { xRxEvent.eEventType = eNetworkRxEvent; xRxEvent.pvData = ( void * ) pxDescriptor; if( xSendEventStructToIPTask( &xRxEvent, 0 ) == pdFALSE ) { vReleaseNetworkBufferAndDescriptor( pxDescriptor ); iptraceETHERNET_RX_EVENT_LOST(); } else { iptraceNETWORK_INTERFACE_RECEIVE(); } } else { vReleaseNetworkBufferAndDescriptor( pxDescriptor ); } } // end for } // end // Call this function before starting the scheduler and after the MAC address and device name has been loaded void setup_freertos_tcp() { // for now, the fallback addresses are given here, but these can be stored in flash and then read static const uint8_t ucIPAddress[ 4 ] = { 192, 168, 1, 171 }; static const uint8_t ucNetMask[ 4 ] = { 255, 255, 255, 0 }; static const uint8_t ucGatewayAddress[ 4 ] = { 192, 168, 1, 1 }; static const uint8_t ucDNSServerAddress[ 4 ] = { 208, 67, 222, 222 }; // setup the tasks setup_ethernet_tasks(); // setup the device name (load serial number from flash) setup_device_name(DEV_NAME_DEFAULT); // init the network stack FreeRTOS_IPInit( ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, pui8MACAddr); } // end // Function that sets pulNumber to a random number, and then returns pdTRUE. // If the random number could not be obtained, then the function will return pdFALSE. BaseType_t xApplicationGetRandomNumber( uint32_t * pulNumber ) { *pulNumber = 0; uint32_t num = obtain_rand32(); if (num == 0) return pdFALSE; *pulNumber = num; return pdTRUE; } // end // Function that returns a random number for TCP. This is taken to be a true random number. uint32_t ulApplicationGetNextSequenceNumber( uint32_t ulSourceAddress, uint16_t usSourcePort, uint32_t ulDestinationAddress, uint16_t usDestinationPort ) { uint32_t pulNumber = 0; xApplicationGetRandomNumber(&pulNumber); return pulNumber; } // end // Function to obtain random number UBaseType_t uxRand() { uint32_t num = obtain_rand32(); return num; } // end // Function called when the network connects or disconnects void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent ) { uint32_t ulIPAddress, ulNetMask, ulGatewayAddress, ulDNSServerAddress; static BaseType_t xNetworkTasksAlreadyCreated = pdFALSE; char cBuffer[ 16 ]; if( eNetworkEvent == eNetworkUp ) { if( xNetworkTasksAlreadyCreated == pdFALSE ) { // Create any necessary tasks here when the network is up // TODO: // Set a flag to indicate that the tasks do not need to be created again xNetworkTasksAlreadyCreated = pdTRUE; } FreeRTOS_GetAddressConfiguration( &ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress ); FreeRTOS_inet_ntoa( ulIPAddress, cBuffer ); vLoggingPrintf( "IP Address: %s\r\n", cBuffer ); FreeRTOS_inet_ntoa( ulNetMask, cBuffer ); vLoggingPrintf( "Subnet Mask: %s\r\n", cBuffer ); FreeRTOS_inet_ntoa( ulGatewayAddress, cBuffer ); vLoggingPrintf( "Gateway IP Address: %s\r\n", cBuffer ); FreeRTOS_inet_ntoa( ulDNSServerAddress, cBuffer ); vLoggingPrintf( "DNS server IP Address: %s\r\n", cBuffer ); } // end if else if( eNetworkEvent == eNetworkDown ) { xNetworkTasksAlreadyCreated = pdFALSE; // clear a flag to indicate that the tasks needs to be created again // TODO: Stop or block any running tasks } // end if } // end // Function that indicates there is a ping response // Also check the code in IPTraceMacroDefaults void pingReply( uint32_t ulIPAddress ) { char cBuffer[ 16 ]; FreeRTOS_inet_ntoa( ulIPAddress, cBuffer ); vLoggingPrintf( "Ping response to: %s\r\n", cBuffer ); } // end // Function that returns pdTRUE if the pcName matches the LLMNR node name BaseType_t xApplicationDNSQueryHook( const char * pcName ) { if(strcmp(pcName, DEV_NAME)) return pdTRUE; return pdFALSE; } // end // Hook to return a human-readable name const char *pcApplicationHostnameHook( void ) { const char *name; if (DEV_NAME[0] != 0) { name = DEV_NAME; } else { name = DEV_NAME_DEFAULT; } vLoggingPrintf("hostname: %s\r\n", DEV_NAME); return name; } // end // Call this function to assign the device name before the network stack begins void setup_device_name(char *name) { memset(DEV_NAME,0,sizeof(DEV_NAME)); strncpy(DEV_NAME, name, MAX_NAME_LLMNR-1); } // end // Network initialization is already done outside of this function BaseType_t xNetworkInterfaceInitialise( void ) { if(networkUP == true) return pdTRUE; return pdFALSE; } // end // Function to output packets to the network BaseType_t xNetworkInterfaceOutput( NetworkBufferDescriptor_t * const pxDescriptor, BaseType_t xReleaseAfterSend ) { taskENTER_CRITICAL(); #if ( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 ) // this is required if the network hardware computes the checksum ProtocolPacket_t * pxPacket; pxPacket = ( ProtocolPacket_t * ) ( pxDescriptor->pucEthernetBuffer ); if( pxPacket->xICMPPacket.xIPHeader.ucProtocol == ( uint8_t ) ipPROTOCOL_ICMP ) { pxPacket->xICMPPacket.xICMPHeader.usChecksum = ( uint16_t ) 0u; } #endif PacketTransmit(pxDescriptor->pucEthernetBuffer, (uint32_t)pxDescriptor->xDataLength); // transmit iptraceNETWORK_INTERFACE_TRANSMIT(); // log the data transmit if( xReleaseAfterSend == pdTRUE ) // release the buffer if requested { vReleaseNetworkBufferAndDescriptor( pxDescriptor ); } taskEXIT_CRITICAL(); return pdTRUE; } // end //----------------------------------------------------------------------------------------------------- // Network interface UP or DOWN tasks //----------------------------------------------------------------------------------------------------- // Function to check and see if the network is up or down by polling a register in the Ethernet driver. // Apparently there is no other way to do this other than polling. bool is_network_up() { uint8_t ui8PHYAddr = 0; // refers to the internal PHY if((EMACPHYRead(EMAC0_BASE, ui8PHYAddr, EPHY_BMSR) & EPHY_BMSR_LINKSTAT) == 0) { return false; // link is not up } return true; // link is up } // end // FreeRTOS task to check and see if the link is up or down by polling an EMAC register. // This task does not have to run if the EMAC is physically turned off. void checkLinkUpOrDownTask( void *pvParameters ) { bool check = false; for(;;) { vTaskDelay(pdMS_TO_TICKS(ETH_UP_DELAY_MS)); taskENTER_CRITICAL(); check = is_network_up(); taskEXIT_CRITICAL(); if(networkUP==false && check==true) { vLoggingPrintf("LINK UP\r\n"); networkUP = true; } else if (networkUP==true && check==false) { // FreeRTOS will poll xNetworkInterfaceInitialise() to check if the network is up // after FreeRTOS_NetworkDown() is called, so there is no corresponding FreeRTOS_NetworkUp() function... networkUP = false; FreeRTOS_NetworkDown(); vLoggingPrintf("LINK DOWN\r\n"); } } } // end // Task handle for task that checks if the network is up or down TaskHandle_t xHandleCheckLinkUpOrDown; // Call this function once only on startup void setup_network_initial() { xTaskCreate( checkLinkUpOrDownTask, RTOS_NET_UP_DOWN_TASK_NAME, RTOS_NET_UP_DOWN_TASK_SIZE, NULL, tskIDLE_PRIORITY, & xHandleCheckLinkUpOrDown ); if (is_network_up()) networkUP = true; // set the initial state else networkUP = false; } // end // Call this network function to physically turn on the EMAC from external task. void turn_on_network() { setup_emac(); // turn on the physical hardware if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING) // required check { vTaskResume( xHandleCheckLinkUpOrDown ); } } // end // Call this function to turn off the EMAC from an external task. void turn_off_network() { FreeRTOS_NetworkDown(); if (xTaskGetSchedulerState() == taskSCHEDULER_RUNNING) // required check { vTaskSuspend( xHandleCheckLinkUpOrDown ); } off_emac(); // turn off the physical hardware } // end //----------------------------------------------------------------------------------------------------- // For BufferAllocation_1.c //----------------------------------------------------------------------------------------------------- #define BUFFER_SIZE ( ipTOTAL_ETHERNET_FRAME_SIZE + ipBUFFER_PADDING ) #define BUFFER_SIZE_ROUNDED_UP ( ( BUFFER_SIZE + 7 ) & ~0x07UL ) static uint8_t ucBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ][ BUFFER_SIZE_ROUNDED_UP ]; void vNetworkInterfaceAllocateRAMToBuffers( NetworkBufferDescriptor_t pxNetworkBuffers[ ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS ] ) { BaseType_t x; for( x = 0; x < ipconfigNUM_NETWORK_BUFFER_DESCRIPTORS; x++ ) { /* pucEthernetBuffer is set to point ipBUFFER_PADDING bytes in from the beginning of the allocated buffer. */ pxNetworkBuffers[ x ].pucEthernetBuffer = &( ucBuffers[ x ][ ipBUFFER_PADDING ] ); /* The following line is also required, but will not be required in future versions. */ *( ( uint32_t * ) &ucBuffers[ x ][ 0 ] ) = ( uint32_t ) &( pxNetworkBuffers[ x ] ); } } // end //-----------------------------------------------------------------------------------------------------