Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
Software apps and online services | ||||||
| ||||||
|
Idea:
The idea was to build a portable smart vehicular emission monitoring system that can measure multiple sensor outputs from the accelerometer (on board of quick feather), Grove - CO2 & Temperature & Humidity Sensor (SCD30), etc., simultaneously. The multiple sensor data feeds were to be used to understand the relation between the 3D acceleration (x,y,z) and the physical characteristics(temperature) and composition(CO2, humidity) of the emission.
Milestones achieved:
- Getting started with Quick feather.
- Using the Eclipse Development Environment and importing my first Project
- Programming the board using TinyFPGA
- Connecting the Quick feather with Adafruit HUZZAH32-ESP32 Feather Board
Goals yet to be achieved:
- Connecting multiple I2C sensors and simultaneously capturing the data using WIFI and Data Capture Lab(DCL).
Discussions about the project:
Connecting Adafruit HUZZAH32-ESP32 Feather Board with Quickfeather board was a bit confusing. So, I will try to detail the process as I have followed(OS windows):
- Install ESP-IDF for windows
- ESP-IDF Tools Installer creates a shortcut in the Start menu to launch the ESP-IDF Command Prompt
- Open the ESP-IDF Command Prompt from the Start menu.
- Use the 'dir' command to see the files and folders in the directory. Check the list to find an examples folder.
- Go inside the examples folder and create a directory named sensiml_esp32 or anything of your choice, and then use the following command to clone the repository: git clone https://github.com/sensiml/esp32_simple_http_uart.git --recursive
- Once the repository is cloned, go inside the folder in which you have cloned the repository type the following command to set the target:
idf.py set-target esp32
- Then use the following command to open the Menu configuration:
idf.py menuconfig
Configuring WiFi SSID/Password
UART Configuration
Swapping UART Pins
You will need to swap the UART RX/TX Pinsif the two feather boards are connected. Select Data UART Swap RX/TX to do this.
Changing Data UART Baud Rate
The application defaults to 480600 bps as a baud rate for the UART. This can be configured in the configuration.
And choose from the list of options
Configuring the Flash Size
The application defaults to 4MB of flash. You may need to change this value depending on your boards' manufacture. To do that,
Select, Serial Flasher Config
And choose from the list of options
- After the above configuration is done, the following command is used to build the program:
idf.py build
- Then the target board is connected to the PC (in this case, Adafruit HUZZAH32-ESP32 Feather Board), and the COM port is determined.
- Then using the following command, the board is flashed:
idf.py -p [PORT] flash
example: idf.py -p COM4 flash (the board is connected to COM4)
Following this, the ESP32 board can be connected to the quick feather board, which can be found here.
The device can the used to connect to DCL for data capture. (see this video in SenisiML Tutorial page 'Connecting QuickFeather and Data Capture Lab over WiFi Using the ESP32' from time 14:02)
I have tried to connect the Grove - CO2 & Temperature & Humidity Sensor (SCD30) (library) by making the necessary changes as shown in the tutorial of the SensiML page but could not debug it completely.
I have attached the source files. Any help is appreciated.
/*
A library for Grove -
Copyright (c) 2018 seeed technology co., ltd.
Author : Wayen Weng
Create Time : November 2018
Change Log :
The MIT License (MIT)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "SCD30.h"
#include "Fw_global_config.h"
#include "FreeRTOS.h"
#include "task.h"
extern "C" void HAL_DelayUsec(unit32_t usecs);
unsigned long millis()
{
TickType_t ticks;
ticks =xTaskGetTickCount();
return (unsigned long)ticks;
}
void delay(unsigned long ms)
{
HAL_DelayUSec(ms*1000);
}
SCD30::SCD30(void) {
devAddr = SCD30_I2C_ADDRESS;
}
void SCD30::initialize(void) {
//Set temperature offset。
//setTemperatureOffset(0);
Wire.begin(); // Added Wire begin to avoid infinite waiting
setMeasurementInterval(2); // 2 seconds between measurements
startPeriodicMeasurment(); // start periodic measuments
//setAutoSelfCalibration(true); // Enable auto-self-calibration
}
void SCD30::setTemperatureOffset(uint16_t offset) {
writeCommandWithArguments(SCD30_SET_TEMP_OFFSET, offset);
}
bool SCD30::isAvailable(void) {
return readRegister(SCD30_GET_DATA_READY);
}
void SCD30::setAutoSelfCalibration(bool enable) {
if (enable) {
writeCommandWithArguments(SCD30_AUTOMATIC_SELF_CALIBRATION, 1); //Activate continuous ASC
} else {
writeCommandWithArguments(SCD30_AUTOMATIC_SELF_CALIBRATION, 0); //Deactivate continuous ASC
}
}
void SCD30::setMeasurementInterval(uint16_t interval) {
writeCommandWithArguments(SCD30_SET_MEASUREMENT_INTERVAL, interval);
}
void SCD30::startPeriodicMeasurment(void) {
writeCommandWithArguments(SCD30_CONTINUOUS_MEASUREMENT, 0x0000);
}
void SCD30::stopMeasurement(void) {
writeCommand(SCD30_STOP_MEASUREMENT);
}
void SCD30::getCarbonDioxideConcentration(float* result) {
uint8_t buf[18] = { 0 };
uint32_t co2U32 = 0;
uint32_t tempU32 = 0;
uint32_t humU32 = 0;
float co2Concentration = 0;
float temperature = 0;
float humidity = 0;
writeCommand(SCD30_READ_MEASUREMENT);
readBuffer(buf, 18);
co2U32 = (uint32_t)((((uint32_t)buf[0]) << 24) | (((uint32_t)buf[1]) << 16) |
(((uint32_t)buf[3]) << 8) | ((uint32_t)buf[4]));
tempU32 = (uint32_t)((((uint32_t)buf[6]) << 24) | (((uint32_t)buf[7]) << 16) |
(((uint32_t)buf[9]) << 8) | ((uint32_t)buf[10]));
humU32 = (uint32_t)((((uint32_t)buf[12]) << 24) | (((uint32_t)buf[13]) << 16) |
(((uint32_t)buf[15]) << 8) | ((uint32_t)buf[16]));
memcpy(&result[0], &co2U32, sizeof(co2Concentration));
memcpy(&result[1], &tempU32, sizeof(temperature));
memcpy(&result[2], &humU32, sizeof(humidity));
}
void SCD30::writeCommand(uint16_t command) {
Wire.beginTransmission(devAddr);
Wire.write(command >> 8); // MSB
Wire.write(command & 0xff); // LSB
Wire.endTransmission();
}
void SCD30::writeCommandWithArguments(uint16_t command, uint16_t arguments) {
uint8_t checkSum, buf[5] = { 0 };
buf[0] = command >> 8;
buf[1] = command & 0xff;
buf[2] = arguments >> 8;
buf[3] = arguments & 0xff;
checkSum = calculateCrc(&buf[2], 2);
buf[4] = checkSum;
writeBuffer(buf, 5);
}
uint16_t SCD30::readRegister(uint16_t address) {
uint8_t buf[2] = { 0 };
writeCommand(address);
readBuffer(buf, 2);
return ((((uint16_t)buf[0]) << 8) | buf[1]);
}
void SCD30::writeBuffer(uint8_t* data, uint8_t len) {
Wire.beginTransmission(devAddr);
Wire.write(data, len);
Wire.endTransmission();
}
void SCD30::readBuffer(uint8_t* data, uint8_t len) {
uint8_t i = 0;
Wire.requestFrom(devAddr, len);
while (Wire.available()) {
data[i ++] = Wire.read();
}
}
uint8_t SCD30::calculateCrc(uint8_t data[], uint8_t len) {
uint8_t bit, byteCtr, crc = 0xff;
// calculates 8-Bit checksum with given polynomial
for (byteCtr = 0; byteCtr < len; byteCtr ++) {
crc ^= (data[byteCtr]);
for (bit = 8; bit > 0; -- bit) {
if (crc & 0x80) {
crc = (crc << 1) ^ SCD30_POLYNOMIAL;
} else {
crc = (crc << 1);
}
}
}
return crc;
}
SCD30 scd30;
/*
A library for Grove -
Copyright (c) 2018 seeed technology co., ltd.
Author : Wayen Weng
Create Time : November 2018
Change Log :
The MIT License (MIT)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifndef __SENSIRION_SCD30_H__
#define __SENSIRION_SCD30_H__
//#include <Arduino.h>
#include <Wire.h>
#define SCD30_I2C_ADDRESS 0x61
#define SCD30_CONTINUOUS_MEASUREMENT 0x0010
#define SCD30_SET_MEASUREMENT_INTERVAL 0x4600
#define SCD30_GET_DATA_READY 0x0202
#define SCD30_READ_MEASUREMENT 0x0300
#define SCD30_STOP_MEASUREMENT 0x0104
#define SCD30_AUTOMATIC_SELF_CALIBRATION 0x5306
#define SCD30_SET_FORCED_RECALIBRATION_FACTOR 0x5204
#define SCD30_SET_TEMPERATURE_OFFSET 0x5403
#define SCD30_SET_ALTITUDE_COMPENSATION 0x5102
#define SCD30_READ_SERIALNBR 0xD033
#define SCD30_SET_TEMP_OFFSET 0x5403
#define SCD30_POLYNOMIAL 0x31 // P(x) = x^8 + x^5 + x^4 + 1 = 100110001
class SCD30 {
public:
SCD30(void);
void initialize(void);
bool isAvailable(void);
void setAutoSelfCalibration(bool enable);
void setMeasurementInterval(uint16_t interval);
void startPeriodicMeasurment(void);
void stopMeasurement(void);
void setTemperatureOffset(uint16_t offset);
void getCarbonDioxideConcentration(float* result);
private:
uint8_t calculateCrc(uint8_t* data, uint8_t len);
void writeCommand(uint16_t command);
void writeCommandWithArguments(uint16_t command, uint16_t arguments);
uint16_t readRegister(uint16_t address);
void writeBuffer(uint8_t* data, uint8_t len);
void readBuffer(uint8_t* data, uint8_t len);
uint8_t devAddr;
};
extern SCD30 scd30;
#endif
/** @file sensor_ssss_process.c */
/*==========================================================
* Copyright 2020 QuickLogic Corporation
*
* Licensed 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 <stdbool.h>
#include <stdio.h>
#include <string.h>
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "timers.h"
#include "datablk_mgr.h"
#include "process_ids.h"
#include "datablk_processor.h"
#include "sensor_ssss.h"
#include "micro_tick64.h"
#include "dbg_uart.h"
#include "ssi_comms.h"
#include "eoss3_hal_i2c.h"
#include "mc3635_wire.h"
#include "sml_recognition_run.h"
#include "DataCollection.h"
// When enabled, GPIO (configured in pincfg_table.c) is toggled whenever a
// datablock is dispacthed for writing to the UART. Datablocks are dispatched
// every (SENSOR_SSSS_LATENCY) ms
#if (SENSOR_SSSS_RATE_DEBUG_GPIO == 1)
#include "eoss3_hal_gpio.h"
uint8_t sensor_rate_debug_gpio_val = 1;
#endif
/* BEGIN user include files
* Add header files needed for accessing the sensor APIs
*/
# include "SCD30.h"
/* User settable MACROs */
/* This section defines MACROs that may be user modified */
//MC3635 qorc_ssi_accel;
SCD30 qorc_ssi_CO2TH;
/* User modifiable sensor descriptor in JSON format */
#if (SSI_SENSOR_SELECT_SSSS == 1)
/* BEGIN JSON descriptor for the sensor configuration */
const char json_string_sensor_config[] = \
"{"\
"\"sample_rate\":100,"\
"\"samples_per_packet\":6,"\
"\"column_location\":{"\
" \"Carbondioxideppm\":0,"
" \"TemperaturedegC\":1,"
" \"Humiditypercent\":2"
"}"\
"}\r\n" ;
/* END JSON descriptor for the sensor data */
#endif /* SSI_SENSOR_SELECT_SSSS */
/* User modifiable function. Update the below function
* to initialize and setup I2C sensors */
void sensor_ssss_configure(void)
{
/** @todo Replace contents of this function */
sensor_ssss_config.rate_hz = SENSOR_SSSS_SAMPLE_RATE_HZ;
sensor_ssss_config.n_channels = SENSOR_SSSS_CHANNELS_PER_SAMPLE;
sensor_ssss_config.bit_depth = SENSOR_SSSS_BIT_DEPTH;
sensor_ssss_config.sensor_id = SENSOR_SSSS_ID;
static int sensor_ssss_configured = false;
/*--- BEGIN User modifiable section ---*/
//qorc_ssi_accel.begin();
//qorc_ssi_accel.set_sample_rate(sensor_ssss_config.rate_hz);
//qorc_ssi_accel.set_sample_resolution(sensor_ssss_config.bit_depth);
//qorc_ssi_accel.set_mode(MC3635_MODE_CWAKE);
qorc_ssi_CO2TH.begin();
qorc_ssi_CO2TH.set_sample_rate(sensor_ssss_config.rate_hz);
/*--- END of User modifiable section ---*/
if (sensor_ssss_configured == false)
{
sensor_ssss_configured = true;
}
sensor_ssss_startstop(1);
}
/* User modifiable function. Update the below function
* to read sensor data sample from sensors and fill-in
* the data block with these sensor data values */
int sensor_ssss_acquisition_buffer_ready()
{
int8_t *p_dest = (int8_t *) &psensor_ssss_data_block_prev->p_data;
int dataElementSize = psensor_ssss_data_block_prev->dbHeader.dataElementSize;
int ret;
int batch_size;
p_dest += sizeof(int8_t)*sensor_ssss_samples_collected*dataElementSize;
/* Read 1 sample per channel, Fill the sample data to p_dest buffer */
/*--- BEGIN User modifiable section ---*/
//xyz_t accel_data = qorc_ssi_accel.read(); /* Read accelerometer data from MC3635 */
/* Fill this accelerometer data into the current data block */
//int16_t *p_accel_data = (int16_t *)p_dest;
//*p_accel_data++ = accel_data.x;
//*p_accel_data++ = accel_data.y;
//*p_accel_data++ = accel_data.z;
//p_dest += 6; // advance datablock pointer to retrieve and store next sensor data
/* Fill this accelerometer data into the current data block */
int16_t *p_CO2TH_data = (int16_t *)p_dest;
init16_t CO2TH_data =qorc_ssi_CO2TH.getCarbonDioxideConcentration(float*result);
*p_CO2TH_data++ = CO2TH_co2Concentration;
*p_CO2TH_data++ = CO2TH_temperature;
*p_CO2TH_data++ = CO2TH_humidity;
p_dest += 6; // advance datablock pointer to retrieve and store next sensor data
/* Read data from other sensors */
int bytes_to_read = SENSOR_SSSS_CHANNELS_PER_SAMPLE * (SENSOR_SSSS_BIT_DEPTH/8) ;
sensor_ssss_samples_collected += SENSOR_SSSS_CHANNELS_PER_SAMPLE;
batch_size = sensor_ssss_batch_size_get() * SENSOR_SSSS_CHANNELS_PER_SAMPLE;
// return 1 if batch_size of samples are collected
// return 0 otherwise
if (sensor_ssss_samples_collected >= batch_size)
{
psensor_ssss_data_block_prev->dbHeader.numDataElements = sensor_ssss_samples_collected;
psensor_ssss_data_block_prev->dbHeader.numDataChannels = SENSOR_SSSS_CHANNELS_PER_SAMPLE;
sensor_ssss_samples_collected = 0;
return 1;
}
else
{
return 0;
}
}
/** End of User modifiable code and variable */
/*========== BEGIN: SSSS SENSOR Datablock processor definitions =============*/
/** @addtogroup QAI_SSSS_PIPELINE_EXAMPLE QORC SDK SSSS pipeline example
*
* @brief SSSS pipeline example code
*
* This example code demonstrates setting up SSSS Queues,
* setting up the datablock buffer manager (\ref DATABLK_MGR)
* and setting up the datablock processor processing elements (\ref DATABLK_PE).
* A specific SSSS processing element for motion detection is provided in this
* example.
*
* @{
*/
/** Maximum number of ssss data blocks that may be queued for chain processing */
#define SENSOR_SSSS_NUM_DATA_BLOCKS (SENSOR_SSSS_MAX_DATA_BLOCKS)
/** maximum number of vertical (parallel processing elements) that may generate datablock outputs
* that may add to the front of the queue.
*
* Queue size of a given datablock processor must be atleast
* summation of maximum datablocks of all sensors registered for
* processing with some room to handle the vertical depth
*/
#define MAX_THREAD_VERTICAL_DEPTH_DATA_BLOCKS (5)
#define SENSOR_SSSS_DBP_THREAD_Q_SIZE (SENSOR_SSSS_MAX_DATA_BLOCKS+MAX_THREAD_VERTICAL_DEPTH_DATA_BLOCKS)
#define SENSOR_SSSS_DBP_THREAD_PRIORITY (10)
uint8_t sensor_ssss_data_blocks[SENSOR_SSSS_MEMSIZE_MAX] ; //PLACE_IN_SECTION("HWA");
QAI_DataBlockMgr_t sensor_ssssBuffDataBlkMgr;
QueueHandle_t sensor_ssss_dbp_thread_q;
/* SSSS AI processing element */
extern void sensor_ssss_ai_data_processor(
QAI_DataBlock_t *pIn,
QAI_DataBlock_t *pOut,
QAI_DataBlock_t **pRet,
datablk_pe_event_notifier_t *pevent_notifier
);
extern void sensor_ssss_ai_config(void *pDatablockManagerPtr);
extern int sensor_ssss_ai_start(void);
extern int sensor_ssss_ai_stop(void);
/** Sensor SSSS AI processing element functions */
datablk_pe_funcs_t sensor_ssss_sensiml_ai_funcs =
{
.pconfig = sensor_ssss_ai_config,
.pprocess = sensor_ssss_ai_data_processor,
.pstart = sensor_ssss_ai_start,
.pstop = sensor_ssss_ai_stop,
.p_pe_object = (void *)NULL
} ;
/** outQ processor for SSSS AI processing element */
outQ_processor_t sensor_ssss_sensiml_ai_outq_processor =
{
.process_func = NULL,
.p_dbm = &sensor_ssssBuffDataBlkMgr,
.in_pid = SENSOR_SSSS_AI_PID,
.outQ_num = 0,
.outQ = NULL,
.p_event_notifier = NULL
};
/* SSSS Live-stream processing element */
extern void sensor_ssss_livestream_data_processor(
QAI_DataBlock_t *pIn,
QAI_DataBlock_t *pOut,
QAI_DataBlock_t **pRet,
datablk_pe_event_notifier_t *pevent_notifier
);
extern void sensor_ssss_livestream_config(void *pDatablockManagerPtr);
extern int sensor_ssss_livestream_start(void);
extern int sensor_ssss_livestream_stop(void);
/** Sensor SSSS AI processing element functions */
datablk_pe_funcs_t sensor_ssss_livestream_funcs =
{
.pconfig = sensor_ssss_livestream_config,
.pprocess = sensor_ssss_livestream_data_processor,
.pstart = sensor_ssss_livestream_start,
.pstop = sensor_ssss_livestream_stop,
.p_pe_object = (void *)NULL
} ;
/** outQ processor for SSSS Live-stream processing element */
outQ_processor_t sensor_ssss_livestream_outq_processor =
{
.process_func = NULL,
.p_dbm = &sensor_ssssBuffDataBlkMgr,
.in_pid = SENSOR_SSSS_LIVESTREAM_PID,
.outQ_num = 0,
.outQ = NULL,
.p_event_notifier = NULL
};
/* SSSS datasave processing element */
extern void sensor_ssss_datasave_data_processor(
QAI_DataBlock_t *pIn,
QAI_DataBlock_t *pOut,
QAI_DataBlock_t **pRet,
datablk_pe_event_notifier_t *pevent_notifier
);
extern void sensor_ssss_datasave_config(void *pDatablockManagerPtr);
extern int sensor_ssss_datasave_start(void);
extern int sensor_ssss_datasave_stop(void);
/** Sensor SSSS datasave processing element functions */
datablk_pe_funcs_t sensor_ssss_datasave_funcs =
{
.pconfig = sensor_ssss_datasave_config,
.pprocess = sensor_ssss_datasave_data_processor,
.pstart = sensor_ssss_datasave_start,
.pstop = sensor_ssss_datasave_stop,
.p_pe_object = (void *)NULL
} ;
/** outQ processor for SSSS datasave processing element */
outQ_processor_t sensor_ssss_datasave_outq_processor =
{
.process_func = NULL,
.p_dbm = &sensor_ssssBuffDataBlkMgr,
.in_pid = SENSOR_SSSS_LIVESTREAM_PID,
.outQ_num = 0,
.outQ = NULL,
.p_event_notifier = NULL
};
datablk_pe_descriptor_t sensor_ssss_datablk_pe_descr[] =
{ // { IN_ID, OUT_ID, ACTIVE, fSupplyOut, fReleaseIn, outQ, &pe_function_pointers, bypass_function, pe_semaphore }
#if (SENSOR_SSSS_RECOG_ENABLED)
/* processing element descriptor for SensiML AI for SSSS sensor */
{ SENSOR_SSSS_ISR_PID, SENSOR_SSSS_AI_PID, true, false, true, &sensor_ssss_sensiml_ai_outq_processor, &sensor_ssss_sensiml_ai_funcs, NULL, NULL},
#endif
#if (SENSOR_SSSS_LIVESTREAM_ENABLED)
/* processing element descriptor for SSSS sensor livestream */
{ SENSOR_SSSS_ISR_PID, SENSOR_SSSS_LIVESTREAM_PID, true, false, true, &sensor_ssss_livestream_outq_processor, &sensor_ssss_livestream_funcs, NULL, NULL},
#endif
#if (SENSOR_SSSS_DATASAVE_ENABLED)
/* processing element descriptor for SSSS sensor datasave */
{ SENSOR_SSSS_ISR_PID, SENSOR_SSSS_DATASAVE_PID, true, false, true, &sensor_ssss_datasave_outq_processor, &sensor_ssss_datasave_funcs, NULL, NULL},
#endif
};
datablk_processor_params_t sensor_ssss_datablk_processor_params[] = {
{ SENSOR_SSSS_DBP_THREAD_PRIORITY,
&sensor_ssss_dbp_thread_q,
sizeof(sensor_ssss_datablk_pe_descr)/sizeof(sensor_ssss_datablk_pe_descr[0]),
sensor_ssss_datablk_pe_descr,
256*2,
(char*)"SENSOR_SSSS_DBP_THREAD",
NULL
}
};
void sensor_ssss_block_processor(void)
{
/* Initialize datablock manager */
datablk_mgr_init( &sensor_ssssBuffDataBlkMgr,
sensor_ssss_data_blocks,
sizeof(sensor_ssss_data_blocks),
(SENSOR_SSSS_SAMPLES_PER_BLOCK),
((SENSOR_SSSS_BIT_DEPTH)/8)
);
/** SSSS datablock processor thread : Create SSSS Queues */
sensor_ssss_dbp_thread_q = xQueueCreate(SENSOR_SSSS_DBP_THREAD_Q_SIZE, sizeof(QAI_DataBlock_t *));
vQueueAddToRegistry( sensor_ssss_dbp_thread_q, "SENSOR_SSSSPipelineExampleQ" );
/** SSSS datablock processor thread : Setup SSSS Thread Handler Processing Elements */
datablk_processor_task_setup(&sensor_ssss_datablk_processor_params[0]);
/** Set the first data block for the ISR or callback function */
sensor_ssss_set_first_data_block();
/* [TBD]: sensor configuration : should this be here or after scheduler starts? */
sensor_ssss_add();
sensor_ssss_configure();
#if 0
printf("Sensor Name: %s\n", "SENSOR_SSSS_NAME");
printf("Sensor Memory: %d\n", (int)SENSOR_SSSS_MEMSIZE_MAX);
printf("Sensor Sampling rate: %d Hz\n", (int)SENSOR_SSSS_SAMPLE_RATE_HZ);
printf("Sensor Number of channels: %d\n", (int)SENSOR_SSSS_CHANNELS_PER_SAMPLE);
printf("Sensor frame size per channel: %d\n", (int)SENSOR_SSSS_SAMPLES_PER_CHANNEL);
printf("Sensor frame size: %d\n", (int)SENSOR_SSSS_SAMPLES_PER_BLOCK);
printf("Sensor sample bit-depth: %d\n", (int)SENSOR_SSSS_BIT_DEPTH);
printf("Sensor datablock count: %d\n", (int)SENSOR_SSSS_NUM_DATA_BLOCKS);
#endif
}
/*========== END: SSSS SENSOR Datablock processor definitions =============*/
/* BEGIN timer task related functions */
TimerHandle_t sensor_ssss_TimId ;
extern "C" void sensor_ssss_dataTimer_Callback(TimerHandle_t hdl);
void sensor_ssss_dataTimer_Callback(TimerHandle_t hdl)
{
// Warning: must not call vTaskDelay(), vTaskDelayUntil(), or specify a non zero
// block time when accessing a queue or a semaphore.
sensor_ssss_acquisition_read_callback(); //osSemaphoreRelease(readDataSem_id);
}
void sensor_ssss_dataTimerStart(void)
{
BaseType_t status;
TimerCallbackFunction_t xCallback = sensor_ssss_dataTimer_Callback;
#if (USE_SENSOR_SSSS_FIFO_MODE)
// setup FIFO mode
#else
int milli_secs = (1000 / SENSOR_SSSS_SAMPLE_RATE_HZ); // reads when a sample is available (upto 416Hz)
#endif
// Create periodic timer
if (!sensor_ssss_TimId) {
sensor_ssss_TimId = xTimerCreate("SensorSSSSTimer", pdMS_TO_TICKS(milli_secs), pdTRUE, (void *)0, xCallback);
configASSERT(sensor_ssss_TimId != NULL);
}
if (sensor_ssss_TimId) {
status = xTimerStart (sensor_ssss_TimId, 0); // start timer
if (status != pdPASS) {
// Timer could not be started
}
}
#if (USE_SENSOR_SSSS_FIFO_MODE)
// setup FIFO mode
#endif
// start the sensor
}
void sensor_ssss_dataTimerStop(void)
{
if (sensor_ssss_TimId) {
xTimerStop(sensor_ssss_TimId, 0);
}
// stop the sensor
}
/* END timer task related functions */
/* BEGIN Sensor Generic Configuration */
sensor_generic_config_t sensor_ssss_config;
void sensor_ssss_startstop( int is_start )
{
/** @todo Replace contents of this function */
if ((is_start) && (sensor_ssss_config.enabled) && (sensor_ssss_config.is_running == 0) )
{
sensor_ssss_dataTimerStart();
sensor_ssss_config.is_running = 1;
}
else if ( (is_start == 0) && (sensor_ssss_config.is_running == 1) )
{
sensor_ssss_dataTimerStop();
sensor_ssss_config.is_running = 0;
}
}
void sensor_ssss_clear( void )
{
sensor_ssss_config.enabled = false;
/** @todo Replace contents of this function */
}
void sensor_ssss_add(void)
{
sensor_ssss_config.enabled = true;
/** @todo Replace contents of this function */
}
/* End of Sensor Generic Configuration */
/* BEGIN SSSS Acquisition */
/* Sensor SSSS capture ISR */
#define SENSOR_SSSS_ISR_EVENT_NO_BUFFER (1) ///< error getting a new datablock buffer
#define SSSS_ISR_OUTQS_NUM (1)
QueueHandle_t *sensor_ssss_isr_outQs[SSSS_ISR_OUTQS_NUM] = { &sensor_ssss_dbp_thread_q };
QAI_DataBlock_t *psensor_ssss_data_block_prev = NULL;
int sensor_ssss_samples_collected = 0;
outQ_processor_t sensor_ssss_isr_outq_processor =
{
.process_func = sensor_ssss_acquisition_read_callback,
.p_dbm = &sensor_ssssBuffDataBlkMgr,
.in_pid = SENSOR_SSSS_ISR_PID,
.outQ_num = 1,
.outQ = sensor_ssss_isr_outQs,
.p_event_notifier = NULL
};
void sensor_ssss_set_first_data_block()
{
/* Acquire a datablock buffer */
if (NULL == psensor_ssss_data_block_prev)
{
datablk_mgr_acquire(sensor_ssss_isr_outq_processor.p_dbm, &psensor_ssss_data_block_prev, 0);
}
configASSERT(psensor_ssss_data_block_prev); // probably indicates uninitialized datablock manager handle
sensor_ssss_samples_collected = 0;
psensor_ssss_data_block_prev->dbHeader.Tstart = xTaskGetTickCount();
}
int sensor_ssss_batch_size_get(void)
{
return (SENSOR_SSSS_SAMPLES_PER_CHANNEL);
}
void sensor_ssss_acquisition_read_callback(void)
{
int gotNewBlock = 0;
QAI_DataBlock_t *pdata_block = NULL;
if (!sensor_ssss_acquisition_buffer_ready())
{
return;
}
/* Acquire a new data block buffer */
datablk_mgr_acquire(sensor_ssss_isr_outq_processor.p_dbm, &pdata_block, 0);
if (pdata_block)
{
gotNewBlock = 1;
}
else
{
// send error message
// xQueueSendFromISR( error_queue, ... )
if (sensor_ssss_isr_outq_processor.p_event_notifier)
(*sensor_ssss_isr_outq_processor.p_event_notifier)(sensor_ssss_isr_outq_processor.in_pid, SENSOR_SSSS_ISR_EVENT_NO_BUFFER, NULL, 0);
pdata_block = psensor_ssss_data_block_prev;
pdata_block->dbHeader.Tstart = xTaskGetTickCount();
pdata_block->dbHeader.numDropCount++;
}
if (gotNewBlock)
{
/* send the previously filled ssss data to specified output Queues */
psensor_ssss_data_block_prev->dbHeader.Tend = pdata_block->dbHeader.Tstart;
datablk_mgr_WriteDataBufferToQueues(&sensor_ssss_isr_outq_processor, NULL, psensor_ssss_data_block_prev);
psensor_ssss_data_block_prev = pdata_block;
}
}
/* END SSSS Acquisition */
/* SSSS AI processing element functions */
void sensor_ssss_ai_data_processor(
QAI_DataBlock_t *pIn,
QAI_DataBlock_t *pOut,
QAI_DataBlock_t **pRet,
datablk_pe_event_notifier_t *pevent_notifier
)
{
int16_t *p_data = (int16_t *) ( (uint8_t *)pIn + offsetof(QAI_DataBlock_t, p_data) );
// Invoke the SensiML recognition API
int nSamples = pIn->dbHeader.numDataElements;
int nChannels = pIn->dbHeader.numDataChannels;
set_recognition_current_block_time();
int batch_sz = nSamples / nChannels;
int classification = sml_recognition_run_batch(p_data, batch_sz, nChannels, sensor_ssss_config.sensor_id);
*pRet = NULL;
return;
}
void sensor_ssss_ai_config(void *pobj)
{
}
int sensor_ssss_ai_start(void)
{
return 0;
}
int sensor_ssss_ai_stop(void)
{
return 0;
}
void sensor_ssss_event_notifier(int pid, int event_type, void *p_event_data, int num_data_bytes)
{
char *p_data = (char *)p_event_data;
printf("[SSSS Event] PID=%d, event_type=%d, data=%02x\n", pid, event_type, p_data[0]);
}
#if (SENSOR_COMMS_KNOWN_PATTERN == 1)
int16_t sensor_ssss_debug_buffer[240]; // Buffer intended to send a known pattern such as sawtooth
int16_t sensor_ssss_debug_data = 0; // state for holding current data for the known pattern
#endif
/* SSSS livestream processing element functions */
void sensor_ssss_livestream_data_processor(
QAI_DataBlock_t *pIn,
QAI_DataBlock_t *pOut,
QAI_DataBlock_t **pRet,
datablk_pe_event_notifier_t *pevent_notifier
)
{
int16_t *p_data = (int16_t *) ( (uint8_t *)pIn + offsetof(QAI_DataBlock_t, p_data) );
//struct sensor_data sdi;
uint64_t time_start, time_curr, time_end, time_incr;
if (sensor_ssss_config.enabled == true)
{
// Live-stream data to the host
uint8_t *p_source = pIn->p_data ;
int ilen = pIn->dbHeader.numDataElements * pIn->dbHeader.dataElementSize ;
#if (SENSOR_SSSS_RATE_DEBUG_GPIO == 1)
// Toggle GPIO to indicate that a new datablock buffer is dispatched to UART
// for transmission for data collection
HAL_GPIO_Write(GPIO_2, sensor_rate_debug_gpio_val);
sensor_rate_debug_gpio_val ^= 1;
#endif
#if (SENSOR_COMMS_KNOWN_PATTERN == 1)
int nSamples = pIn->dbHeader.numDataElements;
int nChannels = pIn->dbHeader.numDataChannels;
// prepare the sawtooth known pattern data
for (int k = 0; k < nSamples; k+=nChannels)
{
for (int l = 0; l < nChannels; l++)
sensor_ssss_debug_buffer[k+l] = sensor_ssss_debug_data;
sensor_ssss_debug_data++;
}
memcpy (pIn->p_data, sensor_ssss_debug_buffer, nSamples * sizeof(int16_t));
#endif
ssi_publish_sensor_data(p_source, ilen);
}
*pRet = NULL;
return;
}
void sensor_ssss_livestream_config(void *pobj)
{
}
int sensor_ssss_livestream_start(void)
{
return 0;
}
int sensor_ssss_livestream_stop(void)
{
return 0;
}
void sensor_ssss_datasave_data_processor(
QAI_DataBlock_t *pIn,
QAI_DataBlock_t *pOut,
QAI_DataBlock_t **pRet,
datablk_pe_event_notifier_t *pevent_notifier
)
{
int16_t *p_data = (int16_t *) ( (uint8_t *)pIn + offsetof(QAI_DataBlock_t, p_data) );
//struct sensor_data sdi;
uint64_t time_start, time_curr, time_end, time_incr;
if (sensor_ssss_config.enabled == true)
{
// Live-stream data to the host
uint8_t *p_source = pIn->p_data ;
int ilen = pIn->dbHeader.numDataElements * pIn->dbHeader.dataElementSize ;
/* Save data to the */
struct sensor_data Info, *pInfo = &Info;
pInfo->bytes_per_reading = pIn->dbHeader.dataElementSize;
pInfo->n_bytes = ilen;
pInfo->rate_hz = sensor_ssss_config.rate_hz;
pInfo->sensor_id = sensor_ssss_config.sensor_id;
pInfo->time_end = convert_to_uSecCount(pIn->dbHeader.Tend);
pInfo->time_start = convert_to_uSecCount(pIn->dbHeader.Tstart);
pInfo->vpData = p_source;
data_save((const struct sensor_data *)pInfo);
}
*pRet = NULL;
return;
}
void sensor_ssss_datasave_config(void *pobj)
{
}
int sensor_ssss_datasave_start(void)
{
return 0;
}
int sensor_ssss_datasave_stop(void)
{
return 0;
}
Comments