static status_t eth_send(const void *buf, size_t len) { status_t err; __IO ETH_DMADescTypeDef *DmaTxDesc; LTRACEF("buf %p, len %zu\n", buf, len); DmaTxDesc = eth.EthHandle.TxDesc; /* is the buffer available? */ if ((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != 0) { LTRACEF("tx buffer not available\n"); err = ERR_IO; goto error; } uint8_t *buffer = (uint8_t *)(DmaTxDesc->Buffer1Addr); memcpy(buffer, buf, len); HAL_StatusTypeDef e = HAL_ETH_TransmitFrame(ð.EthHandle, len); err = (e == HAL_OK) ? NO_ERROR : ERR_IO; error: /* When Transmit Underflow flag is set, clear it and issue a Transmit Poll Demand to resume transmission */ if ((eth.EthHandle.Instance->DMASR & ETH_DMASR_TUS) != 0) { /* Clear TUS ETHERNET DMA flag */ eth.EthHandle.Instance->DMASR = ETH_DMASR_TUS; /* Resume DMA transmission*/ eth.EthHandle.Instance->DMATPDR = 0; } return err; }
/** * @brief This function should do the actual transmission of the packet. The packet is * contained in the pbuf that is passed to the function. This pbuf * might be chained. * * @param netif the lwip network interface structure for this ethernetif * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type) * @return ERR_OK if the packet could be sent * an err_t value if the packet couldn't be sent * * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to * strange results. You might consider waiting for space in the DMA queue * to become available since the stack doesn't retry to send a packet * dropped because of memory failure (except for the TCP timers). */ static err_t low_level_output( struct netif *netif, struct pbuf *p ) { err_t errval; struct pbuf *q; uint8_t *buffer = (uint8_t *) ( EthHandle.TxDesc->Buffer1Addr ); __IO ETH_DMADescTypeDef *DmaTxDesc; uint32_t framelength = 0; uint32_t bufferoffset = 0; uint32_t byteslefttocopy = 0; uint32_t payloadoffset = 0; DmaTxDesc = EthHandle.TxDesc; bufferoffset = 0; /* copy frame from pbufs to driver buffers */ for ( q = p; q != NULL; q = q->next ) { /* Is this buffer available? If not, goto error */ if ( ( DmaTxDesc->Status & ETH_DMATXDESC_OWN ) != (uint32_t) RESET ) { errval = ERR_USE; goto error; } /* Get bytes in current lwIP buffer */ byteslefttocopy = q->len; payloadoffset = 0; /* Check if the length of data to copy is bigger than Tx buffer size*/ while ( ( byteslefttocopy + bufferoffset ) > ETH_TX_BUF_SIZE ) { /* Copy data to Tx buffer*/ memcpy( (uint8_t *) ( (uint8_t *) buffer + bufferoffset ), (uint8_t *) ( (uint8_t *) q->payload + payloadoffset ), ( ETH_TX_BUF_SIZE - bufferoffset ) ); /* Point to next descriptor */ DmaTxDesc = (ETH_DMADescTypeDef *) ( DmaTxDesc->Buffer2NextDescAddr ); /* Check if the buffer is available */ if ( ( DmaTxDesc->Status & ETH_DMATXDESC_OWN ) != (uint32_t) RESET ) { errval = ERR_USE; goto error; } buffer = (uint8_t *) ( DmaTxDesc->Buffer1Addr ); byteslefttocopy = byteslefttocopy - ( ETH_TX_BUF_SIZE - bufferoffset ); payloadoffset = payloadoffset + ( ETH_TX_BUF_SIZE - bufferoffset ); framelength = framelength + ( ETH_TX_BUF_SIZE - bufferoffset ); bufferoffset = 0; } /* Copy the remaining bytes */ memcpy( (uint8_t *) ( (uint8_t *) buffer + bufferoffset ), (uint8_t *) ( (uint8_t *) q->payload + payloadoffset ), byteslefttocopy ); bufferoffset = bufferoffset + byteslefttocopy; framelength = framelength + byteslefttocopy; } /* Prepare transmit descriptors to give to DMA */ HAL_ETH_TransmitFrame( &EthHandle, framelength ); num_ethernet_tx_msg++; errval = ERR_OK; error: /* When Transmit Underflow flag is set, clear it and issue a Transmit Poll Demand to resume transmission */ if ( ( EthHandle.Instance->DMASR & ETH_DMASR_TUS ) != (uint32_t) RESET ) { /* Clear TUS ETHERNET DMA flag */ EthHandle.Instance->DMASR = ETH_DMASR_TUS; /* Resume DMA transmission*/ EthHandle.Instance->DMATPDR = 0; } return errval; }
BaseType_t xNetworkInterfaceOutput( xNetworkBufferDescriptor_t * const pxDescriptor, BaseType_t xReleaseAfterSend) { uint8_t *buffer = (uint8_t *) (heth_global.TxDesc->Buffer1Addr); __IO ETH_DMADescTypeDef *DmaTxDesc; uint32_t framelength = 0; uint32_t byteslefttocopy = 0; uint32_t payloadoffset = 0; DmaTxDesc = heth_global.TxDesc; uint8_t errval; /* copy frame from pbufs to driver buffers */ /* Is this buffer available? If not, goto error */ if ((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != (uint32_t) RESET) { errval = pdFAIL; goto error; } #if( ipconfigDRIVER_INCLUDED_TX_IP_CHECKSUM != 0 ) { ProtocolPacket_t *pxPacket; /* If the peripheral must calculate the checksum, it wants the protocol checksum to have a value of zero. */ pxPacket = (ProtocolPacket_t *) (pxDescriptor->pucEthernetBuffer); if (pxPacket->xICMPPacket.xIPHeader.ucProtocol == ipPROTOCOL_ICMP) { pxPacket->xICMPPacket.xICMPHeader.usChecksum = (uint16_t) 0u; } } #endif /* Get bytes in current lwIP buffer */ byteslefttocopy = pxDescriptor->xDataLength; framelength = byteslefttocopy; // copy of frame length payloadoffset = 0; /* Check if the length of data to copy is bigger than Tx buffer size*/ while ((byteslefttocopy) > ETH_TX_BUF_SIZE) { /* Copy data to Tx buffer*/ memcpy((uint8_t*) ((uint8_t*) buffer), (uint8_t*) ((uint8_t*) pxDescriptor->pucEthernetBuffer + payloadoffset), (ETH_TX_BUF_SIZE)); /* Point to next descriptor */ DmaTxDesc = (ETH_DMADescTypeDef *) (DmaTxDesc->Buffer2NextDescAddr); /* Check if the buffer is available */ if ((DmaTxDesc->Status & ETH_DMATXDESC_OWN) != (uint32_t) RESET) { errval = pdFAIL; goto error; } // memcpy( (uint8_t*)((uint8_t*)buffer), (uint8_t*)((uint8_t*)pxDescriptor->pucEthernetBuffer + payloadoffset), byteslefttocopy ); buffer = (uint8_t *) (DmaTxDesc->Buffer1Addr); byteslefttocopy -= (ETH_TX_BUF_SIZE); payloadoffset += (ETH_TX_BUF_SIZE); } /* Copy the remaining bytes */ memcpy((uint8_t*) ((uint8_t*) buffer), (uint8_t*) ((uint8_t*) pxDescriptor->pucEthernetBuffer + payloadoffset), byteslefttocopy); /* Prepare transmit descriptors to give to DMA */ HAL_ETH_TransmitFrame(&heth_global, framelength); gdb.monit.tx_eth_frames++; /* Call the standard trace macro to log the send event. */ iptraceNETWORK_INTERFACE_TRANSMIT(); errval = pdPASS; error: if (xReleaseAfterSend != pdFALSE) { /* It is assumed SendData() copies the data out of the FreeRTOS+TCP Ethernet buffer. The Ethernet buffer is therefore no longer needed, and must be freed for re-use. */ vReleaseNetworkBufferAndDescriptor(pxDescriptor); } /* When Transmit Underflow flag is set, clear it and issue a Transmit Poll Demand to resume transmission */ if ((heth_global.Instance->DMASR & ETH_DMASR_TUS) != (uint32_t) RESET) { /* Clear TUS ETHERNET DMA flag */ heth_global.Instance->DMASR = ETH_DMASR_TUS; /* Resume DMA transmission*/ heth_global.Instance->DMATPDR = 0; } return errval; }