Hackster is hosting Hackster Holidays, Ep. 6: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Monday!Stream Hackster Holidays, Ep. 6 on Monday!
ujjval rathod
Published

Overhead tank water level monitoring using Blues Notecard

Overhead tank water level monitoring plus weather data display on cloud dashboard on Thinger. io

IntermediateFull instructions provided20 hours310
Overhead tank water level monitoring using Blues Notecard

Things used in this project

Hardware components

Blues Notecarrier A
Blues Notecarrier A
Notecarrier A Rev 1.7
×1
Blues Notecard (Cellular)
Blues Notecard (Cellular)
Global cellular notecard
×1
Nordic Semiconductor nrf52840dk
×1
Seeed Studio Grove - VOC Gas Sensor (SGP40)
×1
u-blox NEO-6M GPS module
×1
DFRobot A01NYUB Waterproof Ultrasonic Distance Sensor (28~750cm, UART, IP67)
×1
Seeed Studio Grove - VOC Gas Sensor (SGP40), Volatile Organic Compound detection, I2C
×1
Pmod ALS
Digilent Pmod ALS
×1

Software apps and online services

Apache Mynewt OS
Blues Notehub.io
Blues Notehub.io

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Solder Wire, Lead Free
Solder Wire, Lead Free

Story

Read more

Code

sgp40.h

C Header File
header file for air-quality sensor sgp40
/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#ifndef _sht44_h_
#define _sht44_h_

#define SGP30_ADDRESS       0x58
#define I2C_NUMBER          1

uint32_t find_sgp30_chip_id();
int probe_spg30();
int init_sgp30_air_quality();

uint16_t measure_air_quality_tvoc();
uint16_t measure_air_quality_vco2();

#endif

Main.c

C/C++
Main.c file with all the tasks. Edit product uuid
/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#include "sysinit/sysinit.h"
#include "os/os.h"
#include "bsp/bsp.h"

#include "hal/hal_gpio.h"
#include "hal/hal_i2c.h"
#include "hal/hal_uart.h"
#include "hal/hal_spi.h"

#include "log/log.h"

#include <console/console.h>

#include "host/ble_uuid.h"
#include "host/ble_hs.h"
#include "host/util/util.h"
#include "services/gap/ble_svc_gap.h"

#include "sgp40.h"
#include "shtc3.h"
#include "ble_gatt.h"

#include <note.h>
#include "note_c_hooks.h"

#define 	UART_NUM 	            1
#define 	UART_BAUDRATE 	        9600
#define		UART_DATA_BITS	        8

#define 	UART_TASK_PRIO		    (100)
#define 	UART_TASK_STACK_SIZE	256

#define     I2C_TASK_PRIO           (80)
#define     I2C_TASK_STACK_SIZE     256

#define     SPI_TASK_PRIO           (20)
#define     SPI_TASK_STACK_SIZE     164
#define     SPI_NUMBER              0

#define     NOTECARD_TASK_PRIO      (11)
#define     NOTECARD_TASK_STACK_SIZE 256

/*Product UUID of smart tank*/

#define PRODUCT_UID ""

uint16_t tvoc, vco2;
uint16_t temp, humy;
uint16_t AmbientLight;
uint16_t dist;

float level;

float lati, longi, tlati, tlongi;

struct distancesensor {
    int uart;
    uint8_t distance[4];
    int count;
    uint16_t value;
    uint16_t sum;
} distancesensor;

struct os_task uart_task;
struct os_task i2c_task;
struct os_task spi_task;
struct os_task notecard_task;

os_stack_t *uart_task_stack;
os_stack_t *i2c_task_stack;
os_stack_t *spi_task_stack;
os_stack_t *notecard_task_stack;

static int tx_func(void *arg) {
    //static char *a = "Hello world";
    return -1;
}

static int rx_func(void *arg, uint8_t data) {
    struct distancesensor *d = (struct distancesensor *)arg;
    
    if(d->count >= sizeof(d -> distance)){
        d->count = 0;
        
        if(d -> distance[0] == 0xFF){
            d->sum = ((d -> distance[0] + d-> distance[1] + d->distance[2]) & 0xFF);
            dist = d->distance[1]*256 + d->distance[2];
            level = 2000 - dist;
            //level = dist;
            console_printf("\nThe distance is %d mm", dist);
            if(d->sum != d->distance[3]){
                console_printf("invalid distance\n");
            }
        }
    }
    d->distance[d->count] = data;
    d->count++;
    //console_printf("data is this %d", data);
    return 0;
}

void uart_task_func(void *arg)
{
    int rc;
    
    struct distancesensor distancesensor;

    rc = hal_uart_init_cbs(UART_NUM, tx_func, NULL, rx_func, &distancesensor);
    
    if (rc) {
    	console_printf("uart init failed with %d\n", rc);
    }    
    rc = hal_uart_config(UART_NUM, UART_BAUDRATE, UART_DATA_BITS, UART_NUM, HAL_UART_PARITY_NONE, HAL_UART_FLOW_CTL_NONE);

    if (rc){
    	console_printf("uart configuration failed with %d", rc);
    }
    hal_uart_close(UART_NUM);
    os_time_delay(1000);
    
    while(1){
    	os_time_delay(100);
    	hal_uart_config(UART_NUM, UART_BAUDRATE, UART_DATA_BITS, UART_NUM, HAL_UART_PARITY_NONE, HAL_UART_FLOW_CTL_NONE);
        os_time_delay(OS_TICKS_PER_SEC);
        hal_uart_close(UART_NUM);        
        os_time_delay(5000);
    }
}

void i2c_task_func(void *arg) {

    int rc;
    os_time_delay(100);
    rc = init_sgp30_air_quality();
    console_printf("init sensor is %d \n", rc);
    os_time_delay(100);
    rc = init_shtc3_sensor();
    console_printf("init sensor is %d \n", rc);
    os_time_delay(9100);
    
    while(1) {
        tvoc = measure_air_quality_tvoc();
        vco2 = measure_air_quality_vco2();

        console_printf("TVOC: %d \n\tVCO2: %d\n", tvoc, vco2);
        
        humy = measure_humidity_normal_mode(1);
        temp = measure_temperature_normal_mode(1);
        console_printf("\nTemperature: %d\n\tHumidity: %d\n", temp, humy);
        os_time_delay(10000);
    }  
}

void spi_task_func(void *arg){

    //int rc;
    uint8_t rx[2];
    uint8_t tx[2];

    struct hal_spi_settings spi_settings = {
        .data_mode = HAL_SPI_MODE0,
        .data_order = HAL_SPI_MSB_FIRST,
        .word_size = HAL_SPI_WORD_SIZE_8BIT,
        .baudrate = 2000
    };
    
    hal_spi_disable(SPI_NUMBER);
    hal_spi_config(SPI_NUMBER, &spi_settings);
    hal_spi_enable(SPI_NUMBER);

    hal_gpio_init_out(44, 1);
    os_time_delay(OS_TICKS_PER_SEC);
    hal_gpio_init_out(44, 0);
    os_time_delay(1000);

    while(1){
        hal_gpio_init_out(44, 1);
        os_time_delay(OS_TICKS_PER_SEC/5);
        hal_gpio_init_out(44, 0);
        hal_spi_txrx(SPI_NUMBER, tx, rx, 2);
        AmbientLight = (rx[0] << 3) | (rx[1] >> 5);
        console_printf("\nThe light is %d\n", AmbientLight);
        os_time_delay(9000);
    }
}

void notecard_task_func(void *arg) {
    os_time_delay(1000);
    
    J *track = NoteNewRequest("card.aux");
    JAddStringToObject(track, "mode", "track");
    NoteRequestWithRetry(track, 5);
    
    J *gps = NoteNewRequest("card.aux.serial");
    JAddStringToObject(gps, "mode","gps");

    NoteRequestWithRetry(gps, 5);
    
    gps = NoteNewRequest("card.location.mode");
    JAddStringToObject(gps, "mode","continuous");
    NoteRequestWithRetry(gps, 5);
    os_time_delay(10000);

    while(1) {
        gps = NoteRequestResponse(NoteNewRequest("card.location"));
        
        if(gps != NULL) {
            lati = JGetNumber(gps, "lat");
            longi = JGetNumber(gps, "lon");
        }
        J *timereq = NoteRequestResponse(NoteNewRequest("card.time"));
        if(timereq != NULL){
              tlati = JGetNumber(timereq, "lat");
              tlongi = JGetNumber(timereq, "lon");
          }

        J *body = JCreateObject();
        JAddStringToObject(body, "message", "location-airq-level");
        JAddNumberToObject(body, "latitude", lati);
        JAddNumberToObject(body, "longitude", longi);
        JAddNumberToObject(body, "Towerlatitude", tlati);
        JAddNumberToObject(body, "Towerlongitude", tlongi);

        JAddNumberToObject(body, "tvoc", tvoc);
        JAddNumberToObject(body, "vco2", vco2);
        JAddNumberToObject(body, "ambientlight", AmbientLight);
        JAddNumberToObject(body, "waterlevel", level);
        JAddNumberToObject(body, "temperature", temp);
        

        J *file = NoteNewRequest("note.add");
        JAddStringToObject(file, "file", "locationinf.qo");
        JAddBoolToObject(file, "sync", true);
        JAddBoolToObject(file, "live", true);
            
        JAddItemToObject(file, "body", body);
        NoteRequest(file);
        NoteNewRequest("hub.sync");

        os_time_delay(300000);
    }
}
static const char *device_name = "Notecard_server";
static void advertise(void);

static int
adv_event(struct ble_gap_event *event, void *arg)
{
    switch (event->type) {
    case BLE_GAP_EVENT_ADV_COMPLETE:
        MODLOG_DFLT(INFO, "Advertising completed, termination code: %d\n",
                    event->adv_complete.reason);
        advertise();
        return 0;

    case BLE_GAP_EVENT_DISCONNECT:
    	advertise();
    	return 0;

    default:
        MODLOG_DFLT(ERROR, "Advertising event not handled\n");
        return 0;
    }
}

static void 
set_ble_addr(void) {
    int rc;

    ble_addr_t addr;

    rc = ble_hs_id_gen_rnd(1, &addr);
    assert(rc == 0);
    
    rc = ble_hs_id_set_rnd(addr.val);
    assert(rc == 0);
}

/* For LED toggling */
int g_led_pin;

static void
on_sync(void) {
    set_ble_addr();
    /*begin advertising*/
    advertise();
}

static void 
on_reset(int reason) {
    MODLOG_DFLT(INFO, "Resetting state; reason=%d\n", reason);
}

static void 
advertise(void) {

    int rc;
    ble_gap_set_prefered_default_le_phy(BLE_GAP_LE_PHY_CODED_MASK, BLE_GAP_LE_PHY_CODED_MASK);
    struct ble_gap_adv_params adv_params;
    struct ble_hs_adv_fields fields;

    /*set advertise params*/
    memset(&adv_params, 0, sizeof(adv_params));
    adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
    adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;

    memset(&fields, 0, sizeof(fields));

    fields.flags = BLE_HS_ADV_F_DISC_GEN;
    fields.tx_pwr_lvl_is_present = 1;
    fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
    fields.name = (uint8_t *)device_name;
    fields.name_len = strlen(device_name);
    fields.name_is_complete = 1;

    rc = ble_gap_adv_set_fields(&fields);
    assert(rc == 0);

    MODLOG_DFLT(INFO, "Starting advetising \n");

    rc = ble_gap_adv_start(BLE_OWN_ADDR_RANDOM, NULL, 10000, &adv_params, adv_event, NULL);
}
/**
 * main
 *
 * The main task for the project. This function initializes packages,
 * and then blinks the BSP LED in a loop.
 *
 * @return int NOTE: this function should never return!
 */
int
mynewt_main(int argc, char **argv)
{
    int rc;
    //void cfg;
    
    sysinit();
    ble_hs_cfg.sync_cb = on_sync;
    ble_hs_cfg.reset_cb = on_reset;

    rc = hal_i2c_enable(I2C_NUMBER);

    struct hal_i2c_settings settings = {
        .frequency = 100,
    };

    rc = hal_i2c_config(I2C_NUMBER, &settings);

    NoteSetFnDefault(malloc, free, platform_delay, platform_millis);
    NoteSetFnDebugOutput(note_log_print);
    NoteSetFnI2C(NOTE_I2C_ADDR_DEFAULT, NOTE_I2C_MAX_DEFAULT, note_i2c_reset, note_i2c_transmit, note_i2c_receive);

    J *req = NoteNewRequest("hub.set");
    JAddStringToObject(req, "product", PRODUCT_UID);
    JAddStringToObject(req, "mode", "continuos");
    JAddBoolToObject(req, "sync", true);

    NoteRequestWithRetry(req, 5);
    
    uart_task_stack = malloc(sizeof(os_stack_t)*UART_TASK_STACK_SIZE);
    os_task_init(&uart_task, "uart_task", uart_task_func, NULL, UART_TASK_PRIO, OS_WAIT_FOREVER, uart_task_stack, UART_TASK_STACK_SIZE);

    i2c_task_stack = malloc(sizeof(os_stack_t)*I2C_TASK_STACK_SIZE);
    os_task_init(&i2c_task, "i2c_task", i2c_task_func, NULL, I2C_TASK_PRIO, OS_WAIT_FOREVER, i2c_task_stack, I2C_TASK_STACK_SIZE);

    spi_task_stack = malloc(sizeof(os_stack_t)*SPI_TASK_STACK_SIZE);
    os_task_init(&spi_task, "spi_task", spi_task_func, NULL, SPI_TASK_PRIO, OS_WAIT_FOREVER, spi_task_stack, SPI_TASK_STACK_SIZE);
    
    notecard_task_stack = malloc(sizeof(os_stack_t)*NOTECARD_TASK_STACK_SIZE);
    os_task_init(&notecard_task, "notecard_task", notecard_task_func, NULL, NOTECARD_TASK_PRIO, OS_WAIT_FOREVER, notecard_task_stack, NOTECARD_TASK_STACK_SIZE);

    rc = ble_svc_gap_device_name_set(device_name);
    assert(rc == 0);
    
    gatt_service_init();
    
    g_led_pin = LED_BLINK_PIN;
    hal_gpio_init_out(g_led_pin, 1);

    while (1) {
        /* Wait one second */
        os_eventq_run(os_eventq_dflt_get());
        
        /* Toggle the LED */
        //hal_gpio_toggle(g_led_pin);  
    }    
    assert(0);   
}

note_c_hooks.h

C Header File
note-c hooks header file
#ifndef NOTE_C_HOOKS_H
#define NOTE_C_HOOKS_H

#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>


void platform_delay(uint32_t ms);
uint32_t platform_millis(void);

const char *note_i2c_receive(uint16_t device_address_, uint8_t *buffer_, uint16_t size_, uint32_t *available_);
bool note_i2c_reset(uint16_t device_address_);
const char *note_i2c_transmit(uint16_t device_address_, uint8_t *buffer_, uint16_t size_);

size_t note_log_print(const char *message_);

#endif // NOTE_C_HOOKS_H

note_c_hooks.c

C/C++
source code for notecard i2c operation
#include "note_c_hooks.h"
#include "bsp/bsp.h"

#include "hal/hal_i2c.h"

#include "os/os_time.h"

#include <console/console.h>

static const size_t REQUEST_HEADER_SIZE = 2;

const uint8_t i2c_num = 1;
bool i2c_initialized = false;


uint32_t platform_millis(void) {
    return (uint32_t)(os_get_uptime_usec()/1000);
}

void platform_delay(uint32_t ms) {
    os_time_delay((OS_TICKS_PER_SEC/1000) * ms);
}

const char *note_i2c_receive(uint16_t device_address_, uint8_t *buffer_, uint16_t size_, uint32_t *available_) {
  {
    //const int request_length = size_ + REQUEST_HEADER_SIZE;
    //request_length
    uint8_t size_buf[2];
    size_buf[0] = 0;
    size_buf[1] = (uint8_t)size_;

    struct hal_i2c_master_data data = {
        .address = device_address_,
        .len = sizeof(size_buf),
        .buffer = size_buf,
    };
    uint8_t write_result = hal_i2c_master_write(i2c_num, &data,OS_TICKS_PER_SEC / 10, 0);

    if (write_result != 0) {
        return "i2c: unable to initiate read from the notecard\n";
    }
    // Read from the Notecard and copy the response bytes into the response buffer
    const int request_length = size_ + REQUEST_HEADER_SIZE;
    uint8_t read_buf[256];

    data.len = request_length;
    data.buffer = read_buf;
    uint8_t read_result = hal_i2c_master_read(i2c_num, &data,OS_TICKS_PER_SEC / 10, 1);

    if (read_result != 0) {
        return "i2c: Unable to receive data from the Notecard.\n";
    } else {
        *available_ = (uint32_t)read_buf[0];
        uint8_t bytes_to_read = read_buf[1];
        for (size_t i = 0; i < bytes_to_read; i++) {
            buffer_[i] = read_buf[i + 2];
        }
        return NULL;
    }
}}

bool note_i2c_reset(uint16_t device_address_){

    (void)device_address_;

    if(i2c_initialized){
        return true;
    }
    if(hal_i2c_enable(i2c_num) != 0){
        console_printf("i2c: Device not ready.\n");
        return false;
    }

    console_printf("i2c: Device is ready.\n");

    i2c_initialized = true;

    return true;
}

const char *note_i2c_transmit(uint16_t device_address_, uint8_t *buffer_, uint16_t size_) 
{

    uint8_t write_buf[size_ + 1];
    write_buf[0] = (uint8_t)size_;
    for (size_t i = 0; i < size_; i++) {
        write_buf[i + 1] = buffer_[i];
    }

    struct hal_i2c_master_data data = {
        .address = device_address_,
        .len = size_ + 1,
        .buffer = write_buf,
    };

    uint8_t write_result = hal_i2c_master_write(i2c_num, &data,OS_TICKS_PER_SEC / 5, 1);

    if (write_result != 0) {
        return "i2c: Unable to transmit data to the Notecard\n";
    } else {
        return NULL;
    }
}

size_t note_log_print(const char *message_) {
    
    if(message_){
        console_printf("%s", message_);
        return 1;        
    }

    return 0;

}

sgp40.c

C/C++
source file for sgp40 air quality sensor
/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#include "hal/hal_i2c.h"

#include "sgp40.h"
#include "log/log.h"

#include <console/console.h>
#include "os/os.h"


int probe_spg30(){
    int rc;
    rc = hal_i2c_master_probe(I2C_NUMBER, SGP30_ADDRESS, OS_TICKS_PER_SEC / 5);

    return rc;
}


uint32_t find_sgp30_chip_id()
{
    uint32_t chip_id = 0;
    uint8_t command[2] = {0x36, 0x82};    
    
    struct hal_i2c_master_data data = {
        .address = SGP30_ADDRESS,
        .len = sizeof(command),
        .buffer = command,
    };

    int write_result = hal_i2c_master_write(I2C_NUMBER, &data, OS_TICKS_PER_SEC / 5, 0);

    if (write_result != 0)
    {
        console_printf("Write not successful %d \n", write_result);
    }

    uint8_t id[6];
    data.len = sizeof(id);
    data.buffer = id;

    write_result = hal_i2c_master_read(I2C_NUMBER, &data, OS_TICKS_PER_SEC / 5, 1);

    if (write_result != 0)
    {
        console_printf("read not successful %d \n", write_result);
    }

    chip_id = ((id[0] << 16) | (id[2] << 8) | (id[4]));
    
    return chip_id;

}

int init_sgp30_air_quality()
{
    uint8_t command[2] = {0x20, 0x03};

    struct hal_i2c_master_data data = {
        .address = SGP30_ADDRESS,
        .len = sizeof(command),
        .buffer = command,
    };

    int write_result = hal_i2c_master_write(I2C_NUMBER, &data, OS_TICKS_PER_SEC / 5, 0);

    if (write_result != 0)
    {
        console_printf("Write not successful %d \n", write_result);
    }
    os_time_delay(OS_TICKS_PER_SEC/2);
    return write_result;
}

