Samyakkumar Jain
Created November 30, 2019 © GPL3+

Untitled

IntermediateWork in progress15 hours71
Untitled

Schematics

Schematic

File missing, please reupload.

Code

epoll_library__h.c

C/C++
#pragma once
#include <time.h>
#include <sys/epoll.h>
#include <unistd.h>

/// Forward declaration of the data type passed to the handlers.
struct EventData;

/// <summary>
///     Function signature for event handlers.
/// </summary>
/// <param name="eventData">The provided event data</param>
typedef void (*EventHandler)(struct EventData* eventData);

/// <summary>
/// <para>Contains context data for epoll events.</para>
/// <para>When an event is registered with RegisterEventHandlerToEpoll, supply
/// a pointer to an instance of this struct.  The pointer must remain valid
/// for as long as the event is active.</para>
/// </summary>
/// <seealso cref="RegisterEventHandlerToEpoll" ></seealso>
typedef struct EventData {
	/// <summary>
	/// Function which is called when the event occurs.
	/// </summary>
	EventHandler eventHandler;
	/// <summary>
	/// The file descriptor that generated the event.
	/// </summary>
	int fd;
} EventData;

/// <summary>
///    Creates an epoll instance.
/// </summary>
/// <returns>A valid epoll file descriptor on success, or -1 on failure</returns>
int CreateEpollFd(void);

/// <summary>
///     Registers an event with the epoll instance. If the event was previously added, that
///     registration will be modified to match the new mask.
/// </summary>
/// <param name="epollFd">Epoll file descriptor</param>
/// <param name="eventFd">File descriptor generating events for the epoll</param>
/// <param name="persistentEventData">Persistent event data structure. This must stay in memory
/// until the handler is removed from the epoll.</param>
/// <param name="epollEventMask">Bit mask for the epoll event type</param>
/// <returns>0 on success, or -1 on failure</returns>
int RegisterEventHandlerToEpoll(int epollFd, int eventFd, EventData* persistentEventData,
	const uint32_t epollEventMask);

/// <summary>
///     Unregisters an event with the epoll instance.
/// </summary>
/// <param name="epollFd">Epoll file descriptor</param>
/// <param name="eventFd">File descriptor generating events for the epoll</param>
/// <returns>0 on success, or -1 on failure</returns>
int UnregisterEventHandlerFromEpoll(int epollFd, int eventFd);

/// <summary>
///     Sets the period of a timer.
/// </summary>
/// <param name="timerFd">Timer file descriptor</param>
/// <param name="period">The new period</param>
/// <returns>0 on success, or -1 on failure</returns>
int SetTimerFdToPeriod(int timerFd, const struct timespec* period);

/// <summary>
///     Sets a timer to fire once only, after a duration specified in milliseconds.
/// </summary>
/// <param name="timerFd">Timer file descriptor</param>
/// <param name="expiry">The time elapsed before it expires once</param>
/// <returns>0 on success, or -1 on failure</returns>
int SetTimerFdToSingleExpiry(int timerFd, const struct timespec* expiry);

/// <summary>
///     Consumes an event by reading from the timer file descriptor.
///     If the event is not consumed, then it will immediately recur.
/// </summary>
/// <param name="timerFd">Timer file descriptor</param>
/// <returns>0 on success, or -1 on failure</returns>
int ConsumeTimerFdEvent(int timerFd);

/// <summary>
///     Creates a timerfd and adds it to an epoll instance.
/// </summary>
/// <param name="epollFd">Epoll file descriptor</param>
/// <param name="period">The timer period</param>
/// <param name="persistentEventData">Persistent event data structure. This must stay in memory
/// until the handler is removed from the epoll.</param>
/// <param name="epollEventMask">Bit mask for the epoll event type</param>
/// <returns>A valid timerfd file descriptor on success, or -1 on failure</returns>
int CreateTimerFdAndAddToEpoll(int epollFd, const struct timespec* period,
	EventData* persistentEventData, const uint32_t epollEventMask);

/// <summary>
///     Waits for an event on an epoll instance and triggers the handler.
/// </summary>
/// <param name="epollFd">
///     Epoll file descriptor which was created with <see cref="CreateEpollFd" ></see>.
/// </param>
/// <returns>0 on success, or -1 on failure</returns>
int WaitForEventAndCallHandler(int epollFd);

/// <summary>
///     Closes a file descriptor and prints an error on failure.
/// </summary>
/// <param name="fd">File descriptor to close</param>
/// <param name="name">File descriptor name to use in error message</param>
void CloseFdAndPrintError(int fd, const char* name);

main_c.c

C/C++
#include <signal.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdio.h>
#include <stdarg.h>
#include <errno.h>

#define I2C_STRUCTS_VERSION 1

#include <applibs/log.h>
#include <applibs/gpio.h>
#include <applibs/i2c.h>
#include <applibs/networking.h>
#include <applibs/storage.h>

