767 lines
24 KiB
C
767 lines
24 KiB
C
#include "FreeRTOS.h"
|
|
#include "task.h"
|
|
#include "queue.h"
|
|
#include "semphr.h"
|
|
#include "gd32f107c_eval.h"
|
|
#include "gd32f10x_gpio.h"
|
|
#include "stdio.h"
|
|
|
|
|
|
/* System application includes. */
|
|
#include "FreeRTOSIPConfig.h"
|
|
|
|
/* Demo application includes. */
|
|
#include "FreeRTOS_IP.h"
|
|
#include "FreeRTOS_Sockets.h"
|
|
#include "SimpleUDPClientAndServer.h"
|
|
#include "SimpleTCPEchoServer.h"
|
|
#include "TCPEchoClient_SingleTasks.h"
|
|
#include "rf_switch_driver.h"
|
|
|
|
#define BUTTON_USER GPIO_PIN_14
|
|
|
|
#define LED2_USER_PORT GPIOC
|
|
#define LED5_TICK_PORT GPIOE
|
|
#define RF_SWITCH_PORT GPIOE
|
|
#define RF_SWITCH_PIN_A GPIO_PIN_10
|
|
#define RF_SWITCH_PIN_B GPIO_PIN_11
|
|
#define RF_SWITCH_PIN_C GPIO_PIN_12
|
|
#define RF_SWITCH_PIN_EN GPIO_PIN_13
|
|
|
|
#define LED2_USER GPIO_PIN_0
|
|
#define LED5_TICK GPIO_PIN_1
|
|
|
|
#define TASK_HELLO_WORLD_DELAY 500
|
|
#define TASK_TOGGLE_LED_DELAY 125
|
|
|
|
#define OSC32_PORT GPIOC
|
|
#define OSC32_IN GPIO_PIN_14
|
|
#define OSC32_OUT GPIO_PIN_15
|
|
/*
|
|
* RMII interface port & pin definitions
|
|
*/
|
|
#define RMII_INT_PORT GPIOB
|
|
#define RMII_INT GPIO_PIN_0
|
|
|
|
#define RMII_REF_CLK_PORT GPIOA
|
|
#define RMII_REF_CLK GPIO_PIN_1
|
|
#define RMII_MCO GPIO_PIN_8
|
|
|
|
#define RMII_MDC_PORT GPIOC
|
|
#define RMII_MDC GPIO_PIN_1
|
|
|
|
#define RMII_MDIO_PORT GPIOA
|
|
#define RMII_MDIO GPIO_PIN_2
|
|
|
|
#define RMII_RXD_PORT GPIOC
|
|
#define RMII_RXD0 GPIO_PIN_4
|
|
#define RMII_RXD1 GPIO_PIN_5
|
|
|
|
#define RMII_CRS_DV_PORT GPIOA
|
|
#define RMII_CRS_DV GPIO_PIN_7
|
|
|
|
#define RMII_TXD_PORT GPIOB
|
|
#define RMII_TX_EN GPIO_PIN_11
|
|
#define RMII_TXD0 GPIO_PIN_12
|
|
#define RMII_TXD1 GPIO_PIN_13
|
|
|
|
|
|
#define TEST_RUNNER_TASK_STACK_SIZE 512
|
|
|
|
#define mainCREATE_SIMPLE_UDP_CLIENT_SERVER_TASKS 0
|
|
#define mainCREATE_TCP_ECHO_TASKS_SINGLE 0
|
|
#define mainCREATE_TCP_ECHO_SERVER_TASK 1
|
|
|
|
/* Simple UDP client and server task parameters. */
|
|
#define mainSIMPLE_UDP_CLIENT_SERVER_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 )
|
|
#define mainSIMPLE_UDP_CLIENT_SERVER_PORT ( 5005UL )
|
|
|
|
/* Echo client task parameters - used for both TCP and UDP echo clients. */
|
|
#define mainECHO_CLIENT_TASK_STACK_SIZE ( configMINIMAL_STACK_SIZE * 2 ) /* Not used in the Windows port. */
|
|
#define mainECHO_CLIENT_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 )
|
|
|
|
/* Echo server task parameters. */
|
|
#define mainECHO_SERVER_TASK_STACK_SIZE ( configMINIMAL_STACK_SIZE * 2 ) /* Not used in the Windows port. */
|
|
#define mainECHO_SERVER_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 )
|
|
|
|
/* Define a name that will be used for LLMNR and NBNS searches. */
|
|
#define mainHOST_NAME "GD32F107C_TCP_UDP_SERVER"
|
|
#define mainDEVICE_NICK_NAME "GD32F107C"
|
|
|
|
#ifdef DEBUG
|
|
#define BKPT_DEBUG() __BKPT();
|
|
#else
|
|
#define BKPT_DEBUG()
|
|
#endif
|
|
|
|
TaskHandle_t vTaskHelloWorld_Handle, vTaskToggleLed_Handle;
|
|
/* Default MAC address configuration. The demo creates a virtual network
|
|
* connection that uses this MAC address by accessing the raw Ethernet data
|
|
* to and from a real network connection on the host PC. See the
|
|
* configNETWORK_INTERFACE_TO_USE definition for information on how to configure
|
|
* the real network connection to use. */
|
|
const uint8_t ucMACAddress[ 6 ] =
|
|
{
|
|
configMAC_ADDR0,
|
|
configMAC_ADDR1,
|
|
configMAC_ADDR2,
|
|
configMAC_ADDR3,
|
|
configMAC_ADDR4,
|
|
configMAC_ADDR5
|
|
};
|
|
|
|
/* The default IP and MAC address used by the demo. The address configuration
|
|
* defined here will be used if ipconfigUSE_DHCP is 0, or if ipconfigUSE_DHCP is
|
|
* 1 but a DHCP server could not be contacted. See the online documentation for
|
|
* more information. In both cases the node can be discovered using
|
|
* "ping RTOSDemo". */
|
|
static const uint8_t ucIPAddress[ 4 ] =
|
|
{
|
|
configIP_ADDR0,
|
|
configIP_ADDR1,
|
|
configIP_ADDR2,
|
|
configIP_ADDR3
|
|
};
|
|
static const uint8_t ucNetMask[ 4 ] =
|
|
{
|
|
configNET_MASK0,
|
|
configNET_MASK1,
|
|
configNET_MASK2,
|
|
configNET_MASK3
|
|
};
|
|
static const uint8_t ucGatewayAddress[ 4 ] =
|
|
{
|
|
configGATEWAY_ADDR0,
|
|
configGATEWAY_ADDR1,
|
|
configGATEWAY_ADDR2,
|
|
configGATEWAY_ADDR3
|
|
};
|
|
static const uint8_t ucDNSServerAddress[ 4 ] =
|
|
{
|
|
configDNS_SERVER_ADDR0,
|
|
configDNS_SERVER_ADDR1,
|
|
configDNS_SERVER_ADDR2,
|
|
configDNS_SERVER_ADDR3
|
|
};
|
|
|
|
/* Use by the pseudo random number generator. */
|
|
static UBaseType_t ulNextRand;
|
|
struct rf_switch_config rfSwitchConfig;
|
|
/*
|
|
* Just seeds the simple pseudo random number generator.
|
|
*/
|
|
static void prvSRand( UBaseType_t ulSeed );
|
|
|
|
/*
|
|
* Miscellaneous initialisation including preparing the logging and seeding the
|
|
* random number generator.
|
|
*/
|
|
static void prvMiscInitialisation( void );
|
|
|
|
void vTaskHelloWorld( void *pvParameters);
|
|
void vTaskToggleLed( void *pvParameters);
|
|
int stdout_putchar (int ch);
|
|
int stdin_getchar (void);
|
|
void DelayMS(unsigned char ms);
|
|
|
|
int stdout_putchar (int ch)
|
|
{
|
|
usart_data_transmit(EVAL_COM1, (uint16_t)ch);
|
|
while (!usart_flag_get(EVAL_COM1, USART_FLAG_TBE)){}
|
|
|
|
return ch;
|
|
}
|
|
int stdin_getchar (void)
|
|
{
|
|
return usart_data_receive(EVAL_COM1);
|
|
}
|
|
|
|
/**! \brief ErrStatus xInitPLL2(void)
|
|
* Enable PLL2 to generate 50MHz clocks
|
|
*/
|
|
static ErrStatus xInitPLL2(void)
|
|
{
|
|
/*CK_PREDIV1 = (CK_HXTAL)/5 = 5 MHz */
|
|
if (!(RCU_CFG1 & RCU_PREDV1_DIV5)) return ERROR;
|
|
/* CK_PLL2 = (CK_PREDIV1) * 10 = 50 MHz */
|
|
rcu_pll2_config(RCU_PLL2_MUL10);
|
|
/* enable PLL2 */
|
|
RCU_CTL |= RCU_CTL_PLL2EN;
|
|
/* wait till PLL2 is ready */
|
|
while(RESET == rcu_flag_get(RCU_FLAG_PLL2STB)){
|
|
};
|
|
return SUCCESS;
|
|
}
|
|
|
|
/**! \brief vInitMCU
|
|
* Initial MCU configuration
|
|
*/
|
|
static void vInitMCU(void)
|
|
{
|
|
SystemInit();
|
|
|
|
rcu_periph_clock_enable(RCU_GPIOA);
|
|
rcu_periph_clock_enable(RCU_GPIOB);
|
|
rcu_periph_clock_enable(RCU_GPIOC);
|
|
rcu_periph_clock_enable(RCU_GPIOE);
|
|
rcu_periph_clock_enable(RCU_AF);
|
|
rcu_periph_clock_enable(RCU_ENET);
|
|
rcu_periph_clock_enable(RCU_ENETTX);
|
|
rcu_periph_clock_enable(RCU_ENETRX);
|
|
rcu_periph_clock_enable(RCU_PMU);
|
|
rcu_periph_reset_enable(RCU_BKPIRST);
|
|
rcu_periph_reset_disable(RCU_BKPIRST);
|
|
rcu_periph_clock_enable(RCU_BKPI);
|
|
|
|
|
|
/* Configure RTC */
|
|
#ifndef DEBUG_RTC_LXTAL
|
|
gpio_init(OSC32_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_2MHZ, OSC32_IN);
|
|
gpio_init(OSC32_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_2MHZ, OSC32_OUT);
|
|
|
|
if (FALSE == rtc_counter_get() & FALSE == rtc_flag_get(RTC_CTL_OVIF))
|
|
{
|
|
pmu_backup_write_enable();
|
|
bkp_deinit();
|
|
rcu_osci_on(RCU_LXTAL);
|
|
rcu_periph_clock_enable(RCU_RTC);
|
|
rcu_rtc_clock_config(RCU_RTCSRC_LXTAL);
|
|
|
|
while (RESET == (RCU_BDCTL & RCU_BDCTL_LXTALSTB)) {}
|
|
|
|
rtc_lwoff_wait();
|
|
rtc_counter_set(0xA5A5);
|
|
rtc_lwoff_wait();
|
|
rtc_prescaler_set(0);
|
|
rtc_lwoff_wait();
|
|
|
|
pmu_backup_write_disable();
|
|
}
|
|
else if (TRUE == rtc_flag_get(RTC_CTL_OVIF))
|
|
rtc_flag_clear(RTC_CTL_OVIF);
|
|
#endif
|
|
|
|
/* Configure GPIO Alternate UART function */
|
|
gd_eval_com_init(EVAL_COM1);
|
|
gpio_init(GPIOB, GPIO_MODE_IPU, GPIO_OSPEED_2MHZ, BUTTON_USER);
|
|
|
|
/* Configure GPIO Output function for LEDs */
|
|
gpio_init(LED2_USER_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_2MHZ, LED2_USER); //gd_eval_led_init(LED2);
|
|
gpio_bit_set(LED2_USER_PORT, LED2_USER); //gd_eval_led_on(LED2);
|
|
gpio_init(LED5_TICK_PORT, GPIO_MODE_OUT_PP, GPIO_OSPEED_2MHZ, LED5_TICK);
|
|
gpio_bit_set(LED5_TICK_PORT, LED5_TICK);
|
|
|
|
|
|
/* Enable PLL2 to generate 50MHz clocks */
|
|
if (ERROR == xInitPLL2()) FreeRTOS_debug_printf(("PLL2 initialization failed\n"));
|
|
|
|
/* Put PLL2 clocks into CKOUT0(PA1) as ref clock for ethernet phy */
|
|
rcu_ckout0_config(RCU_CKOUT0SRC_CKPLL2);
|
|
gpio_ethernet_phy_select(GPIO_ENET_PHY_RMII);
|
|
|
|
/* Configure GPIO Alternate RMII function */
|
|
gpio_init(RMII_TXD_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, RMII_TX_EN);
|
|
gpio_init(RMII_TXD_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, RMII_TXD0);
|
|
gpio_init(RMII_TXD_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, RMII_TXD1);
|
|
|
|
gpio_init(RMII_MDC_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, RMII_MDC);
|
|
gpio_init(RMII_MDIO_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, RMII_MDIO);
|
|
gpio_init(RMII_INT_PORT, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, RMII_INT);
|
|
|
|
gpio_init(RMII_REF_CLK_PORT, GPIO_MODE_AF_PP, GPIO_OSPEED_50MHZ, RMII_MCO);
|
|
|
|
gpio_init(RMII_REF_CLK_PORT, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, RMII_REF_CLK);
|
|
gpio_init(RMII_RXD_PORT, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, RMII_RXD0);
|
|
gpio_init(RMII_RXD_PORT, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, RMII_RXD1);
|
|
gpio_init(RMII_CRS_DV_PORT, GPIO_MODE_IN_FLOATING, GPIO_OSPEED_50MHZ, RMII_CRS_DV);
|
|
|
|
/* Enable Ethernet MAC */
|
|
enet_descriptors_chain_init(ENET_DMA_TX);
|
|
enet_descriptors_chain_init(ENET_DMA_RX); //enet_desc_receive_complete_bit_enable(dma_current_rxdesc);
|
|
enet_enable();
|
|
//nvic_irq_enable(ENET_IRQn, ipconfigMAC_INTERRUPT_PRIORITY, 0xFF);
|
|
__disable_irq();
|
|
NVIC_ClearPendingIRQ(ENET_IRQn);
|
|
NVIC_SetPriority(ENET_IRQn, ipconfigMAC_INTERRUPT_PRIORITY);
|
|
NVIC_EnableIRQ(ENET_IRQn);
|
|
__enable_irq();
|
|
}
|
|
|
|
/**! \brief vTaskHelloWorld procedure
|
|
*
|
|
* \param Not Used.
|
|
*/
|
|
void vTaskHelloWorld( void *pvParameters)
|
|
{
|
|
char ButtonState = 0;
|
|
for( ;; )
|
|
{
|
|
#ifdef DEBUG_ET_IRQ
|
|
ulTaskNotifyTakeIndexed(1, pdFALSE, portMAX_DELAY );
|
|
FreeRTOS_debug_printf(("ENET_DMA_INT_FLAG_ET\n"));
|
|
#else
|
|
ButtonState = !gpio_input_bit_get(GPIOB, BUTTON_USER);
|
|
if (ButtonState)
|
|
{
|
|
FreeRTOS_debug_printf(("Key pressed\n"));
|
|
fflush( stdout );
|
|
vTaskDelay(TASK_HELLO_WORLD_DELAY);
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
/**! \brief vTaskToggleLed procedure
|
|
*
|
|
* \param Not Used.
|
|
*/
|
|
void vTaskToggleLed( void *pvParameters)
|
|
{
|
|
char toggle = 1;
|
|
for( ;; )
|
|
{
|
|
#ifdef DEBUG_RBU_IRQ
|
|
ulTaskNotifyTakeIndexed(0, pdFALSE, portMAX_DELAY );
|
|
FreeRTOS_debug_printf(("ENET_DMA_INT_FLAG_RBU\n"));
|
|
#else
|
|
if (toggle)
|
|
{
|
|
gpio_bit_reset(LED2_USER_PORT, LED2_USER);
|
|
}
|
|
else
|
|
{
|
|
gpio_bit_set(LED2_USER_PORT, LED2_USER);
|
|
}
|
|
toggle = !toggle;
|
|
vTaskDelay(TASK_TOGGLE_LED_DELAY);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief Miscellaneous initialisation including preparing the logging and seeding
|
|
* the random number generator.
|
|
*/
|
|
static void prvMiscInitialisation( void )
|
|
{
|
|
UBaseType_t xTimeNow;
|
|
uint32_t ulRandomNumbers[ 4 ];
|
|
|
|
/* Seed the random number generator. */
|
|
xTimeNow = rtc_counter_get();
|
|
FreeRTOS_debug_printf( ("Seed for randomiser: 0x%08X\r\n", (unsigned)xTimeNow ) );
|
|
prvSRand( ( uint32_t ) xTimeNow );
|
|
|
|
( void ) xApplicationGetRandomNumber( &ulRandomNumbers[ 0 ] );
|
|
( void ) xApplicationGetRandomNumber( &ulRandomNumbers[ 1 ] );
|
|
( void ) xApplicationGetRandomNumber( &ulRandomNumbers[ 2 ] );
|
|
( void ) xApplicationGetRandomNumber( &ulRandomNumbers[ 3 ] );
|
|
FreeRTOS_debug_printf( ("Random numbers: 0x%08X 0x%08X 0x%08X 0x%08X\r\n",
|
|
ulRandomNumbers[ 0 ],
|
|
ulRandomNumbers[ 1 ],
|
|
ulRandomNumbers[ 2 ],
|
|
ulRandomNumbers[ 3 ] ) );
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
vInitMCU();
|
|
vRFSwitchInit(&rfSwitchConfig, RF_SWITCH_PORT, RF_SWITCH_PIN_A, RF_SWITCH_PORT, RF_SWITCH_PIN_B, RF_SWITCH_PORT, RF_SWITCH_PIN_C, RF_SWITCH_PORT, RF_SWITCH_PIN_EN);
|
|
prvMiscInitialisation();
|
|
xTaskCreate( vTaskToggleLed, "ToggleLed", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, &vTaskToggleLed_Handle);
|
|
xTaskCreate( vTaskHelloWorld, "HelloWorld", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY + 1, &vTaskHelloWorld_Handle);
|
|
FreeRTOS_IPInit( ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress );
|
|
|
|
vTaskStartScheduler();
|
|
while(1);
|
|
}
|
|
|
|
BaseType_t xApplicationDNSQueryHook( const char * pcName )
|
|
{
|
|
#ifdef DEBUG
|
|
return TRUE;
|
|
#endif
|
|
}
|
|
/**
|
|
* @brief pcApplicationHostnameHook( void )
|
|
*/
|
|
const char * pcApplicationHostnameHook( void )
|
|
{
|
|
return mainHOST_NAME;
|
|
}
|
|
|
|
/**
|
|
* @brief xApplicationDHCPHook( eDHCPCallbackPhase_t eDHCPPhase, uint32_t ulIPAddress )
|
|
*/
|
|
eDHCPCallbackAnswer_t xApplicationDHCPHook( eDHCPCallbackPhase_t eDHCPPhase, uint32_t ulIPAddress )
|
|
{
|
|
eDHCPCallbackAnswer_t xResult = eDHCPUseDefaults;
|
|
switch (eDHCPPhase)
|
|
{
|
|
case eDHCPPhasePreDiscover:
|
|
FreeRTOS_printf((" Driver is about to send a DHCP discovery.\n"));
|
|
xResult = eDHCPContinue;
|
|
break;
|
|
case eDHCPPhasePreRequest:
|
|
FreeRTOS_printf((" Driver is about to request DHCP an IP address.\n"));
|
|
xResult = eDHCPContinue;
|
|
break;
|
|
default:
|
|
FreeRTOS_printf((" Stop DHCP requests.\n"));
|
|
xResult = eDHCPStopNoChanges;
|
|
break;
|
|
};
|
|
return xResult;
|
|
};
|
|
|
|
/**
|
|
* @brief vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent )
|
|
*/
|
|
/* Called by FreeRTOS+TCP when the network connects or disconnects. Disconnect
|
|
* events are only received if implemented in the MAC driver. */
|
|
void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent )
|
|
{
|
|
uint32_t ulIPAddress, ulNetMask, ulGatewayAddress, ulDNSServerAddress;
|
|
char cBuffer[ 16 ];
|
|
static BaseType_t xTasksAlreadyCreated = pdFALSE;
|
|
|
|
/* If the network has just come up...*/
|
|
if( eNetworkEvent == eNetworkUp )
|
|
{
|
|
/* Create the tasks that use the IP stack if they have not already been
|
|
* created. */
|
|
if( xTasksAlreadyCreated == pdFALSE )
|
|
{
|
|
/* See the comments above the definitions of these pre-processor
|
|
* macros at the top of this file for a description of the individual
|
|
* demo tasks. */
|
|
#if ( mainCREATE_SIMPLE_UDP_CLIENT_SERVER_TASKS == 1 )
|
|
{
|
|
vStartSimpleUDPClientServerTasks( configMINIMAL_STACK_SIZE, mainSIMPLE_UDP_CLIENT_SERVER_PORT, mainSIMPLE_UDP_CLIENT_SERVER_TASK_PRIORITY );
|
|
}
|
|
#endif /* mainCREATE_SIMPLE_UDP_CLIENT_SERVER_TASKS */
|
|
|
|
#if ( mainCREATE_TCP_ECHO_TASKS_SINGLE == 1 )
|
|
{
|
|
vStartTCPEchoClientTasks_SingleTasks( mainECHO_CLIENT_TASK_STACK_SIZE, mainECHO_CLIENT_TASK_PRIORITY );
|
|
}
|
|
#endif /* mainCREATE_TCP_ECHO_TASKS_SINGLE */
|
|
|
|
#if ( mainCREATE_TCP_ECHO_SERVER_TASK == 1 )
|
|
{
|
|
vStartSimpleTCPServerTasks( mainECHO_SERVER_TASK_STACK_SIZE, mainECHO_SERVER_TASK_PRIORITY );
|
|
}
|
|
#endif
|
|
|
|
xTasksAlreadyCreated = pdTRUE;
|
|
}
|
|
|
|
/* Print out the network configuration, which may have come from a DHCP
|
|
* server. */
|
|
FreeRTOS_GetAddressConfiguration( &ulIPAddress, &ulNetMask, &ulGatewayAddress, &ulDNSServerAddress );
|
|
FreeRTOS_inet_ntoa( ulIPAddress, cBuffer );
|
|
FreeRTOS_printf( ( "\r\n\r\nIP Address: %s\r\n", cBuffer ) );
|
|
|
|
FreeRTOS_inet_ntoa( ulNetMask, cBuffer );
|
|
FreeRTOS_printf( ( "Subnet Mask: %s\r\n", cBuffer ) );
|
|
|
|
FreeRTOS_inet_ntoa( ulGatewayAddress, cBuffer );
|
|
FreeRTOS_printf( ( "Gateway Address: %s\r\n", cBuffer ) );
|
|
|
|
FreeRTOS_inet_ntoa( ulDNSServerAddress, cBuffer );
|
|
FreeRTOS_printf( ( "DNS Server Address: %s\r\n\r\n\r\n", cBuffer ) );
|
|
}
|
|
}
|
|
|
|
static void prvSRand( UBaseType_t ulSeed )
|
|
{
|
|
/* Utility function to seed the pseudo random number generator. */
|
|
ulNextRand = ulSeed;
|
|
}
|
|
|
|
UBaseType_t uxRand( void )
|
|
{
|
|
const uint32_t ulMultiplier = 0x015a4e35UL, ulIncrement = 1UL;
|
|
|
|
/* Utility function to generate a pseudo random number. */
|
|
|
|
ulNextRand = ( ulMultiplier * ulNextRand ) + ulIncrement;
|
|
return( ( int ) ( ulNextRand ) & 0x7fffUL );
|
|
}
|
|
|
|
BaseType_t xApplicationGetRandomNumber( uint32_t * pulNumber )
|
|
{
|
|
BaseType_t xReturn; /* Return pdTRUE if successful */
|
|
#ifdef RANDOM_NUMBER
|
|
CK_RV xResult = 0;
|
|
SemaphoreHandle_t xSessionLock = NULL;
|
|
CK_SESSION_HANDLE xPkcs11Session = 0;
|
|
CK_FUNCTION_LIST_PTR pxPkcs11FunctionList = NULL;
|
|
uint32_t ulRandomValue = 0;
|
|
|
|
|
|
xResult = prvSocketsGetCryptoSession( &xSessionLock,
|
|
&xPkcs11Session,
|
|
&pxPkcs11FunctionList );
|
|
|
|
if( 0 == xResult )
|
|
{
|
|
/* Request a sequence of cryptographically random byte values using
|
|
* PKCS#11. */
|
|
xResult = pxPkcs11FunctionList->C_GenerateRandom( xPkcs11Session,
|
|
( CK_BYTE_PTR ) &ulRandomValue,
|
|
sizeof( ulRandomValue ) );
|
|
}
|
|
|
|
/* Check if any of the API calls failed. */
|
|
if( 0 == xResult )
|
|
{
|
|
xReturn = pdTRUE;
|
|
*( pulNumber ) = ulRandomValue;
|
|
}
|
|
else
|
|
{
|
|
xReturn = pdFALSE;
|
|
*( pulNumber ) = 0uL;
|
|
}
|
|
return xReturn;
|
|
}
|
|
#else
|
|
*pulNumber = uxRand();
|
|
return pdTRUE;
|
|
#endif
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Generate a TCP Initial Sequence Number that is reasonably difficult
|
|
* to predict, per https://tools.ietf.org/html/rfc6528.
|
|
*/
|
|
extern uint32_t ulApplicationGetNextSequenceNumber( uint32_t ulSourceAddress,
|
|
uint16_t usSourcePort,
|
|
uint32_t ulDestinationAddress,
|
|
uint16_t usDestinationPort )
|
|
{
|
|
( void ) ulSourceAddress;
|
|
( void ) usSourcePort;
|
|
( void ) ulDestinationAddress;
|
|
( void ) usDestinationPort;
|
|
#ifdef RANDOM_NUMBER
|
|
CK_RV xResult = CKR_OK;
|
|
SemaphoreHandle_t xSessionLock = NULL;
|
|
CK_SESSION_HANDLE xPkcs11Session = 0;
|
|
CK_FUNCTION_LIST_PTR pxPkcs11FunctionList = NULL;
|
|
CK_MECHANISM xMechSha256 = { 0 };
|
|
uint8_t ucSha256Result[ cryptoSHA256_DIGEST_BYTES ];
|
|
CK_ULONG ulLength = sizeof( ucSha256Result );
|
|
uint32_t ulNextSequenceNumber = 0;
|
|
static uint64_t ullKey;
|
|
static CK_BBOOL xKeyIsInitialized = CK_FALSE;
|
|
|
|
/* Acquire a crypto session handle. */
|
|
xResult = prvSocketsGetCryptoSession( &xSessionLock,
|
|
&xPkcs11Session,
|
|
&pxPkcs11FunctionList );
|
|
|
|
if( CKR_OK == xResult )
|
|
{
|
|
xSemaphoreTake( xSessionLock, portMAX_DELAY );
|
|
|
|
if( CK_FALSE == xKeyIsInitialized )
|
|
{
|
|
/* One-time initialization, per boot, of the random seed. */
|
|
xResult = pxPkcs11FunctionList->C_GenerateRandom( xPkcs11Session,
|
|
( CK_BYTE_PTR ) &ullKey,
|
|
sizeof( ullKey ) );
|
|
|
|
if( xResult == CKR_OK )
|
|
{
|
|
xKeyIsInitialized = CK_TRUE;
|
|
}
|
|
}
|
|
|
|
xSemaphoreGive( xSessionLock );
|
|
}
|
|
|
|
/* Lock the shared crypto session. */
|
|
xSemaphoreTake( xSessionLock, portMAX_DELAY );
|
|
|
|
/* Start a hash. */
|
|
if( CKR_OK == xResult )
|
|
{
|
|
xMechSha256.mechanism = CKM_SHA256;
|
|
xResult = pxPkcs11FunctionList->C_DigestInit( xPkcs11Session, &xMechSha256 );
|
|
}
|
|
|
|
/* Hash the seed. */
|
|
if( CKR_OK == xResult )
|
|
{
|
|
xResult = pxPkcs11FunctionList->C_DigestUpdate( xPkcs11Session,
|
|
( CK_BYTE_PTR ) &ullKey,
|
|
sizeof( ullKey ) );
|
|
}
|
|
|
|
/* Hash the source address. */
|
|
if( CKR_OK == xResult )
|
|
{
|
|
xResult = pxPkcs11FunctionList->C_DigestUpdate( xPkcs11Session,
|
|
( CK_BYTE_PTR ) &ulSourceAddress,
|
|
sizeof( ulSourceAddress ) );
|
|
}
|
|
|
|
/* Hash the source port. */
|
|
if( CKR_OK == xResult )
|
|
{
|
|
xResult = pxPkcs11FunctionList->C_DigestUpdate( xPkcs11Session,
|
|
( CK_BYTE_PTR ) &usSourcePort,
|
|
sizeof( usSourcePort ) );
|
|
}
|
|
|
|
/* Hash the destination address. */
|
|
if( CKR_OK == xResult )
|
|
{
|
|
xResult = pxPkcs11FunctionList->C_DigestUpdate( xPkcs11Session,
|
|
( CK_BYTE_PTR ) &ulDestinationAddress,
|
|
sizeof( ulDestinationAddress ) );
|
|
}
|
|
|
|
/* Hash the destination port. */
|
|
if( CKR_OK == xResult )
|
|
{
|
|
xResult = pxPkcs11FunctionList->C_DigestUpdate( xPkcs11Session,
|
|
( CK_BYTE_PTR ) &usDestinationPort,
|
|
sizeof( usDestinationPort ) );
|
|
}
|
|
|
|
/* Get the hash. */
|
|
if( CKR_OK == xResult )
|
|
{
|
|
xResult = pxPkcs11FunctionList->C_DigestFinal( xPkcs11Session,
|
|
ucSha256Result,
|
|
&ulLength );
|
|
}
|
|
|
|
xSemaphoreGive( xSessionLock );
|
|
|
|
/* Use the first four bytes of the hash result as the starting point for
|
|
* all initial sequence numbers for connections based on the input 4-tuple. */
|
|
if( CKR_OK == xResult )
|
|
{
|
|
memcpy( &ulNextSequenceNumber,
|
|
ucSha256Result,
|
|
sizeof( ulNextSequenceNumber ) );
|
|
|
|
/* Add the tick count of four-tick intervals. In theory, per the RFC
|
|
* (see above), this approach still allows server equipment to optimize
|
|
* handling of connections from the same device that haven't fully timed out. */
|
|
ulNextSequenceNumber += xTaskGetTickCount() / 4;
|
|
}
|
|
return ulNextSequenceNumber;
|
|
#else
|
|
/* THIS IS ONLY A DUMMY IMPLEMENTATION
|
|
* THAT RETURNS A PSEUDO RANDOM NUMBER SO IS NOT INTENDED FOR USE IN PRODUCTION
|
|
* SYSTEMS. */
|
|
return uxRand();
|
|
#endif
|
|
}
|
|
|
|
|
|
/**! \func void vApplicationMallocFailedHook( void )
|
|
* \brief This hook function is called when allocation failed.
|
|
*/
|
|
void vApplicationMallocFailedHook( void )
|
|
{
|
|
FreeRTOS_debug_printf(("Malloc Failed Hook\n"));
|
|
BKPT_DEBUG();
|
|
}
|
|
|
|
|
|
/**! \func vApplicationTickHook( void )
|
|
* \brief Toggles LED5_TICK to indicate RTOS running well
|
|
*/
|
|
void vApplicationTickHook( void )
|
|
{
|
|
static uint16_t tickCounter = 0;
|
|
if(++tickCounter == configTICK_RATE_HZ)
|
|
{
|
|
gpio_bit_reset(LED5_TICK_PORT, LED5_TICK);
|
|
tickCounter = 0;
|
|
}
|
|
else if(tickCounter == configTICK_RATE_HZ/2)
|
|
{
|
|
gpio_bit_set(LED5_TICK_PORT, LED5_TICK);
|
|
}
|
|
}
|
|
|
|
/**! \func vApplicationIdleHook( void )
|
|
* \brief Idle task Hook
|
|
*/
|
|
void vApplicationIdleHook( void )
|
|
{
|
|
#if defined (DEBUG)
|
|
int32_t delta = (configTICK_RATE_HZ-(TASK_TOGGLE_LED_DELAY + TASK_HELLO_WORLD_DELAY)) % configTICK_RATE_HZ;
|
|
if (delta < 0) delta = -delta;
|
|
|
|
static uint32_t idleHookCounter = 0;
|
|
uint32_t currentTick = xTaskGetTickCount();
|
|
if(currentTick > idleHookCounter + delta)
|
|
{
|
|
FreeRTOS_debug_printf(("Idle Hook %d\n", idleHookCounter));//__ASM("BKPT #0\n");
|
|
}
|
|
idleHookCounter = currentTick;
|
|
#endif
|
|
}
|
|
|
|
/**! \func vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName )
|
|
* \brief Stack overflow Hook
|
|
*/
|
|
void vApplicationStackOverflowHook( TaskHandle_t pxTask, char *pcTaskName )
|
|
{
|
|
FreeRTOS_debug_printf(("Stack Overflow Hook\n"));
|
|
BKPT_DEBUG();
|
|
}
|
|
|
|
|
|
__attribute__((used)) void prvGetRegistersFromStack( uint32_t *pulFaultStackAddress )
|
|
{
|
|
/* These are volatile to try and prevent the compiler/linker optimising them
|
|
away as the variables never actually get used. If the debugger won't show the
|
|
values of the variables, make them global my moving their declaration outside
|
|
of this function. */
|
|
static volatile uint32_t r0;
|
|
static volatile uint32_t r1;
|
|
static volatile uint32_t r2;
|
|
static volatile uint32_t r3;
|
|
static volatile uint32_t r12;
|
|
static volatile uint32_t lr; /* Link register. */
|
|
static volatile uint32_t pc; /* Program counter. */
|
|
static volatile uint32_t psr;/* Program status register. */
|
|
|
|
r0 = pulFaultStackAddress[ 0 ];
|
|
r1 = pulFaultStackAddress[ 1 ];
|
|
r2 = pulFaultStackAddress[ 2 ];
|
|
r3 = pulFaultStackAddress[ 3 ];
|
|
|
|
r12 = pulFaultStackAddress[ 4 ];
|
|
lr = pulFaultStackAddress[ 5 ];
|
|
pc = pulFaultStackAddress[ 6 ];
|
|
psr = pulFaultStackAddress[ 7 ];
|
|
|
|
FreeRTOS_debug_printf(("Hard Fault Hook\n"));
|
|
BKPT_DEBUG();
|
|
|
|
NVIC_SystemReset();
|
|
/* When the following line is hit, the variables contain the register values. */
|
|
for( ;; );
|
|
}
|
|
|
|
void DelayMS(unsigned char ms)
|
|
{
|
|
unsigned long us = 1000*ms;
|
|
|
|
while (us--)
|
|
{
|
|
__NOP();
|
|
}
|
|
}
|
|
|