Skip to content

Instantly share code, notes, and snippets.

@nair-arjun
Created April 11, 2024 22:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nair-arjun/abecb59ae024f56b6264db46a049fd3a to your computer and use it in GitHub Desktop.
Save nair-arjun/abecb59ae024f56b6264db46a049fd3a to your computer and use it in GitHub Desktop.
Wireless Firmware Code
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "note.h"
#include "n_atof.c"
#include "n_b64.c"
#include "n_cjson.c"
#include "n_cjson_helpers.c"
#include "n_const.c"
#include "n_ftoa.c"
#include "n_helpers.c"
#include "n_hooks.c"
#include "n_i2c.c"
#include "n_md5.c"
#include "n_printf.c"
#include "n_request.c"
#include "n_serial.c"
#include "n_str.c"
#include "n_ua.c"
#include "n_lib.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define myProductID "REMOVED PRODUCT UID FOR FORUM PURPOSES"
#define OUTBOUND_SYNC_INTERVAL 5
#define HUB_SET_TIMEOUT 5
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
I2C_HandleTypeDef hi2c1;
TIM_HandleTypeDef htim16;
/* USER CODE BEGIN PV */
bool i2c1Initialized = false;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM16_Init(void);
static void MX_I2C1_Init(void);
static void MX_I2C1_DeInit(void);
void delay(uint32_t ms);
long unsigned int millis(void);
int NotecardI2C(void);
int initNotecard(void);
bool noteI2CReset(uint16_t DevAddress);
const char *noteI2CTransmit(uint16_t DevAddress, uint8_t* pBuffer, uint16_t Size);
const char *noteI2CReceive(uint16_t DevAddress, uint8_t* pBuffer, uint16_t Size, uint32_t *avail);
/* USER CODE BEGIN PFP */
int initNotecard(void){
J *req = NoteNewRequest("hub.set");
if (myProductID[0]) {
JAddStringToObject(req, "product", myProductID);
}
JAddStringToObject(req, "mode", "periodic");
// Sync outbound data every OUTBOUND_SYNC_INTERVAL minutes. Alarm notes will
// still be synced immediately.
JAddNumberToObject(req, "outbound", OUTBOUND_SYNC_INTERVAL);
JAddBoolToObject(req, "sync", true);
// The hub.set request may fail if it's sent shortly after power up. We use
// NoteRequestWithRetry to give it a chance to succeed.
NoteRequest(req);
return 0;
}
int NotecardI2C(void){
// Initialize note-c references.
NoteSetFn(malloc, free, delay, millis);
//NoteSetFnDebugOutput(noteLogPrint);
//NoteSetFnMutex(lockNotecard, unlockNotecard, lockNotecard, unlockNotecard);
NoteSetFnI2C(NOTE_I2C_ADDR_DEFAULT, NOTE_I2C_MAX_DEFAULT, noteI2CReset,
noteI2CTransmit, noteI2CReceive);
return 1;
}
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void delay(uint32_t ms) {
HAL_Delay(ms);
}
// Get the number of app milliseconds since boot (this will wrap)
long unsigned int millis() {
return (long unsigned int) HAL_GetTick();
}
// I2C reset procedure, called before any I/O and called again upon I/O error
bool noteI2CReset(uint16_t DevAddress) {
MX_I2C1_DeInit();
MX_I2C1_Init();
return true;
}
// Transmits in master mode an amount of data, in blocking mode. The address
// is the actual address; the caller should have shifted it right so that the
// low bit is NOT the read/write bit. An error message is returned, else NULL if success.
const char *noteI2CTransmit(uint16_t DevAddress, uint8_t* pBuffer, uint16_t Size) {
char *errstr = NULL;
int writelen = sizeof(uint8_t) + Size;
uint8_t *writebuf = malloc(writelen);
if (writebuf == NULL) {
errstr = "i2c: insufficient memory (write)";
} else {
writebuf[0] = Size;
memcpy(&writebuf[1], pBuffer, Size);
HAL_StatusTypeDef err_code = HAL_I2C_Master_Transmit(&hi2c1, DevAddress<<1, writebuf, writelen, 250);
free(writebuf);
if (err_code != HAL_OK) {
errstr = "i2c: HAL_I2C_Master_Transmit error";
}
}
return errstr;
}
// Receives in master mode an amount of data in blocking mode. An error mesage returned, else NULL if success.
const char *noteI2CReceive(uint16_t DevAddress, uint8_t* pBuffer, uint16_t Size, uint32_t *available) {
const char *errstr = NULL;
HAL_StatusTypeDef err_code;
// Retry transmit errors several times, because it's harmless to do so
for (int i=0; i<3; i++) {
uint8_t hdr[2];
hdr[0] = (uint8_t) 0;
hdr[1] = (uint8_t) Size;
HAL_StatusTypeDef err_code = HAL_I2C_Master_Transmit(&hi2c1, DevAddress<<1, hdr, sizeof(hdr), 250);
if (err_code == HAL_OK) {
errstr = NULL;
break;
}
errstr = "i2c: HAL_I2C_Master_Transmit error";
}
// Only receive if we successfully began transmission
if (errstr == NULL) {
int readlen = Size + (sizeof(uint8_t)*2);
uint8_t *readbuf = malloc(readlen);
if (readbuf == NULL) {
errstr = "i2c: insufficient memory (read)";
} else {
err_code = HAL_I2C_Master_Receive(&hi2c1, DevAddress<<1, readbuf, readlen, 10);
if (err_code != HAL_OK) {
errstr = "i2c: HAL_I2C_Master_Receive error";
} else {
uint8_t availbyte = readbuf[0];
uint8_t goodbyte = readbuf[1];
if (goodbyte != Size) {
errstr = "i2c: incorrect amount of data";
} else {
*available = availbyte;
memcpy(pBuffer, &readbuf[2], Size);
}
}
free(readbuf);
}
}
// Done
return errstr;
}
int getNotecardDiagnostic(void){
double temperature = 0;
J *rsp = NoteRequestResponse(NoteNewRequest("card.temp"));
if (rsp != NULL) {
temperature = JGetNumber(rsp, "value");
NoteDeleteResponse(rsp);
}
// Do the same to retrieve the voltage that is detected by the Notecard on its V+ pin.
double voltage = 0;
rsp = NoteRequestResponse(NoteNewRequest("card.voltage"));
if (rsp != NULL) {
voltage = JGetNumber(rsp, "value");
NoteDeleteResponse(rsp);
}
// Enqueue the measurement to the Notecard for transmission to the Notehub, adding the "start"
// flag for demonstration purposes to upload the data instantaneously, so that if you are looking
// at this on notehub.io you will see the data appearing 'live'.)
J *req = NoteNewRequest("note.add");
if (req != NULL) {
JAddStringToObject(req, "file", "sensors.qo");
JAddBoolToObject(req, "start", true);
J *body = JCreateObject();
if (body != NULL) {
JAddNumberToObject(body, "temp", temperature);
JAddNumberToObject(body, "voltage", voltage);
JAddItemToObject(req, "body", body);
}
NoteRequest(req);
}
return 1;
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM16_Init();
MX_I2C1_Init();
NotecardI2C();
initNotecard();
getNotecardDiagnostic();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* 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};
/** Configure the main internal regulator output voltage
*/
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI;
RCC_OscInitStruct.MSIState = RCC_MSI_ON;
RCC_OscInitStruct.MSICalibrationValue = RCC_MSICALIBRATION_DEFAULT;
RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_6;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Configure the SYSCLKSource, HCLK, PCLK1 and PCLK2 clocks dividers
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK3|RCC_CLOCKTYPE_HCLK
|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1
|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.AHBCLK3Divider = RCC_SYSCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief I2C1 Initialization Function
* @param None
* @retval None
*/
static void MX_I2C1_Init(void)
{
/* USER CODE BEGIN I2C1_Init 0 */
if(i2c1Initialized){
return;
}
i2c1Initialized=true;
/* USER CODE END I2C1_Init 0 */
/* USER CODE BEGIN I2C1_Init 1 */
/* USER CODE END I2C1_Init 1 */
hi2c1.Instance = I2C1;
hi2c1.Init.Timing = 0x00000E14;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
/** Configure Analogue filter
*/
if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
{
Error_Handler();
}
/** Configure Digital filter
*/
if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN I2C1_Init 2 */
/* USER CODE END I2C1_Init 2 */
}
// I2C1 De-initialization
void MX_I2C1_DeInit(void) {
// Exit if already done
if (!i2c1Initialized)
return;
i2c1Initialized = false;
// Deconfigure Analogue filter
HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_DISABLE);
// Deinitialize
HAL_I2C_DeInit(&hi2c1);
}
/**
* @brief TIM16 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM16_Init(void)
{
/* USER CODE BEGIN TIM16_Init 0 */
/* USER CODE END TIM16_Init 0 */
/* USER CODE BEGIN TIM16_Init 1 */
/* USER CODE END TIM16_Init 1 */
htim16.Instance = TIM16;
htim16.Init.Prescaler = 8000-1;
htim16.Init.CounterMode = TIM_COUNTERMODE_UP;
htim16.Init.Period = 10000-1;
htim16.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim16.Init.RepetitionCounter = 0;
htim16.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim16) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM16_Init 2 */
/* USER CODE END TIM16_Init 2 */
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOB_CLK_ENABLE();
/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @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 */
__disable_irq();
while (1)
{
}
/* 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,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment