/* * Amazon FreeRTOS * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * http://aws.amazon.com/freertos * http://www.FreeRTOS.org */ /** * @file main.c * @brief Implements the main function. */ /* FreeRTOS include. */ #include #include "task.h" /* Standard includes. */ #include #include #include #include /* Test runner includes. */ #include "aws_test_runner.h" /* AWS System application includes. */ #include "FreeRTOS_IP.h" #include "FreeRTOS_Sockets.h" #include "FreeRTOS_DHCP.h" #include "aws_demo_logging.h" #include "aws_system_init.h" #include "aws_dev_mode_key_provisioning.h" /* Unity includes. */ #include "unity.h" /* Define a name that will be used for LLMNR and NBNS searches. Once running, * you can "ping RTOSDemo" instead of pinging the IP address, which is useful when * using DHCP. */ #define mainHOST_NAME "TestRunner" #define mainDEVICE_NICK_NAME "windows_TestRunner" #define TEST_RUNNER_TASK_STACK_SIZE 10000 #define FIRST_EXCEPTION_HANDLER 1 /* Windows-NT VectoredHandler callback function. */ static LONG CALLBACK prvExceptionHandler( _In_ PEXCEPTION_POINTERS ExceptionInfo ); jmp_buf xMark; /* Address for long jump to jump to. */ /*-----------------------------------------------------------*/ /* * Writes trace data to a disk file when the trace recording is stopped. * This function will simply overwrite any trace files that already exist. */ static void prvSaveTraceFile( void ); /*-----------------------------------------------------------*/ /* Notes if the trace is running or not. */ static BaseType_t xTraceRunning = pdTRUE; /* 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 }; /*-----------------------------------------------------------*/ int main( void ) { /* Register the Windows VEH for exceptions. */ AddVectoredExceptionHandler( FIRST_EXCEPTION_HANDLER, prvExceptionHandler ); vTraceEnable( TRC_START ); /* Initialize logging for libraries that depend on it. */ vLoggingInit( pdTRUE, pdFALSE, pdFALSE, 0, 0 ); /* Initialize the network interface. * ***NOTE*** Tasks that use the network are created in the network event hook * when the network is connected and ready for use (see the definition of * vApplicationIPNetworkEventHook() below). The address values passed in here * are used if ipconfigUSE_DHCP is set to 0, or if ipconfigUSE_DHCP is set to 1 * but a DHCP server cannot be contacted. */ FreeRTOS_printf( ( "FreeRTOS_IPInit\n" ) ); FreeRTOS_IPInit( ucIPAddress, ucNetMask, ucGatewayAddress, ucDNSServerAddress, ucMACAddress ); /* Initialize AWS system libraries. */ SYSTEM_Init(); vDevModeKeyProvisioning(); vTaskStartScheduler(); return 0; } /*-----------------------------------------------------------*/ void vApplicationIPNetworkEventHook( eIPCallbackEvent_t eNetworkEvent ) { static BaseType_t xTasksAlreadyCreated = pdFALSE; /* If the network has just come up...*/ if( ( eNetworkEvent == eNetworkUp ) && ( xTasksAlreadyCreated == pdFALSE ) ) { xTaskCreate( TEST_RUNNER_RunTests_task, "TestRunner", TEST_RUNNER_TASK_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL ); xTasksAlreadyCreated = pdTRUE; } } /*-----------------------------------------------------------*/ static LONG CALLBACK prvExceptionHandler( _In_ PEXCEPTION_POINTERS ExceptionInfo ) { /* If this function is called during a test, the test immediately fails. */ TEST_FAIL(); return EXCEPTION_CONTINUE_EXECUTION; } /*-----------------------------------------------------------*/ #if ( ( ipconfigUSE_LLMNR != 0 ) || \ ( ipconfigUSE_NBNS != 0 ) || \ ( ipconfigDHCP_REGISTER_HOSTNAME == 1 ) ) const char * pcApplicationHostnameHook( void ) { /* This function will be called during the DHCP: the machine will be registered * with an IP address plus this name. */ return mainHOST_NAME; } #endif /* if ( ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) || ( ipconfigDHCP_REGISTER_HOSTNAME == 1 ) ) */ /*-----------------------------------------------------------*/ #if ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) BaseType_t xApplicationDNSQueryHook( const char * pcName ) { BaseType_t xReturn; /* Determine if a name lookup is for this node. Two names are given * to this node: that returned by pcApplicationHostnameHook() and that set * by mainDEVICE_NICK_NAME. */ if( _stricmp( pcName, pcApplicationHostnameHook() ) == 0 ) { xReturn = pdPASS; } else if( _stricmp( pcName, mainDEVICE_NICK_NAME ) == 0 ) { xReturn = pdPASS; } else { xReturn = pdFAIL; } return xReturn; } #endif /* if ( ipconfigUSE_LLMNR != 0 ) || ( ipconfigUSE_NBNS != 0 ) */ /*-----------------------------------------------------------*/ void vApplicationIdleHook( void ) { const uint32_t ulMSToSleep = 1; const TickType_t xKitHitCheckPeriod = pdMS_TO_TICKS( 1000UL ); static TickType_t xTimeNow, xLastTimeCheck = 0; /* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set * to 1 in FreeRTOSConfig.h. It will be called on each iteration of the idle * task. It is essential that code added to this hook function never attempts * to block in any way (for example, call xQueueReceive() with a block time * specified, or call vTaskDelay()). If application tasks make use of the * vTaskDelete() API function to delete themselves then it is also important * that vApplicationIdleHook() is permitted to return to its calling function, * because it is the responsibility of the idle task to clean up memory * allocated by the kernel to any task that has since deleted itself. */ /* _kbhit() is a Windows system function, and system functions can cause * crashes if they somehow block the FreeRTOS thread. The call to _kbhit() * can be removed if it causes problems. Limiting the frequency of calls to * _kbhit() should minimize the potential for issues. */ xTimeNow = xTaskGetTickCount(); if( ( xTimeNow - xLastTimeCheck ) > xKitHitCheckPeriod ) { if( _kbhit() != pdFALSE ) { if( xTraceRunning == pdTRUE ) { xTraceRunning = pdFALSE; vTraceStop(); prvSaveTraceFile(); } } /* Uncomment the print line to get confirmation that tests are still * running if you suspect a previous run resulted in a crash. */ /* configPRINTF( ( "Running...\n" ) ); /**/ xLastTimeCheck = xTimeNow; } /* This is just a trivial example of an idle hook. It is called on each * cycle of the idle task if configUSE_IDLE_HOOK is set to 1 in * FreeRTOSConfig.h. It must *NOT* attempt to block. In this case the * idle task just sleeps to lower the CPU usage. */ Sleep( ulMSToSleep ); } /*-----------------------------------------------------------*/ void vAssertCalled( const char * pcFile, uint32_t ulLine ) { const uint32_t ulLongSleep = 1000UL; volatile uint32_t ulBlockVariable = 0UL; volatile char * pcFileName = ( volatile char * ) pcFile; volatile uint32_t ulLineNumber = ulLine; ( void ) pcFileName; ( void ) ulLineNumber; printf( "vAssertCalled %s, %ld\n", pcFile, ( long ) ulLine ); fflush( stdout ); /* Setting ulBlockVariable to a non-zero value in the debugger will allow * this function to be exited. */ taskDISABLE_INTERRUPTS(); { while( ulBlockVariable == 0UL ) { Sleep( ulLongSleep ); } } taskENABLE_INTERRUPTS(); } /*-----------------------------------------------------------*/ /* configUSE_STATIC_ALLOCATION is set to 1, so the application must provide an * implementation of vApplicationGetIdleTaskMemory() to provide the memory that is * used by the Idle task. */ void vApplicationGetIdleTaskMemory( StaticTask_t ** ppxIdleTaskTCBBuffer, StackType_t ** ppxIdleTaskStackBuffer, uint32_t * pulIdleTaskStackSize ) { /* If the buffers to be provided to the Idle task are declared inside this * function then they must be declared static - otherwise they will be allocated on * the stack and so not exists after this function exits. */ static StaticTask_t xIdleTaskTCB; static StackType_t uxIdleTaskStack[ configMINIMAL_STACK_SIZE ]; /* Pass out a pointer to the StaticTask_t structure in which the Idle * task's state will be stored. */ *ppxIdleTaskTCBBuffer = &xIdleTaskTCB; /* Pass out the array that will be used as the Idle task's stack. */ *ppxIdleTaskStackBuffer = uxIdleTaskStack; /* Pass out the size of the array pointed to by *ppxIdleTaskStackBuffer. * Note that, as the array is necessarily of type StackType_t, * configMINIMAL_STACK_SIZE is specified in words, not bytes. */ *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE; } /*-----------------------------------------------------------*/ /* configUSE_STATIC_ALLOCATION and configUSE_TIMERS are both set to 1, so the * application must provide an implementation of vApplicationGetTimerTaskMemory() * to provide the memory that is used by the Timer service task. */ void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer, StackType_t ** ppxTimerTaskStackBuffer, uint32_t * pulTimerTaskStackSize ) { /* If the buffers to be provided to the Timer task are declared inside this * function then they must be declared static - otherwise they will be allocated on * the stack and so not exists after this function exits. */ static StaticTask_t xTimerTaskTCB; static StackType_t uxTimerTaskStack[ configTIMER_TASK_STACK_DEPTH ]; /* Pass out a pointer to the StaticTask_t structure in which the Timer * task's state will be stored. */ *ppxTimerTaskTCBBuffer = &xTimerTaskTCB; /* Pass out the array that will be used as the Timer task's stack. */ *ppxTimerTaskStackBuffer = uxTimerTaskStack; /* Pass out the size of the array pointed to by *ppxTimerTaskStackBuffer. * Note that, as the array is necessarily of type StackType_t, * configTIMER_TASK_STACK_DEPTH is specified in words, not bytes. */ *pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH; } /*-----------------------------------------------------------*/ static void prvSaveTraceFile( void ) { FILE * pxOutputFile; fopen_s( &pxOutputFile, "Trace.dump", "wb" ); if( pxOutputFile != NULL ) { fwrite( RecorderDataPtr, sizeof( RecorderDataType ), 1, pxOutputFile ); fclose( pxOutputFile ); printf( "\r\nTrace output saved to Trace.dump\r\n" ); } else { printf( "\r\nFailed to create trace dump file\r\n" ); } } /*-----------------------------------------------------------*/ void getUserCmd( char * pucUserCmd ) { char cTmp; scanf( "%c%c", pucUserCmd, &cTmp ); } /*-----------------------------------------------------------*/ /** * @brief Warn user if pvPortMalloc fails. * * Called if a call to pvPortMalloc() fails because there is insufficient * free memory available in the FreeRTOS heap. pvPortMalloc() is called * internally by FreeRTOS API functions that create tasks, queues, software * timers, and semaphores. The size of the FreeRTOS heap is set by the * configTOTAL_HEAP_SIZE configuration constant in FreeRTOSConfig.h. * */ void vApplicationMallocFailedHook() { /* The TCP tests will test behavior when the entire heap is allocated. In * order to avoid interfering with those tests, this function does nothing. */ }