#include "epoll_timerfd_utilities.h"

#include "BME680_reg.h"

#include <azureiot/iothub_device_client_ll.h>
#include <azureiot/iothub_client_core_common.h>
#include <azureiot/iothub_client_options.h>
#include <azureiot/iothub.h>
#include <azureiot/iothubtransportmqtt.h>
#include <azureiot/azure_sphere_provisioning.h>
#include "epoll_timerfd_utilities.h"

#define SCOPEID_LENGTH 20
static char scopeId[SCOPEID_LENGTH]; // ScopeId for the Azure IoT Central application, set in
									 // app_manifest.json, CmdArgs

static volatile sig_atomic_t terminationRequired = false;

static I2C_DeviceAddress bme680_addr = 0x77;

static IOTHUB_DEVICE_CLIENT_LL_HANDLE iothubClientHandle = NULL;
static const int keepalivePeriodSeconds = 20;
static bool iothubAuthenticated = false;
static void SendMessageCallback(IOTHUB_CLIENT_CONFIRMATION_RESULT result, void* context);
static void TwinCallback(DEVICE_TWIN_UPDATE_STATE updateState, const unsigned char* payload,
	size_t payloadSize, void* userContextCallback);
static void TwinReportBoolState(const char* propertyName, bool propertyValue);
static void ReportStatusCallback(int result, void* context);
static void readWaterDetectHandler(EventData* eventData);
static const char* GetReasonString(IOTHUB_CLIENT_CONNECTION_STATUS_REASON reason);
static const char* getAzureSphereProvisioningResultString(
	AZURE_SPHERE_PROV_RETURN_VALUE provisioningResult);
static void SendTelemetry(const unsigned char* key, const unsigned char* key1, const unsigned char* value1,
	const unsigned char* key2, const unsigned char* value2,
	const unsigned char* key3, const unsigned char* value3,
	const unsigned char* key4, const unsigned char* value4,
	const unsigned char* key5, const unsigned char* value5);
static void SetupAzureClient(void);

static uint8_t calculate_heat(void);
static double get_temperature(void);
static double get_humidity(void);
static double get_pressure(void);
static double get_gas(void);

static void init_device(void);

static void SendData(void);

static int InitPeripheralsAndHandlers(void);
static void ClosePeripheralsAndHandlers(void);

static int azureTimerFd = -1;
static int epollFd = -1;
static int i2cFd = -1;
static int waterDetectGpioFd = -1;
static int waterDetectTimerFd = -1;

static GPIO_Value_Type waterDetectState = GPIO_Value_Low;

static const int AzureIoTDefaultPollPeriodSeconds = 10;
static const int AzureIoTMinReconnectPeriodSeconds = 60;
static const int AzureIoTMaxReconnectPeriodSeconds = 10 * 60;
static const int waterDetectPollPeriod = 5000000000;

static int azureIoTPollPeriodSeconds = -1;

static void AzureTimerEventHandler(EventData* eventData);

static void TerminationHandler(int signalNumber)
{
	// Don't use Log_Debug here, as it is not guaranteed to be async-signal-safe.
	terminationRequired = true;
}

int main(int argc, char* argv[])
{
	Log_Debug("IoT Hub/Central Application starting.\n");

	if (argc == 2) {
		Log_Debug("Setting Azure Scope ID %s\n", argv[1]);
		strncpy(scopeId, argv[1], SCOPEID_LENGTH);
	}
	else {
		Log_Debug("ScopeId needs to be set in the app_manifest CmdArgs\n");
		return -1;
	}

	if (InitPeripheralsAndHandlers() != 0) {
		terminationRequired = true;
	}

	// Main loop
	while (!terminationRequired) {
		if (WaitForEventAndCallHandler(epollFd) != 0) {
			terminationRequired = true;
		}
	}

	ClosePeripheralsAndHandlers();

	Log_Debug("Application exiting.\n");

	return 0;
}

/// <summary>
/// Azure timer event:  Check connection status and send telemetry
/// </summary>
static void AzureTimerEventHandler(EventData* eventData)
{
	if (ConsumeTimerFdEvent(azureTimerFd) != 0) {
		terminationRequired = true;
		return;
	}

	bool isNetworkReady = false;
	if (Networking_IsNetworkingReady(&isNetworkReady) != -1) {
		if (isNetworkReady && !iothubAuthenticated) {
			SetupAzureClient();
		}
	}
	else {
		Log_Debug("Failed to get Network state\n");
	}

	if (iothubAuthenticated) {
		SendData();
		IoTHubDeviceClient_LL_DoWork(iothubClientHandle);
	}
}

static EventData azureEventData = { .eventHandler = &AzureTimerEventHandler };
static EventData waterDetectEventData = { .eventHandler = &readWaterDetectHandler };