uint16_t measure_air_quality_tvoc()
{
    
    uint16_t tvoc;
    uint8_t buf[6];

    uint8_t command[2] = {0x20, 0x08};

    struct hal_i2c_master_data data = {
        .address = SGP30_ADDRESS,
        .len = sizeof(command),
        .buffer = command,
    };

    int write_result = hal_i2c_master_write(I2C_NUMBER, &data, OS_TICKS_PER_SEC / 5, 0);

    if (write_result != 0)
    {
        console_printf("Write not successful %d \n", write_result);
    }
    os_time_delay(OS_TICKS_PER_SEC/2);
    data.len = sizeof(buf);
    data.buffer = buf;

    write_result = hal_i2c_master_read(I2C_NUMBER, &data, OS_TICKS_PER_SEC / 2, 1);

    if (write_result != 0)
    {
        console_printf("read not successful %d \n", write_result);
    }

    tvoc = ((buf[3] << 8) | buf[4]);

    return tvoc;
    
}


uint16_t measure_air_quality_vco2()
{
    
    uint16_t vco2;
    uint8_t buf[6];

    uint8_t command[2] = {0x20, 0x08};

    struct hal_i2c_master_data data = {
        .address = SGP30_ADDRESS,
        .len = sizeof(command),
        .buffer = command,
    };

    int write_result = hal_i2c_master_write(I2C_NUMBER, &data, OS_TICKS_PER_SEC / 5, 0);

    if (write_result != 0)
    {
        console_printf("Write not successful %d \n", write_result);
    }

    os_time_delay(OS_TICKS_PER_SEC/2);
    data.len = sizeof(buf);
    data.buffer = buf;

    write_result = hal_i2c_master_read(I2C_NUMBER, &data, OS_TICKS_PER_SEC / 2, 1);

    if (write_result != 0)
    {
        console_printf("read not successful %d \n", write_result);
    }
    
    vco2 = ((buf[0] << 8) | buf[1]);

    return vco2;
}

shtc3.h

C Header File
Header file for SHTC3 sensor
/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#ifndef _shtc3_h_
#define _shtc3_h_

#define SHTC3_ADDRESS       0x70
#define I2C_NUMBER          1

int probe_shtc3();
int init_shtc3_sensor();

uint16_t measure_humidity_normal_mode(int clock_stretching);
uint16_t measure_temperature_normal_mode(int clock_stretching);

#endif

shtc3.c

C/C++
source file for shtc3 sensor
/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#include "hal/hal_i2c.h"

#include "sgp40.h"
#include "log/log.h"

#include <console/console.h>
#include "os/os.h"

#include "shtc3.h"


int probe_shtc3() {
    int rc;
    rc = hal_i2c_master_probe(I2C_NUMBER, SHTC3_ADDRESS, OS_TICKS_PER_SEC / 5);

    return rc;
}

int init_shtc3_sensor() {

    int write_result;
    uint8_t command[2] = {0xB0, 0x98};

    struct hal_i2c_master_data data = {
        .address = SHTC3_ADDRESS,
        .len = sizeof(command),
        .buffer = command,
    };
    /* set the sensor into sleep mode */
    write_result = hal_i2c_master_write(I2C_NUMBER, &data, OS_TICKS_PER_SEC / 5, 1);
    
    if (write_result != 0)
    {
        console_printf("Write not successful %d \n", write_result);
    }

    command[0] = 0x35;
    command[1] = 0x17;

    /* set the sensor into wakeup mode */
    write_result = hal_i2c_master_write(I2C_NUMBER, &data, OS_TICKS_PER_SEC / 5, 1);
    
    if (write_result != 0)
    {
        console_printf("Write not successful %d \n", write_result);
    }
    return write_result;
}

uint16_t measure_temperature_normal_mode(int clock_stretching) {

    uint16_t temperature;
    int write_result;
    uint8_t command[2] = {0x78, 0x66};

    if(clock_stretching){
        command[0] = 0x7C;
        command[1] = 0xA2;
    }
    
    struct hal_i2c_master_data data = {
        .address = SHTC3_ADDRESS,
        .len = sizeof(command),
        .buffer = command,
    };
    /* send command to have normal mode with clock_stretching enable/disabled and read T first */

    write_result = hal_i2c_master_write(I2C_NUMBER, &data, OS_TICKS_PER_SEC / 5, 1);

    if (write_result != 0)
    {
        console_printf("Write not successful %d \n", write_result);
    }

    os_time_delay(OS_TICKS_PER_SEC/2);

    /* now read the data in buffer*/
    
    uint8_t buf[6];

    data.len = sizeof(buf);
    data.buffer = buf;

    write_result = hal_i2c_master_read(I2C_NUMBER, &data, OS_TICKS_PER_SEC / 2, 1);
    
    temperature = (-45) + 0.00267 *((buf[0]<<8) | buf[1]);

    return temperature;

}

uint16_t measure_humidity_normal_mode(int clock_stretching) {

    float humidity = 0.00;
    
    int write_result;

    uint8_t command[2] = {0x78, 0x66};

    if(clock_stretching){
        command[0] = 0x7C;
        command[1] = 0xA2;
    }
    
    struct hal_i2c_master_data data = {
        .address = SHTC3_ADDRESS,
        .len = sizeof(command),
        .buffer = command,
    };
    /* send command to have normal mode with clock_stretching enable/disabled and read T first */

    write_result = hal_i2c_master_write(I2C_NUMBER, &data, OS_TICKS_PER_SEC / 5, 1);

    if (write_result != 0)
    {
        console_printf("Write not successful %d \n", write_result);
    }

    os_time_delay(OS_TICKS_PER_SEC/2);

    /* now read the data in buffer*/
    
    uint8_t buf[6];

    data.len = sizeof(buf);
    data.buffer = buf;

    write_result = hal_i2c_master_read(I2C_NUMBER, &data, OS_TICKS_PER_SEC / 2, 1);
    
    humidity = ((buf[3]<<8) | buf[4]);
    humidity = humidity / 16384;


    return humidity;

}

ble_gatt.h

C Header File
header file for ble services and characteristic
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#ifndef _BLE_GATT_H_
#define _BLE_GATT_H_

extern uint16_t dist;
extern uint16_t tvoc, vco2;
extern uint16_t temp, humy;
extern uint16_t AmbientLight;

int gatt_service_init(void);
int gatt_ser_char_access_cb(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);

#endif

ble_gatt.c

C/C++
ble_gatt.c file for service and characteristic registration
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "bsp/bsp.h"
#include "host/ble_hs.h"
#include "host/ble_uuid.h"

#include "ble_gatt.h"

//static int gatt_ser_char_access_cb(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg);

static const ble_uuid128_t gatt_uuid_water_level = BLE_UUID128_INIT(0x6c, 0xb7, 0x3a, 0xc5, 0x53, 0x82, 0x4c, 0x2f, 0x92, 0x8e, 0x91, 0x91, 0xe3, 0x41, 0x3a, 0x58);
static const ble_uuid128_t gatt_uuid_water_level_char = BLE_UUID128_INIT(0x32, 0x58, 0x76, 0xe4, 0xbc, 0xdc, 0x11, 0xed, 0xaf, 0xa1, 0x02, 0x42, 0xac, 0x12, 0x00, 0x02);

static const ble_uuid128_t gatt_uuid_weather_service = BLE_UUID128_INIT(0x6c, 0xb7, 0x3a, 0xc5, 0x53, 0x82, 0x4c, 0x2f, 0x92, 0x8e, 0x91, 0x91, 0xe3, 0x41, 0x3a, 0x59);
static const ble_uuid128_t gatt_uuid_weather_char_tvoc = BLE_UUID128_INIT(0x32, 0x58, 0x76, 0xe4, 0xbc, 0xdc, 0x11, 0xed, 0xaf, 0xa1, 0x02, 0x42, 0xac, 0x12, 0x00, 0x03);
static const ble_uuid128_t gatt_uuid_weather_char_vco2 = BLE_UUID128_INIT(0x32, 0x58, 0x76, 0xe4, 0xbc, 0xdc, 0x11, 0xed, 0xaf, 0xa1, 0x02, 0x42, 0xac, 0x12, 0x00, 0x04);
static const ble_uuid128_t gatt_uuid_weather_char_temp = BLE_UUID128_INIT(0x32, 0x58, 0x76, 0xe4, 0xbc, 0xdc, 0x11, 0xed, 0xaf, 0xa1, 0x02, 0x42, 0xac, 0x12, 0x00, 0x05);
static const ble_uuid128_t gatt_uuid_weather_char_ambient_light = BLE_UUID128_INIT(0x32, 0x58, 0x76, 0xe4, 0xbc, 0xdc, 0x11, 0xed, 0xaf, 0xa1, 0x02, 0x42, 0xac, 0x12, 0x00, 0x06);


static const struct ble_gatt_svc_def gatt_svr_water_level_svcs[] = {
    {
    .type = BLE_GATT_SVC_TYPE_PRIMARY,
    .uuid = &gatt_uuid_water_level.u, 
    .characteristics = (struct ble_gatt_chr_def[]) { {
        .uuid = &gatt_uuid_water_level_char.u,
        .access_cb = gatt_ser_char_access_cb,
        .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ,
    }, 
    {
        0,
    }
    },},
    {
        0,
    },
};

static const struct ble_gatt_svc_def gatt_svr_weather_svcs[] = {
    {
    .type = BLE_GATT_SVC_TYPE_PRIMARY,
    .uuid = &gatt_uuid_weather_service.u, 
    .characteristics = (struct ble_gatt_chr_def[]) { {
        .uuid = &gatt_uuid_weather_char_tvoc.u,
        .access_cb = gatt_ser_char_access_cb,
        .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ,
    },
    {
        .uuid = &gatt_uuid_weather_char_vco2.u,
        .access_cb = gatt_ser_char_access_cb,
        .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ,
    },
    {
        .uuid = &gatt_uuid_weather_char_temp.u,
        .access_cb = gatt_ser_char_access_cb,
        .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ,
    },
    {
        .uuid = &gatt_uuid_weather_char_ambient_light.u,
        .access_cb = gatt_ser_char_access_cb,
        .flags = BLE_GATT_CHR_F_READ | BLE_GATT_CHR_F_READ,
    },
    {
        0,
    }
    },},
    {
        0,
    },
};


int gatt_ser_char_access_cb(uint16_t conn_handle, uint16_t attr_handle, struct ble_gatt_access_ctxt *ctxt, void *arg)
{
    int rc = 0;
    const ble_uuid_t *uuid;
    char data[8];
    data[6] = 'm';
    data[7] = 'm';
    
    uuid = ctxt->chr->uuid;
    
    /* Determine which characteristic is read */
    if(ble_uuid_cmp(uuid, &gatt_uuid_water_level_char.u) == 0) {
    	assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
    	sprintf(data, "%d", dist);        
    	rc = os_mbuf_append(ctxt->om, &data, sizeof data);
    	return rc;    	    
    }

    if(ble_uuid_cmp(uuid, &gatt_uuid_weather_char_tvoc.u) == 0) {
        assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
        rc = os_mbuf_append(ctxt->om, &tvoc, sizeof tvoc);
        return rc;
    }

    if(ble_uuid_cmp(uuid, &gatt_uuid_weather_char_vco2.u) == 0) {
        assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
        rc = os_mbuf_append(ctxt->om, &vco2, sizeof vco2);
        return rc;
    }
    if(ble_uuid_cmp(uuid, &gatt_uuid_weather_char_temp.u) == 0) {
        assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
        rc = os_mbuf_append(ctxt->om, &temp, sizeof temp);
        return rc;
    }
    if(ble_uuid_cmp(uuid, &gatt_uuid_weather_char_ambient_light.u) == 0) {
        assert(ctxt->op == BLE_GATT_ACCESS_OP_READ_CHR);
        rc = os_mbuf_append(ctxt->om, &AmbientLight, sizeof AmbientLight);
        return rc;
    }
    
    return rc;
}


int gatt_service_init(void){
	
	int rc;
	
	rc = ble_gatts_count_cfg(gatt_svr_water_level_svcs);
	
	if(rc != 0){
		return rc;
	}
	rc = ble_gatts_add_svcs(gatt_svr_water_level_svcs);    
	
	if(rc != 0){
		return rc;
	}
    
    rc = ble_gatts_count_cfg(gatt_svr_weather_svcs);
	
	if(rc != 0){
		return rc;
	}
	rc = ble_gatts_add_svcs(gatt_svr_weather_svcs);    
	
	if(rc != 0){
		return rc;
	}
    
	return 0;
}

Credits

ujjval rathod

ujjval rathod

9 projects • 19 followers

Comments