/*
 * Copyright (c) 2026, windnerd.net
 * All rights reserved.
 *
 * This source code is licensed under the BSD 3-Clause License found in the
 * LICENSE file in the root directory of this source tree.
 */

#include "Arduino.h"
#include "Windnerd_Core.h"
#include "stm32g0xx_hal.h"  // necessary to change clock settings


WN_Core Anemometer;

HardwareSerial SerialOutput(USART2);  // TX2 on WindNerd Core board (yellow wire)
HardwareSerial SerialDebug(USART1);   // RX1 and TX1 on WindNerd Core board (headers connector)

// called every 3 seconds, gives instant wind speed + direction
void instantWindCallback(wn_instant_wind_sample_t sample) {
  // Build base sentence (without checksum)
  String sentence = "$IIMWV,";

  // Wind direction formatted to 3 digits
  if (sample.dir < 100) sentence += "0";
  if (sample.dir < 10) sentence += "0";
  sentence += String(sample.dir);

  sentence += ",R,";
  sentence += String(sample.speed, 1);  // 1 decimal
  sentence += ",N,A";

  // Calculate checksum
  byte checksum = 0;
  for (int i = 1; i < sentence.length(); i++)  // skip '$'
  {
    checksum ^= sentence[i];
  }

  // Add checksum in HEX
  sentence += "*";
  if (checksum < 16) sentence += "0";  // leading zero if needed
  sentence += String(checksum, HEX);

  // NMEA requires uppercase HEX
  sentence.toUpperCase();

  // Send with CRLF
  SerialOutput.println(sentence);
}


void setup() {

  SerialOutput.begin(4800);
  SerialDebug.begin(115200);

  Anemometer.invertVanePolarity(false);                  // change to true if you notice north and south are inverted
  Anemometer.setSpeedUnit(UNIT_KN);                      // NMEA requires knot as unit  
  Anemometer.onInstantWindUpdate(&instantWindCallback);  // set the callback for instant wind

  Anemometer.begin();
}

void loop() {
  Anemometer.loop();


  // put the MCU to sleep, the WindNerd Core library uses a timer interrupt to wake it up automatically when needed
  HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
}

// this is an override to set the SYS clock at 8MHz in order to reduce power consumption
// this code was generated by STM32CubeMx
void SystemClock_Config(void) {
  RCC_OscInitTypeDef RCC_OscInitStruct = { 0 };
  RCC_ClkInitTypeDef RCC_ClkInitStruct = { 0 };

  /** Configure the main internal regulator output voltage
   */
  HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);

  /** Initializes the RCC Oscillators according to the specified parameters
   * in the RCC_OscInitTypeDef structure.
   */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV2;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
   */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) {
    Error_Handler();
  }

  SystemCoreClockUpdate();
}