static int InitPeripheralsAndHandlers(void)
{
	struct sigaction action;
	memset(&action, 0, sizeof(struct sigaction));
	action.sa_handler = TerminationHandler;
	sigaction(SIGTERM, &action, NULL);

	epollFd = CreateEpollFd();
	if (epollFd < 0) {
		return -1;
	}

	Log_Debug("Opening ISU2 I2C\n");
	i2cFd = I2CMaster_Open(2);
	I2CMaster_SetBusSpeed(i2cFd, I2C_BUS_SPEED_STANDARD);
	I2CMaster_SetTimeout(i2cFd, 100);
	I2CMaster_SetDefaultTargetAddress(i2cFd, bme680_addr);

	init_device();

	azureIoTPollPeriodSeconds = AzureIoTDefaultPollPeriodSeconds;
	struct timespec azureTelemetryPeriod = { azureIoTPollPeriodSeconds, 0 };
	azureTimerFd =
		CreateTimerFdAndAddToEpoll(epollFd, &azureTelemetryPeriod, &azureEventData, EPOLLIN);

	Log_Debug("Opening GPIO2 as input.\n");
	waterDetectGpioFd = GPIO_OpenAsInput(2);
	if (waterDetectGpioFd < 0) {
		Log_Debug("ERROR: Could not open button GPIO: %s (%d).\n", strerror(errno), errno);
		return -1;
	}

	struct timespec waterDetectCheckPeriod = { 0, waterDetectPollPeriod };
	waterDetectTimerFd = CreateTimerFdAndAddToEpoll(epollFd, &waterDetectCheckPeriod, &waterDetectEventData, EPOLLIN);
	if (waterDetectTimerFd < 0) return -1;

	return 0;
}

static void readWaterDetectHandler(EventData *eventData)
{
	GPIO_Value_Type newState;
	int result = GPIO_GetValue(waterDetectGpioFd, &newState);
	if (result != 0) {
		Log_Debug("ERROR: Could not read button GPIO: %s (%d).\n", strerror(errno), errno);
		//terminationRequired = true;
		return;
	}
	waterDetectState = newState;
}

static void init_device(void) {
	I2CMaster_Write(i2cFd, bme680_addr, ctrl_hum_data, sizeof(ctrl_hum_data));
	I2CMaster_Write(i2cFd, bme680_addr, ctrl_meas_data, sizeof(ctrl_meas_data));
	I2CMaster_Write(i2cFd, bme680_addr, ctrl_gas_1_data, sizeof(ctrl_gas_1_data));
	I2CMaster_Write(i2cFd, bme680_addr, gas_wait_0_data, sizeof(gas_wait_0_data));
	res_heat_0_data[1] = calculate_heat();
	I2CMaster_Write(i2cFd, bme680_addr, res_heat_0_data, sizeof(res_heat_0_data));
	I2CMaster_Write(i2cFd, bme680_addr, config_data, sizeof(config_data));
}

static uint8_t calculate_heat(void) 
{
	int par_g1, par_g2, par_g2_temp, par_g3, res_heat_range, res_heat_val;
	uint8_t current_reg = 0xED;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_g1, 1);
	current_reg = 0xEB;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_g2_temp, 1);
	current_reg++;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_g2, 1);
	current_reg = 0xEE;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_g3, 1);
	current_reg = 0x02;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &res_heat_range, 1);
	current_reg = 0x00;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &res_heat_val, 1);

	par_g2 = (par_g2 << 8) + par_g2_temp;
	res_heat_range &= 0b00110000;

	double var1 = ((double)par_g1 / 16.0) + 49.0;
	double var2 = (((double)par_g2 / 32768.0) * 0.0005) + 0.00235;
	double var3 = (double)par_g3 / 1024.0;
	double var4 = var1 * (1.0 + (var2 * (double)300.0));
	double var5 = var4 + (var3 * (double)23.0);
	return (uint8_t)(3.4 * ((var5 * (4.0 / (4.0 + (double)res_heat_range)) *
		(1.0 / (1.0 + ((double)res_heat_val * 0.002)))) - 25));
}

static void ClosePeripheralsAndHandlers(void)
{
	Log_Debug("Closing file descriptors\n");

	CloseFdAndPrintError(i2cFd, "I2C");
	CloseFdAndPrintError(azureTimerFd, "AzureTimer");
	CloseFdAndPrintError(epollFd, "Epoll");
	CloseFdAndPrintError(waterDetectGpioFd, "WaterDetectGpio");
	CloseFdAndPrintError(waterDetectTimerFd, "WaterDetectTimer");
}

static void HubConnectionStatusCallback(IOTHUB_CLIENT_CONNECTION_STATUS result,
	IOTHUB_CLIENT_CONNECTION_STATUS_REASON reason,
	void* userContextCallback)
{
	iothubAuthenticated = (result == IOTHUB_CLIENT_CONNECTION_AUTHENTICATED);
	Log_Debug("IoT Hub Authenticated: %s\n", GetReasonString(reason));
}

