text: /* USER CODE BEGIN Header */
  /**
    ******************************************************************************
    * @file           : main.c
    * @brief          : Main program body
    ******************************************************************************
    * @attention
    *
    * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
    * All rights reserved.</center></h2>
    *
    * This software component is licensed by ST under Ultimate Liberty license
    * SLA0044, the "License"; You may not use this file except in compliance with
    * the License. You may obtain a copy of the License at:
    *                             www.st.com/SLA0044
    *
    ******************************************************************************
    */
  /* USER CODE END Header */
  
  /* Includes ------------------------------------------------------------------*/
  #include "main.h"
  #include "cmsis_os.h"
  #include "usb_device.h"
  
  /* Private includes ----------------------------------------------------------*/
  /* USER CODE BEGIN Includes */
  
  #include "usbd_cdc.h"	//just for the XXX_USBCDC_PresenceHack()
  #include "system_interfaces.h"
  #include "serial_devices.h"
  #include "util_circbuff2.h"
  
  #include "lamps.h"
  #include "task_notification_bits.h"
  
  #include "CarelessWSPR_settings.h"
  
  #include "task_monitor.h"
  #include "task_gps.h"
  #include "task_wspr.h"
  
  #include "maidenhead.h"
  #include "si5351a.h"
  #include "wspr.h"
  
  #include "backup_registers.h"
  
  
  #ifndef COUNTOF
  #define COUNTOF(arr) (sizeof(arr)/sizeof(arr[0]))
  #endif
  
  //This controls whether we use the FreeRTOS heap implementation to also provide
  //the libc malloc() and friends.
  #define USE_FREERTOS_HEAP_IMPL 1
  
  volatile int dummy;	//XXX for debugging; delete
  #ifdef DEBUG
  volatile size_t g_nHeapFree;
  volatile size_t g_nMinEverHeapFree;
  volatile int g_nMaxGPSRxQueue;
  volatile int g_nMaxCDCTxQueue;
  volatile int g_nMaxCDCRxQueue;
  volatile int g_nMinStackFreeDefault;
  volatile int g_nMinStackFreeMonitor;
  volatile int g_nMinStackFreeGPS;
  volatile int g_nMinStackFreeWSPR;
  #endif
  
  #if USE_FREERTOS_HEAP_IMPL
  
  #if configAPPLICATION_ALLOCATED_HEAP
  //we define our heap (to be used by FreeRTOS heap_4.c implementation) to be
  //exactly where we want it to be.
  __attribute__((aligned(8))) 
  uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
  #endif
  //we implemented a 'realloc' for a heap_4 derived implementation
  extern void* pvPortRealloc( void* pvOrig, size_t xWantedSize );
  //we implemented a 'heapwalk' function
  typedef int (*CBK_HEAPWALK) ( void* pblk, uint32_t nBlkSize, int bIsFree, void* pinst );
  extern int vPortHeapWalk ( CBK_HEAPWALK pfnWalk, void* pinst );
  
  //'wrapped functions' for library interpositioning
  //you must specify these gcc (linker-directed) options to cause the wrappers'
  //delights to be generated:
  
  //-Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,realloc -Wl,--wrap,calloc
  //-Wl,--wrap,_malloc_r -Wl,--wrap,_free_r -Wl,--wrap,_realloc_r -Wl,--wrap,_calloc_r
  
  //hmm; can I declare these 'inline' and save a little code and stack?
  void* __wrap_malloc ( size_t size ) { return pvPortMalloc ( size ); }
  void __wrap_free ( void* pv ) { vPortFree ( pv ); }
  void* __wrap_realloc ( void* pv, size_t size ) { return pvPortRealloc ( pv, size ); }
  
  void* __wrap__malloc_r ( struct _reent* r, size_t size ) { return pvPortMalloc ( size ); }
  void __wrap__free_r ( struct _reent* r, void* pv ) { vPortFree ( pv ); }
  void* __wrap__realloc_r ( struct _reent* r, void* pv, size_t size ) { return pvPortRealloc ( pv, size ); }
  
  #endif
  
  /* USER CODE END Includes */
  
  /* Private typedef -----------------------------------------------------------*/
  /* USER CODE BEGIN PTD */
  
  /* USER CODE END PTD */
  
  /* Private define ------------------------------------------------------------*/
  /* USER CODE BEGIN PD */
  
  /* USER CODE END PD */
  
  /* Private macro -------------------------------------------------------------*/
  /* USER CODE BEGIN PM */
  
  /* USER CODE END PM */
  
  /* Private variables ---------------------------------------------------------*/
  I2C_HandleTypeDef hi2c1;
  
  RTC_HandleTypeDef hrtc;
  
  TIM_HandleTypeDef htim4;
  
  UART_HandleTypeDef huart1;
  
  osThreadId defaultTaskHandle;
  uint32_t defaultTaskBuffer[ 128 ];
  osStaticThreadDef_t defaultTaskControlBlock;
  /* USER CODE BEGIN PV */
  
  /* USER CODE END PV */
  
  /* Private function prototypes -----------------------------------------------*/
  void SystemClock_Config(void);
  static void MX_GPIO_Init(void);
  static void MX_RTC_Init(void);
  static void MX_I2C1_Init(void);
  static void MX_USART1_UART_Init(void);
  static void MX_TIM4_Init(void);
  void StartDefaultTask(void const * argument);
  
  /* USER CODE BEGIN PFP */
  
  /* USER CODE END PFP */
  
  /* Private user code ---------------------------------------------------------*/
  /* USER CODE BEGIN 0 */
  
  /* USER CODE END 0 */
  
  /**
    * @brief  The application entry point.
    * @retval int
    */
  int main(void)
  {
    /* USER CODE BEGIN 1 */
  	//enable the core debug cycle counter to be used as a precision timer
  	CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
  	DWT->CYCCNT = 0;
  	DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
    /* USER CODE END 1 */
    
  
    /* MCU Configuration--------------------------------------------------------*/
  
    /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
    HAL_Init();
  
    /* USER CODE BEGIN Init */
  
  	//if you get a linker fail on the following, it is because some manual
  	//changes to:
  	//  .\Middlewares\ST\STM32_USB_Device_Library\Class\CDC\Inc\usbd_cdc.h
  	//  .\Middlewares\ST\STM32_USB_Device_Library\Class\CDC\Src\usbd_cdc.c
  	//  .\Src\usbd_cdc_if.c
  	//must be applied.  There are backups of those files to help with that.
  	//This has to be done manually, because the changes are in tool generated
  	//code that gets overwritten when you re-run STM32CubeMX.  The nature of
  	//those changes are such that when they are overwritten, you will still
  	//be able to build but stuff won't work at runtime.  This hack will cause
  	//the build to fail if you forget to merge those changes back on, thus
  	//prompting you to do so.
  	//Sorry for the inconvenience, but I don't think there is any better way
  	//of making it obvious that this chore simply must be done.
  	XXX_USBCDC_PresenceHack();	//this does nothing real; do not delete
  
    /* USER CODE END Init */
  
    /* Configure the system clock */
    SystemClock_Config();
  
    /* USER CODE BEGIN SysInit */
  
  	//do a dummy alloc to cause the heap to be init'ed and so the memory stats as well
  	vPortFree ( pvPortMalloc ( 0 ) );
  
  	//get system config depersisted from flash before we do much more
  	Settings_depersist();
  
    /* USER CODE END SysInit */
  
    /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_RTC_Init();
    MX_I2C1_Init();
    MX_USART1_UART_Init();
    MX_TIM4_Init();
    /* USER CODE BEGIN 2 */
  
    /* USER CODE END 2 */
  
    /* USER CODE BEGIN RTOS_MUTEX */
    /* add mutexes, ... */
    /* USER CODE END RTOS_MUTEX */
  
    /* USER CODE BEGIN RTOS_SEMAPHORES */
    /* add semaphores, ... */
    /* USER CODE END RTOS_SEMAPHORES */
  
    /* USER CODE BEGIN RTOS_TIMERS */
    /* start timers, add new ones, ... */
    /* USER CODE END RTOS_TIMERS */
  
    /* USER CODE BEGIN RTOS_QUEUES */
    /* add queues, ... */
    /* USER CODE END RTOS_QUEUES */
  
    /* Create the thread(s) */
    /* definition and creation of defaultTask */
    osThreadStaticDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 128, defaultTaskBuffer, &defaultTaskControlBlock);
    defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);
  
    /* USER CODE BEGIN RTOS_THREADS */
    /* add threads, ... */
    /* USER CODE END RTOS_THREADS */
  
    /* Start scheduler */
    osKernelStart();
    
    /* We should never get here as control is now taken by the scheduler */
  
    /* Infinite loop */
    /* USER CODE BEGIN WHILE */
    while (1)
    {
      /* USER CODE END WHILE */
  
      /* USER CODE BEGIN 3 */
    }
    /* USER CODE END 3 */
  }
  
  /**
    * @brief System Clock Configuration
    * @retval None
    */
  void SystemClock_Config(void)
  {
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
    RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
  
    /** Initializes the CPU, AHB and APB busses clocks 
    */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE|RCC_OSCILLATORTYPE_LSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
    RCC_OscInitStruct.LSEState = RCC_LSE_ON;
    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
      Error_Handler();
    }
    /** Initializes the CPU, AHB and APB busses clocks 
    */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                                |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
  
    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
    {
      Error_Handler();
    }
    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_RTC|RCC_PERIPHCLK_USB;
    PeriphClkInit.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
    PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    {
      Error_Handler();
    }
  }
  
  /**
    * @brief I2C1 Initialization Function
    * @param None
    * @retval None
    */
  static void MX_I2C1_Init(void)
  {
  
    /* USER CODE BEGIN I2C1_Init 0 */
  
    /* USER CODE END I2C1_Init 0 */
  
    /* USER CODE BEGIN I2C1_Init 1 */
  
    /* USER CODE END I2C1_Init 1 */
    hi2c1.Instance = I2C1;
    hi2c1.Init.ClockSpeed = 400000;
    hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
    hi2c1.Init.OwnAddress1 = 0;
    hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
    hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    hi2c1.Init.OwnAddress2 = 0;
    hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
    if (HAL_I2C_Init(&hi2c1) != HAL_OK)
    {
      Error_Handler();
    }
    /* USER CODE BEGIN I2C1_Init 2 */
  
    /* USER CODE END I2C1_Init 2 */
  
  }
  
  /**
    * @brief RTC Initialization Function
    * @param None
    * @retval None
    */
  static void MX_RTC_Init(void)
  {
  
    /* USER CODE BEGIN RTC_Init 0 */
  
    /* USER CODE END RTC_Init 0 */
  
    RTC_TimeTypeDef sTime = {0};
    RTC_DateTypeDef DateToUpdate = {0};
  
    /* USER CODE BEGIN RTC_Init 1 */
  
    /* USER CODE END RTC_Init 1 */
    /** Initialize RTC Only 
    */
    hrtc.Instance = RTC;
    hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND;
    hrtc.Init.OutPut = RTC_OUTPUTSOURCE_NONE;
    if (HAL_RTC_Init(&hrtc) != HAL_OK)
    {
      Error_Handler();
    }
  
    /* USER CODE BEGIN Check_RTC_BKUP */
  	//we use one of the 'backup registers' to store some flags; the 'RTC set'
  	//is used to indicate we have set the clock at some point.  If this flag is
  	//set in the backup register, then we have /not power-cycled the board, and
  	//so we avoid the generated code, below which will blast the RTC setting.
  	HAL_PWR_EnableBkUpAccess();	//... and leave it that way
  	uint32_t flags = HAL_RTCEx_BKUPRead ( &hrtc, FLAGS_REGISTER );
  	if ( ! ( flags & FLAG_HAS_SET_RTC ) )
  	{	//ugly hack to skip needlessly setting the RTC via generated code
    /* USER CODE END Check_RTC_BKUP */
  
    /** Initialize RTC and set the Time and Date 
    */
    sTime.Hours = 0;
    sTime.Minutes = 0;
    sTime.Seconds = 0;
  
    if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
    {
      Error_Handler();
    }
    DateToUpdate.WeekDay = RTC_WEEKDAY_FRIDAY;
    DateToUpdate.Month = RTC_MONTH_JULY;
    DateToUpdate.Date = 26;
    DateToUpdate.Year = 19;
  
    if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BIN) != HAL_OK)
    {
      Error_Handler();
    }
    /* USER CODE BEGIN RTC_Init 2 */
  	}
  else
  	{
  		//If we have reset or woken up but aren't going to set the RTC because
  		//it was already set, then we at least need to do the following or we
  		//won't ever be able to write to the RTC (e.g. for setting alarm)
  		//NOTE:  on the 'F1's, the RTC is 'V1', which means that there is not
  		//date.  The date is emulated in software, and so is lost on reset,
  		//etc.  Fortunately, we don't really care about date in WSPR -- just
  		//time.
  		HAL_RTC_WaitForSynchro(&hrtc);
  	}	//end ugly hack to avoid some generated code
  
    /* USER CODE END RTC_Init 2 */
  
  }
  
  /**
    * @brief TIM4 Initialization Function
    * @param None
    * @retval None
    */
  static void MX_TIM4_Init(void)
  {
  
    /* USER CODE BEGIN TIM4_Init 0 */
  
    /* USER CODE END TIM4_Init 0 */
  
    TIM_ClockConfigTypeDef sClockSourceConfig = {0};
    TIM_MasterConfigTypeDef sMasterConfig = {0};
  
    /* USER CODE BEGIN TIM4_Init 1 */
  
    /* USER CODE END TIM4_Init 1 */
    htim4.Instance = TIM4;
    htim4.Init.Prescaler = 4095;
    htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim4.Init.Period = 11999;
    htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
    if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
    {
      Error_Handler();
    }
    sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
    if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
    {
      Error_Handler();
    }
    sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
    {
      Error_Handler();
    }
    /* USER CODE BEGIN TIM4_Init 2 */
  
    /* USER CODE END TIM4_Init 2 */
  
  }
  
  /**
    * @brief USART1 Initialization Function
    * @param None
    * @retval None
    */
  static void MX_USART1_UART_Init(void)
  {
  
    /* USER CODE BEGIN USART1_Init 0 */
  
    /* USER CODE END USART1_Init 0 */
  
    /* USER CODE BEGIN USART1_Init 1 */
  
    /* USER CODE END USART1_Init 1 */
    huart1.Instance = USART1;
    huart1.Init.BaudRate = 9600;
    huart1.Init.WordLength = UART_WORDLENGTH_8B;
    huart1.Init.StopBits = UART_STOPBITS_1;
    huart1.Init.Parity = UART_PARITY_NONE;
    huart1.Init.Mode = UART_MODE_TX_RX;
    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    huart1.Init.OverSampling = UART_OVERSAMPLING_16;
    if (HAL_UART_Init(&huart1) != HAL_OK)
    {
      Error_Handler();
    }
    /* USER CODE BEGIN USART1_Init 2 */
  
    /* USER CODE END USART1_Init 2 */
  
  }
  
  /**
    * @brief GPIO Initialization Function
    * @param None
    * @retval None
    */
  static void MX_GPIO_Init(void)
  {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
  
    /* GPIO Ports Clock Enable */
    __HAL_RCC_GPIOC_CLK_ENABLE();
    __HAL_RCC_GPIOD_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();
    __HAL_RCC_GPIOB_CLK_ENABLE();
  
    /*Configure GPIO pin Output Level */
    HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET);
  
    /*Configure GPIO pin : LED2_Pin */
    GPIO_InitStruct.Pin = LED2_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(LED2_GPIO_Port, &GPIO_InitStruct);
  
    /*Configure GPIO pins : PA0 PA1 PA2 PA3 
                             PA4 PA5 PA6 PA7 
                             PA8 PA15 */
    GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3 
                            |GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7 
                            |GPIO_PIN_8|GPIO_PIN_15;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  
    /*Configure GPIO pins : PB0 PB1 PB10 PB11 
                             PB12 PB13 PB14 PB15 
                             PB3 PB4 PB5 PB6 
                             PB7 */
    GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_10|GPIO_PIN_11 
                            |GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15 
                            |GPIO_PIN_3|GPIO_PIN_4|GPIO_PIN_5|GPIO_PIN_6 
                            |GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
  
    /*Configure GPIO pin : BOOT1_Pin */
    GPIO_InitStruct.Pin = BOOT1_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(BOOT1_GPIO_Port, &GPIO_InitStruct);
  
  }
  
  /* USER CODE BEGIN 4 */
  
  
  
  //====================================================
  
  
  //this is made a function simply for tidiness, and locals lifetime
  void __startWorkerTasks ( void )
  {
  	//kick off the monitor thread, which handles the user interactions
  	{
  	osThreadStaticDef(taskMonitor, thrdfxnMonitorTask, osPriorityNormal, 0, COUNTOF(g_tbMonitor), g_tbMonitor, &g_tcbMonitor);
  	g_thMonitor = osThreadCreate(osThread(taskMonitor), NULL);
  	}
  
  	//kick off the GPS thread, which handles incoming NMEA data
  	{
  	osThreadStaticDef(taskGPS, thrdfxnGPSTask, osPriorityNormal, 0, COUNTOF(g_tbGPS), g_tbGPS, &g_tcbGPS);
  	g_thGPS = osThreadCreate(osThread(taskGPS), NULL);
  	}
  
  	//kick off WSPR thread, which performs WSPR sending
  	{
  	osThreadStaticDef(taskWSPR, thrdfxnWSPRTask, osPriorityNormal, 0, COUNTOF(g_tbWSPR), g_tbWSPR, &g_tcbWSPR);
  	g_thWSPR = osThreadCreate(osThread(taskWSPR), NULL);
  	}
  }
  
  
  //====================================================
  
  
  
  void vApplicationStackOverflowHook(xTaskHandle xTask, signed char *pcTaskName)
  {
  	/* Run time stack overflow checking is performed if
  	configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2. This hook function is
  	called if a stack overflow is detected. */
  	volatile int i = 0;
  	(void)i;
  }
  
  
  
  void vApplicationMallocFailedHook(void)
  {
  	/* vApplicationMallocFailedHook() will only be called if
  	configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h. It is a hook
  	function that will get called if a call to pvPortMalloc() fails.
  	pvPortMalloc() is called internally by the kernel whenever a task, queue,
  	timer or semaphore is created. It is also called by various parts of the
  	demo application. If heap_1.c or heap_2.c are used, then the size of the
  	heap available to pvPortMalloc() is defined by configTOTAL_HEAP_SIZE in
  	FreeRTOSConfig.h, and the xPortGetFreeHeapSize() API function can be used
  	to query the size of free heap space that remains (although it does not
  	provide information on how the remaining heap might be fragmented). */
  	volatile int i = 0;
  	(void)i;
  }
  
  
  
  //====================================================
  //EXTI support
  
  
  void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
  {
  /*
  	switch ( GPIO_Pin )
  	{
  		default:
  			//XXX que?
  		break;
  	}
  */
  }
  
  
  
  void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
  {
  	//We use the RTC alarm to schedule a WSPR transmission start
  	WSPR_RTC_Alarm();
  }
  
  
  
  /* USER CODE END 4 */
  
  /* USER CODE BEGIN Header_StartDefaultTask */
  /**
    * @brief  Function implementing the defaultTask thread.
    * @param  argument: Not used 
    * @retval None
    */
  /* USER CODE END Header_StartDefaultTask */
  void StartDefaultTask(void const * argument)
  {
      
      
                   
    /* init code for USB_DEVICE */
    MX_USB_DEVICE_Init();
  
    /* USER CODE BEGIN 5 */
  
  	//init the synth now
  	si5351aInit();
  
  	//initialize the WSPR engine
  	WSPR_Initialize();
  
  	//crank up serial ports
  	//XXX (I wonder if this is best way up in main at least for USB; I ask
  	//because the MX_USB_DEVICE_Init() above could conceivably stimulate
  	//action on these buffers before they have been initialized
  	UART1_Init();	//UART1 == GPS
  	USBCDC_Init();	//CDC == monitor
  
  	//bind the interfaces to the relevant devices
  	g_pMonitorIOIf = &g_pifCDC;		//monitor is on USB CDC
  	g_pGPSIOIf = &g_pifUART1;		//GPS is on UART1
  	//light some lamps on a countdown
  	LightLamp ( 1000, &g_lltGn, _ledOnGn );
  
  	//start up worker threads
  	__startWorkerTasks();
  
  	//================================================
  	//continue running this task
  	//This task, the 'default' task, was generated by the tool, and it's easier
  	//to just keep it than to fight the tool to destroy it (though some of that
  	//fighting can be made a little easier if it was dynamically allocated,
  	//then just exited).  We repurpose it after init to handle the lamps and
  	//periodically sample performance data (useful for tuning pre-release).
  
  	//Infinite loop
  	uint32_t msWait = 1000;
  	for(;;)
  	{
  		//wait on various task notifications
  		uint32_t ulNotificationValue;
  		BaseType_t xResult = xTaskNotifyWait( pdFALSE,	//Don't clear bits on entry.
  				0xffffffff,	//Clear all bits on exit.
  				&ulNotificationValue,	//Stores the notified value.
  				pdMS_TO_TICKS(msWait) );
  		if( xResult == pdPASS )
  		{
  			//the lights have changed
  			if ( ulNotificationValue & TNB_LIGHTSCHANGED )
  			{
  				//XXX
  			}
  		}
  		else	//timeout on wait
  		{
  			//XXX things to do on periodic idle timeout
  		}
  		
  #ifdef DEBUG
  		//XXX these are to tune the freertos heap size; if we have a heap
  #if USE_FREERTOS_HEAP_IMPL
  		g_nHeapFree = xPortGetFreeHeapSize();
  		g_nMinEverHeapFree = xPortGetMinimumEverFreeHeapSize();
  #else
  		g_nMinEverHeapFree = (char*)platform_get_last_free_ram( 0 ) - (char*)platform_get_first_free_ram( 0 );
  #endif
  		g_nMaxGPSRxQueue = UART1_rxbuff_max();
  		g_nMaxCDCTxQueue = CDC_txbuff_max();
  		g_nMaxCDCRxQueue = CDC_rxbuff_max();
  		//free stack space measurements
  		g_nMinStackFreeDefault = uxTaskGetStackHighWaterMark ( defaultTaskHandle );
  		g_nMinStackFreeMonitor = uxTaskGetStackHighWaterMark ( g_thMonitor );
  		g_nMinStackFreeGPS = uxTaskGetStackHighWaterMark ( g_thGPS );
  		g_nMinStackFreeWSPR = uxTaskGetStackHighWaterMark ( g_thWSPR );
  		//XXX others
  #endif
  		
  		//turn out the lights, the party's over
  		uint32_t now = HAL_GetTick();
  		uint32_t remMin = 0xffffffff;	//nothing yet
  		ProcessLightOffTime ( now, &remMin, &g_lltGn, _ledOffGn );
  
  		//don't wait longer than 3 sec
  		if ( remMin > 3000 )
  			remMin = 3000;
  		
  		msWait = remMin;
  	}
  
    /* USER CODE END 5 */ 
  }
  
  /**
    * @brief  Period elapsed callback in non blocking mode
    * @note   This function is called  when TIM2 interrupt took place, inside
    * HAL_TIM_IRQHandler(). It makes a direct call to HAL_IncTick() to increment
    * a global variable "uwTick" used as application time base.
    * @param  htim : TIM handle
    * @retval None
    */
  void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
  {
    /* USER CODE BEGIN Callback 0 */
  
    /* USER CODE END Callback 0 */
    if (htim->Instance == TIM2) {
      HAL_IncTick();
    }
    /* USER CODE BEGIN Callback 1 */
  
  	else if (htim->Instance == TIM4)
  	{
  		//we use TIM4 for WSPR bit pacing
  		WSPR_Timer_Timeout();
  	}
  
    /* USER CODE END Callback 1 */
  }
  
  /**
    * @brief  This function is executed in case of error occurrence.
    * @retval None
    */
  void Error_Handler(void)
  {
    /* USER CODE BEGIN Error_Handler_Debug */
    /* User can add his own implementation to report the HAL error return state */
  	volatile int i = 0;
  	(void)i;
    /* USER CODE END Error_Handler_Debug */
  }
  
  #ifdef  USE_FULL_ASSERT
  /**
    * @brief  Reports the name of the source file and the source line number
    *         where the assert_param error has occurred.
    * @param  file: pointer to the source file name
    * @param  line: assert_param error line source number
    * @retval None
    */
  void assert_failed(uint8_t *file, uint32_t line)
  { 
    /* USER CODE BEGIN 6 */
    /* User can add his own implementation to report the file name and line number,
       tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  	volatile int i = 0;
  	(void)i;
    /* USER CODE END 6 */
  }
  #endif /* USE_FULL_ASSERT */
  
  /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
  