-
Notifications
You must be signed in to change notification settings - Fork 134
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[examples] Add FreeRTOS TCP Ethernet example
- Loading branch information
Showing
2 changed files
with
267 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,256 @@ | ||
/* | ||
* Copyright (c) 2020, Mike Wolfram | ||
* | ||
* This file is part of the modm project. | ||
* | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
*/ | ||
// ---------------------------------------------------------------------------- | ||
|
||
#include <modm/board.hpp> | ||
#include <modm/driver/ethernet/lan8720a.hpp> | ||
#include <modm/processing/rtos.hpp> | ||
#include <FreeRTOS_IP.h> | ||
#include <FreeRTOS_Sockets.h> | ||
|
||
using namespace Board; | ||
|
||
namespace Ethernet | ||
{ | ||
using RMII_Ref_Clk = GpioInputA1; | ||
using RMII_Mdio = GpioA2; | ||
using RMII_Crs_Dv = GpioInputA7; | ||
using RMII_Tx_En = GpioOutputG11; | ||
using RMII_Tx_D0 = GpioOutputG13; | ||
using RMII_Tx_D1 = GpioOutputB13; | ||
using RMII_Mdc = GpioOutputC1; | ||
using RMII_Rx_D0 = GpioInputC4; | ||
using RMII_Rx_D1 = GpioInputC5; | ||
using Port = Eth<modm::Lan8720a>; | ||
} | ||
|
||
UBaseType_t ulNextRand; | ||
|
||
void vApplicationIPNetworkEventHook(eIPCallbackEvent_t eNetworkEvent); | ||
|
||
class NetworkInitTask : modm::rtos::Thread | ||
{ | ||
public: | ||
NetworkInitTask() | ||
: Thread(5, 2048, "network_init") | ||
{} | ||
|
||
void | ||
run() | ||
{ | ||
uint8_t ipAddress[4] { 192, 168, 1, 1 }; | ||
uint8_t netmask[4] { 255, 255, 255, 0 }; | ||
uint8_t gatewayAddress[4] { 0, 0, 0, 0 }; | ||
uint8_t dnsAddress[4] { 0, 0, 0, 0 }; | ||
|
||
// local MAC address | ||
uint8_t macAddress[] { 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 }; | ||
|
||
// A real MAC address can be retrieved from the Microchip 24AA02E48 | ||
// I2C EEPROM, which is locaed at address 0xFA. | ||
|
||
// initialize random numbers | ||
time_t now; | ||
time(&now); | ||
ulNextRand = uint32_t(now); | ||
|
||
FreeRTOS_IPInit(ipAddress, | ||
netmask, | ||
gatewayAddress, | ||
dnsAddress, | ||
&macAddress[0]); | ||
|
||
vTaskDelete(0); | ||
} | ||
}; | ||
|
||
class HttpConnection | ||
{ | ||
static constexpr TickType_t shutdownTimeout { pdMS_TO_TICKS(5000) }; | ||
static constexpr TickType_t receiveTimeout { pdMS_TO_TICKS(5000) }; | ||
static constexpr TickType_t sendTimeout { pdMS_TO_TICKS(5000) }; | ||
|
||
public: | ||
static constexpr char name[] { "HTTPConnection" }; | ||
static constexpr uint8_t httpText[] = { | ||
"HTTP/1.1 200 OK \r\n" | ||
"Content-Type: text/html\r\n" | ||
"Connection: keep-alive\r\n" | ||
"\r\n" | ||
"<html><body><h1>Hello from your STM32!</h1></body></html>" | ||
}; | ||
|
||
enum class | ||
ResponseStatus : uint16_t { | ||
Ok = 200, | ||
BadRequest = 400, | ||
NotFound = 404, | ||
}; | ||
|
||
static void | ||
run(void *parameter) | ||
{ | ||
Socket_t connectedSocket = reinterpret_cast<Socket_t>(parameter); | ||
uint8_t *buffer = reinterpret_cast<uint8_t *>(pvPortMalloc(ipconfigTCP_MSS)); | ||
|
||
if (buffer) { | ||
FreeRTOS_setsockopt(connectedSocket, 0, FREERTOS_SO_RCVTIMEO, &receiveTimeout, | ||
sizeof(receiveTimeout)); | ||
FreeRTOS_setsockopt(connectedSocket, 0, FREERTOS_SO_SNDTIMEO, &sendTimeout, | ||
sizeof(sendTimeout)); | ||
|
||
while (true) { | ||
std::memset(buffer, 0, ipconfigTCP_MSS); | ||
int32_t bytes = FreeRTOS_recv(connectedSocket, buffer, ipconfigTCP_MSS, 0); | ||
if (bytes <= 0) | ||
break; | ||
if (FreeRTOS_send(connectedSocket, httpText, sizeof(httpText) - 1, 0) < 0) | ||
break; | ||
} | ||
} | ||
|
||
FreeRTOS_shutdown(connectedSocket, FREERTOS_SHUT_RDWR); | ||
TickType_t shutdownTime { xTaskGetTickCount() }; | ||
do { | ||
if (FreeRTOS_recv(connectedSocket, buffer, ipconfigTCP_MSS, 0) < 0) | ||
break; | ||
} while ((xTaskGetTickCount() - shutdownTime) < shutdownTimeout); | ||
|
||
vPortFree(buffer); | ||
FreeRTOS_closesocket(connectedSocket); | ||
vTaskDelete(0); | ||
|
||
} | ||
}; | ||
|
||
class HttpServerListener | ||
{ | ||
static constexpr TickType_t receiveTimeout { portMAX_DELAY }; | ||
static constexpr BaseType_t backlog { 20 }; | ||
|
||
public: | ||
static constexpr char name[] { "HTTPListener" }; | ||
|
||
static void | ||
run(void *) | ||
{ | ||
Socket_t listeningSocket; | ||
Socket_t connectedSocket; | ||
|
||
listeningSocket = FreeRTOS_socket(FREERTOS_AF_INET, | ||
FREERTOS_SOCK_STREAM, | ||
FREERTOS_IPPROTO_TCP); | ||
FreeRTOS_setsockopt(listeningSocket, 0, FREERTOS_SO_RCVTIMEO, &receiveTimeout, | ||
sizeof(receiveTimeout)); | ||
|
||
#if ipconfigUSE_TCP_WIN == 1 | ||
WinProperties_t winProps { | ||
.lTxBufSize = ipconfigTCP_TX_BUFFER_LENGTH, | ||
.lTxWinSize = 2, | ||
.lRxBufSize = ipconfigTCP_RX_BUFFER_LENGTH, | ||
.lRxWinSize = 2, | ||
}; | ||
FreeRTOS_setsockopt(listeningSocket, 0, FREERTOS_SO_WIN_PROPERTIES, | ||
reinterpret_cast<void *>(&winProps), sizeof(winProps)); | ||
#endif | ||
|
||
struct freertos_sockaddr bindAddress { | ||
.sin_port = FreeRTOS_htons(80), | ||
}; | ||
FreeRTOS_bind(listeningSocket, &bindAddress, sizeof(bindAddress)); | ||
FreeRTOS_listen(listeningSocket, backlog); | ||
|
||
struct freertos_sockaddr clientAddress; | ||
|
||
while (true) { | ||
connectedSocket = FreeRTOS_accept(listeningSocket, &clientAddress, 0); | ||
char buffer[16]; | ||
FreeRTOS_inet_ntoa(clientAddress.sin_addr, buffer); | ||
xTaskCreate(HttpConnection::run, HttpConnection::name, configMINIMAL_STACK_SIZE * 5, | ||
reinterpret_cast<void *>(connectedSocket), configMAX_PRIORITIES, 0); | ||
} | ||
} | ||
}; | ||
|
||
NetworkInitTask networkInit; | ||
|
||
int | ||
main() | ||
{ | ||
Board::initialize(); | ||
Leds::setOutput(); | ||
MODM_LOG_INFO << "\n\nReboot: Ethernet Example" << modm::endl; | ||
|
||
Ethernet::Port::connect<Ethernet::RMII_Ref_Clk::Refclk, | ||
Ethernet::RMII_Mdc::Mdc, | ||
Ethernet::RMII_Mdio::Mdio, | ||
Ethernet::RMII_Crs_Dv::Rcccrsdv, | ||
Ethernet::RMII_Tx_En::Txen, | ||
Ethernet::RMII_Tx_D0::Txd0, | ||
Ethernet::RMII_Tx_D1::Txd1, | ||
Ethernet::RMII_Rx_D0::Rxd0, | ||
Ethernet::RMII_Rx_D1::Rxd1>(); | ||
|
||
modm::rtos::Scheduler::schedule(); | ||
|
||
// we should never get here | ||
return 0; | ||
} | ||
|
||
void vApplicationIPNetworkEventHook(eIPCallbackEvent_t eNetworkEvent) | ||
{ | ||
static bool taskCreated = false; | ||
|
||
if (eNetworkEvent != eNetworkUp) | ||
return; | ||
|
||
if (not taskCreated) { | ||
xTaskCreate(HttpServerListener::run, HttpServerListener::name, configMINIMAL_STACK_SIZE * 2, 0, configMAX_PRIORITIES + 1, 0); | ||
taskCreated = true; | ||
} | ||
|
||
uint32_t ipAddress; | ||
uint32_t netmask; | ||
uint32_t gateway; | ||
uint32_t dns; | ||
char buffer[16]; | ||
|
||
FreeRTOS_GetAddressConfiguration(&ipAddress, &netmask, &gateway, &dns); | ||
FreeRTOS_inet_ntoa(ipAddress, buffer); | ||
MODM_LOG_DEBUG << "IP address: " << buffer << modm::endl; | ||
FreeRTOS_inet_ntoa(netmask, buffer); | ||
MODM_LOG_DEBUG << "Netmask : " << buffer << modm::endl; | ||
FreeRTOS_inet_ntoa(gateway, buffer); | ||
MODM_LOG_DEBUG << "Gateway : " << buffer << modm::endl; | ||
FreeRTOS_inet_ntoa(dns, buffer); | ||
MODM_LOG_DEBUG << "DNS : " << buffer << modm::endl; | ||
} | ||
|
||
UBaseType_t uxRand( void ) | ||
{ | ||
static constexpr uint32_t ulMultiplier = 0x015a4e35UL; | ||
static constexpr uint32_t ulIncrement = 1UL; | ||
|
||
/* Utility function to generate a pseudo random number. */ | ||
|
||
ulNextRand = ( ulMultiplier * ulNextRand ) + ulIncrement; | ||
return( ( int ) ( ulNextRand >> 16UL ) & 0x7fffUL ); | ||
} | ||
|
||
BaseType_t xApplicationGetRandomNumber(uint32_t* pulNumber) | ||
{ | ||
*(pulNumber) = uxRand(); | ||
return pdTRUE; | ||
} | ||
|
||
uint32_t ulApplicationGetNextSequenceNumber(uint32_t, uint16_t, uint32_t, uint16_t) | ||
{ | ||
return uxRand(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
<library> | ||
<extends>modm:nucleo-f767zi</extends> | ||
<options> | ||
<option name="modm:build:build.path">../../../build/nucleo_f767zi/ethernet</option> | ||
</options> | ||
<modules> | ||
<module>modm:build:scons</module> | ||
<module>modm:freertos:tcp:lan8720a</module> | ||
<module>modm:processing:rtos</module> | ||
</modules> | ||
</library> |