static void SetupAzureClient(void)
{
	if (iothubClientHandle != NULL)
		IoTHubDeviceClient_LL_Destroy(iothubClientHandle);

	AZURE_SPHERE_PROV_RETURN_VALUE provResult =
		IoTHubDeviceClient_LL_CreateWithAzureSphereDeviceAuthProvisioning(scopeId, 10000,
			&iothubClientHandle);
	Log_Debug("IoTHubDeviceClient_LL_CreateWithAzureSphereDeviceAuthProvisioning returned '%s'.\n",
		getAzureSphereProvisioningResultString(provResult));

	if (provResult.result != AZURE_SPHERE_PROV_RESULT_OK) {

		// If we fail to connect, reduce the polling frequency, starting at
		// AzureIoTMinReconnectPeriodSeconds and with a backoff up to
		// AzureIoTMaxReconnectPeriodSeconds
		if (azureIoTPollPeriodSeconds == AzureIoTDefaultPollPeriodSeconds) {
			azureIoTPollPeriodSeconds = AzureIoTMinReconnectPeriodSeconds;
		}
		else {
			azureIoTPollPeriodSeconds *= 2;
			if (azureIoTPollPeriodSeconds > AzureIoTMaxReconnectPeriodSeconds) {
				azureIoTPollPeriodSeconds = AzureIoTMaxReconnectPeriodSeconds;
			}
		}

		struct timespec azureTelemetryPeriod = { azureIoTPollPeriodSeconds, 0 };
		SetTimerFdToPeriod(azureTimerFd, &azureTelemetryPeriod);

		Log_Debug("ERROR: failure to create IoTHub Handle - will retry in %i seconds.\n",
			azureIoTPollPeriodSeconds);
		return;
	}

	// Successfully connected, so make sure the polling frequency is back to the default
	azureIoTPollPeriodSeconds = AzureIoTDefaultPollPeriodSeconds;
	struct timespec azureTelemetryPeriod = { azureIoTPollPeriodSeconds, 0 };
	SetTimerFdToPeriod(azureTimerFd, &azureTelemetryPeriod);

	iothubAuthenticated = true;

	if (IoTHubDeviceClient_LL_SetOption(iothubClientHandle, OPTION_KEEP_ALIVE,
		&keepalivePeriodSeconds) != IOTHUB_CLIENT_OK) {
		Log_Debug("ERROR: failure setting option \"%s\"\n", OPTION_KEEP_ALIVE);
		return;
	}

	//IoTHubDeviceClient_LL_SetDeviceTwinCallback(iothubClientHandle, TwinCallback, NULL);
	IoTHubDeviceClient_LL_SetConnectionStatusCallback(iothubClientHandle,
		HubConnectionStatusCallback, NULL);
}

static const char* GetReasonString(IOTHUB_CLIENT_CONNECTION_STATUS_REASON reason)
{
	static char* reasonString = "unknown reason";
	switch (reason) {
	case IOTHUB_CLIENT_CONNECTION_EXPIRED_SAS_TOKEN:
		reasonString = "IOTHUB_CLIENT_CONNECTION_EXPIRED_SAS_TOKEN";
		break;
	case IOTHUB_CLIENT_CONNECTION_DEVICE_DISABLED:
		reasonString = "IOTHUB_CLIENT_CONNECTION_DEVICE_DISABLED";
		break;
	case IOTHUB_CLIENT_CONNECTION_BAD_CREDENTIAL:
		reasonString = "IOTHUB_CLIENT_CONNECTION_BAD_CREDENTIAL";
		break;
	case IOTHUB_CLIENT_CONNECTION_RETRY_EXPIRED:
		reasonString = "IOTHUB_CLIENT_CONNECTION_RETRY_EXPIRED";
		break;
	case IOTHUB_CLIENT_CONNECTION_NO_NETWORK:
		reasonString = "IOTHUB_CLIENT_CONNECTION_NO_NETWORK";
		break;
	case IOTHUB_CLIENT_CONNECTION_COMMUNICATION_ERROR:
		reasonString = "IOTHUB_CLIENT_CONNECTION_COMMUNICATION_ERROR";
		break;
	case IOTHUB_CLIENT_CONNECTION_OK:
		reasonString = "IOTHUB_CLIENT_CONNECTION_OK";
		break;
	}
	return reasonString;
}

static const char* getAzureSphereProvisioningResultString(
	AZURE_SPHERE_PROV_RETURN_VALUE provisioningResult)
{
	switch (provisioningResult.result) {
	case AZURE_SPHERE_PROV_RESULT_OK:
		return "AZURE_SPHERE_PROV_RESULT_OK";
	case AZURE_SPHERE_PROV_RESULT_INVALID_PARAM:
		return "AZURE_SPHERE_PROV_RESULT_INVALID_PARAM";
	case AZURE_SPHERE_PROV_RESULT_NETWORK_NOT_READY:
		return "AZURE_SPHERE_PROV_RESULT_NETWORK_NOT_READY";
	case AZURE_SPHERE_PROV_RESULT_DEVICEAUTH_NOT_READY:
		return "AZURE_SPHERE_PROV_RESULT_DEVICEAUTH_NOT_READY";
	case AZURE_SPHERE_PROV_RESULT_PROV_DEVICE_ERROR:
		return "AZURE_SPHERE_PROV_RESULT_PROV_DEVICE_ERROR";
	case AZURE_SPHERE_PROV_RESULT_GENERIC_ERROR:
		return "AZURE_SPHERE_PROV_RESULT_GENERIC_ERROR";
	default:
		return "UNKNOWN_RETURN_VALUE";
	}
}

static void SendTelemetry(const unsigned char* key, const unsigned char* key1, const unsigned char* value1,
	const unsigned char* key2, const unsigned char* value2, 
	const unsigned char* key3, const unsigned char* value3,
	const unsigned char* key4, const unsigned char* value4,
	const unsigned char* key5, const unsigned char* value5)
{
	static char eventBuffer[300] = { 0 };
	static const char* EventMsgTemplate = "{ \"%s\": { \
		\"%s\" : \"%s\", \
		\"%s\" : \"%s\", \
		\"%s\" : \"%s\", \
		\"%s\" : \"%s\", \
		\"%s\" : \"%s\"}}";
	int len = snprintf(eventBuffer, sizeof(eventBuffer), EventMsgTemplate, key, 
		key1, value1, key2, value2, key3, value3, key4, value4, key5, value5);
	if (len < 0)
		return;

	Log_Debug("Sending IoT Hub Message: %s\n", eventBuffer);

	IOTHUB_MESSAGE_HANDLE messageHandle = IoTHubMessage_CreateFromString(eventBuffer);

	if (messageHandle == 0) {
		Log_Debug("WARNING: unable to create a new IoTHubMessage\n");
		return;
	}

	if (IoTHubDeviceClient_LL_SendEventAsync(iothubClientHandle, messageHandle, SendMessageCallback,
		/*&callback_param*/ 0) != IOTHUB_CLIENT_OK) {
		Log_Debug("WARNING: failed to hand over the message to IoTHubClient\n");
	}
	else {
		Log_Debug("INFO: IoTHubClient accepted the message for delivery\n");
	}

	IoTHubMessage_Destroy(messageHandle);
}

static void SendMessageCallback(IOTHUB_CLIENT_CONFIRMATION_RESULT result, void* context)
{
	Log_Debug("INFO: Message received by IoT Hub. Result is: %d\n", result);
}

void SendData(void)
{
	double temperature, humidity, pressure, gas_res;

	temperature = get_temperature();
	humidity = get_humidity();
	pressure = get_pressure();
	gas_res = get_gas();

	char tempBuffer[20];
	int len = snprintf(tempBuffer, 20, "%3.2f", temperature);
	char humBuffer[20];
	len = snprintf(humBuffer, 20, "%3.1f", humidity);
	char pressBuffer[20];
	len = snprintf(pressBuffer, 20, "%6.1f", pressure);
	char gasBuffer[20];
	len = snprintf(gasBuffer, 20, "%3.2f", gas_res);

	bool water_present = false;

	if (waterDetectState == GPIO_Value_High) water_present = true;

	char waterPresentBuffer[20];
	len = snprintf(waterPresentBuffer, 20, "%s", water_present ? "true" : "false");

	if (len > 0)
		SendTelemetry("Env_data", "temperature", tempBuffer, "humidity", humBuffer, "pressure",
			pressBuffer, "gas", gasBuffer, "water_present", waterPresentBuffer);

	I2CMaster_Write(i2cFd, bme680_addr, reset_data, sizeof(reset_data));
	init_device();
}

static double get_gas(void)
{
	static const const_array1[] = {1, 1, 1, 1, 1, 0.99, 1, 0.992, 1, 1, 0.998, 0.995, 1, 0.99, 1, 1};
	static const const_array2[] = { 8000000, 4000000, 2000000, 1000000, 499500.4995, 248262.1648,
	125000, 63004.03226, 31281.28128, 15625, 7812.5, 3906.25, 1953.125, 976.5625, 488.28125, 244.140625};

	uint8_t gas_adc_lsb, gas_adc_msb, gas_range, range_switching_error;
	uint16_t raw_gas_adc;
	double gas_res;
	uint8_t current_reg = 0x2B;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &gas_adc_lsb, 1);
	current_reg = 0x2A;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &gas_adc_msb, 1);
	current_reg = 0x2B;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &gas_range, 1);
	current_reg = 0x04;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &range_switching_error, 1);

	raw_gas_adc = (gas_adc_msb << 2) + (gas_adc_lsb >> 6);
	gas_range = gas_range & 0b1111;

	double var1 = (1340.0 + 5.0 * range_switching_error) * const_array1[gas_range];
	gas_res = var1 * const_array2[gas_range] / (raw_gas_adc - 512.0 + var1);
	return gas_res;

}

