aconno acnsensa project for iOS devices with iBeacon packets support.
Dependencies: LSM9DS1 Si7006A20 aconno_SEGGER_RTT aconno_bsp adc52832_common
main.cpp
- Committer:
- jurica238814
- Date:
- 2018-08-06
- Revision:
- 28:1a2c30eb745c
- Parent:
- 27:67467a7a56b3
- Child:
- 32:168317e16c69
File content as of revision 28:1a2c30eb745c:
/* * aconno.de * Made by Jurica Resetar * Edited by Karlo Milicevic * Edited by Dominik Bartolovic * All right reserved * */ #include "mbed.h" #include "ble/BLE.h" #include "acd52832_bsp.h" #include "GapAdvertisingData.h" #include "Si7006A20.h" #include "LSM9DS1.h" #include "math.h" #include "nrf52_digital.h" #include "adc52832_common/utilities.h" #include "MPL115A1.h" #include "acd_nrf52_saadc.h" #include "service.h" #include <events/mbed_events.h> #include "aconnoConfig.h" #define V0 0.47 /* In volts */ #define TC 0.01 /* In volts */ #define VCC (3.6) #define VALUE_TO_PERCENTAGE (100) #define WAKEUP_TIME_DELAY_MS (150) #define APPLICATION_ID (0xCF170059) #define ADC_REFERENCE (3.6f) /* adc reference voltage */ #define ADC_RESOLUTION (1024) /* 10-bit adc */ #define I2C_DATA (p19) #define I2C_CLK (p20) #define SPI_MISO (p5) #define SPI_MOSI (p3) #define SPI_SCLK (p4) #define DEBUG (0) #define DEBUG_PRINT (1) #define SLEEP_TIME (0.150) /* Sleep time in seconds */ #define WAKE_UP_TIME (0.150) /* Awake time in ms */ #define ADV_INTERVAL (100) /* Advertising interval in ms */ #define GO_TO_SLEEP (0) /* Sleep flag: 0 -> Device will not go to sleep, 1 -> Will go to sleep mode */ #define CALIBRATION_STEPS (20) #define TX_POWER_DB (4) #define INVERT_AXES (1) uint8_t gConnected = 0; static NRF52_SAADC analogIn; static NRF52_DigitalOut lightPower(p28); static NRF52_DigitalOut temperaturePower(p31); static NRF52_DigitalOut shdn(p6); static NRF52_DigitalOut power(p2); static NRF52_DigitalOut cs(p7); static Si7006 *si; static LSM9DS1 *mems; static SPI *spi; static MPL115A1 *mpl115a1; static EventQueue eventQueue(32 * EVENTS_EVENT_SIZE); uint8_t myMacAddress[6] = {}; MACService *macServicePtr; #if DEBUG_PRINT #include "SEGGER_RTT.h" #define printf(...) SEGGER_RTT_printf(0, __VA_ARGS__) #else #define printf(...) #endif static vector3_s memsAccelerometerInit; static vector3_s memsGyroscopeInit; static vector3_s memsMagnetometerInit; static GapAdvertisingData adv_data = GapAdvertisingData(); struct __attribute__((packed, aligned(1))) iBeaconMSD_t { // AppleID is constant uint16_t appleID; // secondID is constant uint8_t secondID; // DataSize is constant uint8_t dataSize; uint8_t UUID[16]; uint16_t major; uint16_t minor; int8_t RSSI; }static iBeaconMSD = {.appleID = 0x004C, .secondID = 0x02, .dataSize = 0x15, .UUID = {UUID_INIT}, .major = MAJOR, .minor = MINOR, .RSSI = RSSI_INIT}; struct __attribute__((packed, aligned(1))) advertising_packet { uint32_t header; uint8_t type; union{ struct{ int16_t gyroscope[3]; int16_t accelerometer[3]; int16_t magnetometer[3]; uint16_t acc_lsb_value; }; struct{ float temperature; float humidity; float pressure; float light; uint8_t battery; }; }; }; void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) { BLE &ble = context->ble; eventQueue.call(Callback<void()>(&ble, &BLE::processEvents)); } static advertising_packet advertisementPacket; void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) { // Restart Advertising on disconnection gConnected = 0; BLE::Instance().gap().startAdvertising(); } void onConnectionCallback(const Gap::ConnectionCallbackParams_t *params) { printf("Connection callback.\n"); gConnected = 1; } /** * Callback triggered when the ble initialization process has finished */ void bleInitCompleteSensors(BLE::InitializationCompleteCallbackContext *params) { BLE& ble = params->ble; ble_error_t error = params->error; if (error != BLE_ERROR_NONE){ return; } /* Ensure that it is the default instance of BLE */ if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE){ return; } uint8_t mac[6] = {0,0,0,0,0,0}; BLEProtocol::AddressType_t temp_address_type; ble.gap().getAddress(&temp_address_type, myMacAddress); macServicePtr = new MACService(ble, mac); macServicePtr->updateMacAddress(myMacAddress); // Update MAC address ble.gap().onConnection(onConnectionCallback); ble.gap().onDisconnection(disconnectionCallback); /* setup advertising */ ble.gap().accumulateAdvertisingPayload( GapAdvertisingData::BREDR_NOT_SUPPORTED); ble.gap().accumulateAdvertisingPayload( GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, (uint8_t *)&advertisementPacket, sizeof(advertisementPacket)); ble.gap().setAdvertisingType( GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); ble.gap().setAdvertisingInterval(ADV_INTERVAL); printf("Init started....\t\t"); ble.gap().setTxPower(TX_POWER_DB); // Set TX power to TX_POWER_DB ble.gap().startAdvertising(); printf("Init done.\n"); } float getLight() { return ((float)analogIn.getData()[1])/ADC_RESOLUTION * VALUE_TO_PERCENTAGE; } float voltage2temp(float vOut) { return ((float)vOut - (float)V0)/((float)TC); } float getTemperature() { return voltage2temp(((float)analogIn.getData()[2])/ADC_RESOLUTION * (float)VCC); } uint8_t getBattery() { uint16_t batteryVoltage = analogIn.getData()[0]; const uint16_t zero_percent_limit = 739; const uint16_t onehundred_percent_limit = 810; const uint16_t percentage_increments = 5; uint8_t percentage; if (batteryVoltage < zero_percent_limit) { percentage = 0; } else if(batteryVoltage > onehundred_percent_limit) { percentage = 100; } else { batteryVoltage -= zero_percent_limit; percentage = (batteryVoltage*100)/(onehundred_percent_limit - zero_percent_limit); percentage = percentage/percentage_increments*percentage_increments; } return percentage; } float getHumidity() { float result; si->getHumidity(&result); return result; } void readGyroscope(vector3_s *gyroscopeData) { mems->readGyroscope((int16_t *)gyroscopeData); *gyroscopeData -= memsGyroscopeInit; } void readAccelerometer(vector3_s *accelerometerData) { mems->readAccelerometer((int16_t *)accelerometerData); *accelerometerData -= memsAccelerometerInit; } void readMagnetometer(vector3_s *magnetometerData){ mems->readMagnetometer((int16_t *)magnetometerData); *magnetometerData -= memsMagnetometerInit; } void calibrateAccelerometer(){ vector3_s accelerometerData; for(uint8_t counter = 0; counter < CALIBRATION_STEPS; ++counter) { readAccelerometer(&accelerometerData); memsAccelerometerInit += accelerometerData; } memsAccelerometerInit /= CALIBRATION_STEPS; } void calibrateGyroscope(){ vector3_s gyroscopeData; for(uint8_t counter = 0; counter < CALIBRATION_STEPS; ++counter) { readGyroscope(&gyroscopeData); memsGyroscopeInit += gyroscopeData; } memsGyroscopeInit /= CALIBRATION_STEPS; } void calibrateMag(){ vector3_s magnetometerData; for(uint8_t counter = 0; counter < CALIBRATION_STEPS; ++counter) { readMagnetometer(&magnetometerData); memsMagnetometerInit += magnetometerData; } memsMagnetometerInit /= CALIBRATION_STEPS; } void updateData(){ static uint8_t advertisementType = 0; int16_t temp_acc[3]; BLE &ble = BLE::Instance(); if(!advertisementType && !gConnected) { printf("Sensor format 1.\n"); ble.gap().clearAdvertisingPayload(); /* setup advertising */ ble.gap().accumulateAdvertisingPayload( GapAdvertisingData::BREDR_NOT_SUPPORTED); ble.gap().accumulateAdvertisingPayload( GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, (uint8_t *)&advertisementPacket, sizeof(advertisementPacket)); ble.gap().setAdvertisingType( GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); adv_data = ble.getAdvertisingData(); advertisementPacket.type = 0x00; readGyroscope((vector3_s *)advertisementPacket.gyroscope); readAccelerometer((vector3_s *)temp_acc); readMagnetometer((vector3_s *)advertisementPacket.magnetometer); advertisementPacket.acc_lsb_value = (0xF9E); // ^--- That's in ug cuz MSB is 1 #if INVERT_AXES advertisementPacket.accelerometer[0] = temp_acc[1]; advertisementPacket.accelerometer[1] = temp_acc[0]; advertisementPacket.accelerometer[2] = temp_acc[2]; #endif adv_data.updateData(adv_data.MANUFACTURER_SPECIFIC_DATA, (uint8_t *)&advertisementPacket, sizeof(advertisementPacket)); ble.setAdvertisingData(adv_data); } else if (advertisementType == 1 && !gConnected) { printf("Sensor format 2.\n"); analogIn.updateData(); adv_data = ble.getAdvertisingData(); advertisementPacket.type = 0x01; advertisementPacket.temperature = getTemperature(); advertisementPacket.light = getLight(); advertisementPacket.humidity = getHumidity(); advertisementPacket.pressure = mpl115a1->getPressure(); advertisementPacket.battery = getBattery(); adv_data.updateData(adv_data.MANUFACTURER_SPECIFIC_DATA, (uint8_t *)&advertisementPacket, sizeof(advertisementPacket)); ble.setAdvertisingData(adv_data); } else if (!gConnected) { printf("Beacon format!\n"); ble.gap().clearAdvertisingPayload(); ble.gap().accumulateAdvertisingPayload( GapAdvertisingData::BREDR_NOT_SUPPORTED); ble.gap().accumulateAdvertisingPayload( GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, (uint8_t*)&iBeaconMSD, sizeof(iBeaconMSD_t)); ble.gap().startAdvertising(); } if(++advertisementType > 2) advertisementType = 0; } int main() { printf("Main started.\n"); Thread bleT; power = 1; wait_ms(WAKEUP_TIME_DELAY_MS); temperaturePower = 1; lightPower = 1; shdn = 1; // Wake up the pressure sensor analogIn.addChannel(9); // Set VDD as source to SAADC analogIn.addChannel(6); // Light analogIn.addChannel(7); // Temp analogIn.calibrate(); BLE &ble = BLE::Instance(); ble.init(bleInitCompleteSensors); while(ble.hasInitialized() == false){ /* spin loop */ } ble.onEventsToProcess(scheduleBleEventsProcessing); advertisementPacket.header = APPLICATION_ID; I2C i2c(I2C_DATA, I2C_CLK); si = new Si7006(&i2c); mems = new LSM9DS1(&i2c); spi = new SPI(SPI_MOSI, SPI_MISO, SPI_SCLK); mpl115a1 = new MPL115A1(*spi, cs); mems->startAccelerometer(); mems->startGyroscope(); mems->startMagnetometer(); eventQueue.call_every(100, updateData); // This call stops main thread eventQueue.dispatch_forever(); }