static double get_pressure(void)
{
	uint32_t raw_press_adc;
	uint8_t par_p1_lsb, par_p1_msb, par_p2_lsb, par_p2_msb, par_p3, par_p4_lsb, par_p4_msb,
		par_p5_lsb, par_p5_msb, par_p6, par_p7, par_p8_lsb, par_p8_msb, par_p9_lsb, par_p9_msb,
		par_p10, press_adc_xlsb, press_adc_lsb, press_adc_msb;
	uint16_t par_p1, par_p2, par_p4, par_p5, par_p8, par_p9;
	uint32_t press_comp;
	uint8_t current_reg = 0x8E;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_p1_lsb, 1);
	current_reg++;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_p1_msb, 1);
	current_reg++;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_p2_lsb, 1);
	current_reg++;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_p2_msb, 1);
	current_reg++;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_p3, 1);
	current_reg = 0x94;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_p4_lsb, 1);
	current_reg++;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_p4_msb, 1);
	current_reg++;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_p5_lsb, 1);
	current_reg++;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_p5_msb, 1);
	current_reg = 0x99;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_p6, 1);
	current_reg--;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_p7, 1);
	current_reg = 0x9C;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_p8_lsb, 1);
	current_reg = 0x9D;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_p8_msb, 1);
	current_reg = 0x9E;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_p9_lsb, 1);
	current_reg = 0x9F;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_p9_msb, 1);
	current_reg = 0xA0;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_p10, 1);
	current_reg = 0x21;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &press_adc_xlsb, 1);
	current_reg--;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &press_adc_lsb, 1);
	current_reg--;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &press_adc_msb, 1);
	par_p1 = (par_p1_msb << 8) + par_p1_lsb;
	par_p2 = (par_p2_msb << 8) + par_p2_lsb;
	par_p4 = (par_p4_msb << 8) + par_p4_lsb;
	par_p5 = (par_p5_msb << 8) + par_p5_lsb;
	par_p8 = (par_p8_msb << 8) + par_p8_lsb;
	par_p9 = (par_p9_msb << 8) + par_p9_lsb;
	raw_press_adc = (press_adc_msb << 12) + (press_adc_lsb << 4) + (press_adc_xlsb >> 4);

	double t_fine = get_temperature() * 5120.0;

	int32_t var1 = ((int32_t)t_fine >> 1) - 64000;
	int32_t var2 = ((((var1 >> 2) * (var1 >> 2)) >> 11) * (int32_t)par_p6) >> 2;
	var2 = var2 + ((var1 * (int32_t)par_p5) << 1);
	var2 = (var2 >> 2) + ((int32_t)par_p4 << 16);
	var1 = (((((var1 >> 2) * (var1 >> 2)) >> 13) * ((int32_t)par_p3 << 5)) >> 3) +
		(((int32_t)par_p2 * var1) >> 1);
	var1 = var1 >> 18;
	var1 = ((32768 + var1) * (int32_t)par_p1) >> 15;
	press_comp = 1048576 - raw_press_adc;
	press_comp = (uint32_t)((press_comp - (var2 >> 12)) * ((uint32_t)3125));
	if (press_comp >= (1 << 30)) press_comp = ((press_comp / (uint32_t)var1) << 1);
	else press_comp = ((press_comp << 1) / (uint32_t)var1);
	var1 = ((int32_t)par_p9 * (int32_t)(((press_comp >> 3) *
		(press_comp >> 3)) >> 13)) >> 12;
	var2 = ((int32_t)(press_comp >> 2) * (int32_t)par_p8) >> 13;
	int32_t var3 = ((int32_t)(press_comp >> 8) * (int32_t)(press_comp >> 8) *
		(int32_t)(press_comp >> 8) * (int32_t)par_p10) >> 17;
	press_comp = (int32_t)(press_comp)+((var1 + var2 + var3 + ((int32_t)par_p7 << 7)) >> 4);
	Log_Debug("Pressure integer val is %i\n", press_comp);
	return (double)press_comp;


}

static double get_humidity(void)
{
	uint32_t raw_hum_adc;
	uint8_t par_h1_lsb, par_h1_msb, par_h2_lsb, par_h2_msb, par_h3, par_h4, par_h5, par_h6, par_h7,
		hum_adc_lsb, hum_adc_msb;
	uint16_t par_h1, par_h2;
	const double temp_comp = get_temperature();
	uint8_t current_reg = 0xE2;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_h1_lsb, 1);
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_h2_lsb, 1);
	current_reg = 0xE3;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_h1_msb, 1);
	current_reg = 0xE1;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_h2_msb, 1);
	current_reg = 0xE4;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_h3, 1);
	current_reg++;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_h4, 1);
	current_reg++;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_h5, 1);
	current_reg++;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_h6, 1);
	current_reg++; //0xE8
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_h7, 1);
	current_reg = 0x26;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &hum_adc_lsb, 1);
	current_reg = 0x25;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &hum_adc_msb, 1);
	raw_hum_adc = (hum_adc_msb << 8) + hum_adc_lsb;
	par_h1 = (par_h1_msb << 4) + (par_h1_lsb >> 4);
	par_h2 = (par_h2_msb << 4) + (par_h2_lsb >> 4);

	double var1 = raw_hum_adc - (((double)par_h1 * 16.0) + (((double)par_h3 / 2.0) * temp_comp));
	double var2 = var1 * (((double)par_h2 / 262144.0) * (1.0 + (((double)par_h4 / 16384.0) *
		temp_comp) + (((double)par_h5 / 1048576.0) * temp_comp * temp_comp)));
	double var3 = (double)par_h6 / 16384.0;
	double var4 = (double)par_h7 / 2097152.0;

	return var2 + ((var3 + (var4 * temp_comp)) * var2 * var2);

}

static double get_temperature(void)
{
	uint32_t raw_temp_adc;
	uint8_t par_t1_lsb, par_t1_msb, par_t2_lsb, par_t2_msb, par_t3, temp_adc_xlsb,
		temp_adc_lsb, temp_adc_msb;
	uint16_t par_t1, par_t2;
	uint8_t current_reg = 0xE9;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_t1_lsb, 1);
	current_reg = 0xEA;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_t1_msb, 1);
	current_reg = 0x8A;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_t2_lsb, 1);
	current_reg = 0x8B;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_t2_msb, 1);
	current_reg = 0x8C;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &par_t3, 1);
	current_reg = 0x24;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &temp_adc_xlsb, 1);
	current_reg = 0x23;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &temp_adc_lsb, 1);
	current_reg = 0x22;
	I2CMaster_WriteThenRead(i2cFd, bme680_addr, &current_reg, 1, &temp_adc_msb, 1);

	temp_adc_xlsb >>= 4;
	raw_temp_adc = (temp_adc_msb << 12) + (temp_adc_lsb << 4) + temp_adc_xlsb;

	par_t1 = (par_t1_msb << 8) + par_t1_lsb;
	par_t2 = (par_t2_msb << 8) + par_t2_lsb;

	double var1 = (((double)raw_temp_adc / 16384.0) - ((double)par_t1 / 1024.0)) * (double)par_t2;
	double var2 = ((((double)raw_temp_adc / 131072.0) - ((double)par_t1 / 8192.0)) *
		(((double)raw_temp_adc / 131072.0) - ((double)par_t1 / 8192.0))) *
		((double)par_t3 * 16.0);
	double t_fine = var1 + var2;
	double temp_comp = t_fine / 5120.0;
	return temp_comp;
}

bme680_header.c

C/C++
#pragma once
#define Ctrl_meas 0x74
#define Ctrl_hum 0x72
#define Ctrl_gas_1 0x71
#define Ctrl_gas_0 0x70
#define Config 0x75
#define Gas_wait_(x) (0x64 + x)
#define Idac_heat_(x) (0x50 + x)
#define Res_heat_(x) (0x5A + x)

#define Gas_r_lsb 0x2B
#define Gas_r_msb 0x2A

#define Hum_lsb 0x26
#define Hum_msb 0x25

#define Temp_xlsb 0x24
#define Temp_lsb 0x23
#define Temp_msb 0x22

#define Press_xlsb 0x21
#define Press_lsb 0x20
#define Press_msb 0x1F

#define BME680_ID 0x61
#define Id 0xD0
#define Reset 0xE0

#define BME680_ADDR 0x77

const uint8_t ctrl_hum_data[] = { Ctrl_hum, 0x01 };
const uint8_t ctrl_meas_data[] = { Ctrl_meas, 0b01010101 };
const uint8_t ctrl_gas_1_data[] = { Ctrl_gas_1, 0b0001000 };
const uint8_t gas_wait_0_data[] = { Gas_wait_(0), 0x59 };
uint8_t res_heat_0_data[] = { Res_heat_(0), 0x00 };
const uint8_t config_data[] = { Config, 0b00001000 };
const uint8_t reset_data[] = { Reset, 0xB6 };

epoll_library__c.c

C/C++
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/timerfd.h>
#include <applibs/log.h>
#include "epoll_timerfd_utilities.h"

int CreateEpollFd(void)
{
	int epollFd = -1;

	epollFd = epoll_create1(0);
	if (epollFd == -1) {
		Log_Debug("ERROR: Could not create epoll instance: %s (%d).\n", strerror(errno), errno);
		return -1;
	}

	return epollFd;
}

int RegisterEventHandlerToEpoll(int epollFd, int eventFd, EventData* persistentEventData,
	const uint32_t epollEventMask)
{
	persistentEventData->fd = eventFd;
	struct epoll_event eventToAddOrModify = { .data.ptr = persistentEventData,
											 .events = epollEventMask };

	// Register the eventFd on the epoll instance referred by epollFd
	// and register the eventHandler handler for events in epollEventMask.
	if (epoll_ctl(epollFd, EPOLL_CTL_ADD, eventFd, &eventToAddOrModify) == -1) {
		// If the Add fails, retry with the Modify as the file descriptor has already been
		// added to the epoll set after it was removed by the kernel upon its closure.
		if (epoll_ctl(epollFd, EPOLL_CTL_MOD, eventFd, &eventToAddOrModify) == -1) {
			Log_Debug("ERROR: Could not register event to epoll instance: %s (%d).\n",
				strerror(errno), errno);
			return -1;
		}
	}

	return 0;
}

int UnregisterEventHandlerFromEpoll(int epollFd, int eventFd)
{
	int res = 0;
	// Unregister the eventFd on the epoll instance referred by epollFd.
	if ((res = epoll_ctl(epollFd, EPOLL_CTL_DEL, eventFd, NULL)) == -1) {
		if (res == -1 && errno != EBADF) { // Ignore EBADF errors
			Log_Debug("ERROR: Could not remove event from epoll instance: %s (%d).\n",
				strerror(errno), errno);
			return -1;
		}
	}

	return 0;
}

int SetTimerFdToPeriod(int timerFd, const struct timespec* period)
{
	struct itimerspec newValue = { .it_value = *period,.it_interval = *period };

	if (timerfd_settime(timerFd, 0, &newValue, NULL) < 0) {
		Log_Debug("ERROR: Could not set timerfd period: %s (%d).\n", strerror(errno), errno);
		return -1;
	}

	return 0;
}

int SetTimerFdToSingleExpiry(int timerFd, const struct timespec* expiry)
{
	struct itimerspec newValue = { .it_value = *expiry,.it_interval = {} };

	if (timerfd_settime(timerFd, 0, &newValue, NULL) < 0) {
		Log_Debug("ERROR: Could not set timerfd interval: %s (%d).\n", strerror(errno), errno);
		return -1;
	}

	return 0;
}

int ConsumeTimerFdEvent(int timerFd)
{
	uint64_t timerData = 0;

	if (read(timerFd, &timerData, sizeof(timerData)) == -1) {
		Log_Debug("ERROR: Could not read timerfd %s (%d).\n", strerror(errno), errno);
		return -1;
	}

	return 0;
}

int CreateTimerFdAndAddToEpoll(int epollFd, const struct timespec* period,
	EventData* persistentEventData, const uint32_t epollEventMask)
{
	// Create the timerfd and arm it by setting the interval to period
	int timerFd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
	if (timerFd < 0) {
		Log_Debug("ERROR: Could not create timerfd: %s (%d).\n", strerror(errno), errno);
		return -1;
	}
	if (SetTimerFdToPeriod(timerFd, period) != 0) {
		int result = close(timerFd);
		if (result != 0) {
			Log_Debug("ERROR: Could not close timerfd: %s (%d).\n", strerror(errno), errno);
		}
		return -1;
	}

	persistentEventData->fd = timerFd;
	if (RegisterEventHandlerToEpoll(epollFd, timerFd, persistentEventData, epollEventMask) != 0) {
		return -1;
	}

	return timerFd;
}

int WaitForEventAndCallHandler(int epollFd)
{
	struct epoll_event event;
	int numEventsOccurred = epoll_wait(epollFd, &event, 1, -1);

	if (numEventsOccurred == -1) {
		if (errno == EINTR) {
			// interrupted by signal, e.g. due to breakpoint being set; ignore
			return 0;
		}
		Log_Debug("ERROR: Failed waiting on events: %s (%d).\n", strerror(errno), errno);
		return -1;
	}

	if (numEventsOccurred == 1 && event.data.ptr != NULL) {
		EventData* eventData = event.data.ptr;
		eventData->eventHandler(eventData);
	}

	return 0;
}

void CloseFdAndPrintError(int fd, const char* fdName)
{
	if (fd >= 0) {
		int result = close(fd);
		if (result != 0) {
			Log_Debug("ERROR: Could not close fd %s: %s (%d).\n", fdName, strerror(errno), errno);
		}
	}
}

Credits

Samyakkumar Jain

Samyakkumar Jain

2 projects • 4 followers
I am Samyak, a final year student of master's with a Specialization in Embedded Systems from Nirma University, India.

Comments