Combines a working system to save force, acceleration and gyro data to an SD card in a MAX32630 with BLE_Heartrate taken from the mbed site.
Dependencies: USBMSD_BD BMI160 HX711 max32630fthr USBDevice
source/main.cpp@83:b67e4bb6a087, 2020-06-04 (annotated)
- Committer:
- qaz
- Date:
- Thu Jun 04 10:32:19 2020 +0000
- Revision:
- 83:b67e4bb6a087
- Parent:
- 82:f01379c0f435
Publishing
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
qaz | 81:b8ef2a762318 | 1 | /* BlueCrutch. mbed Microcontroller Library yada */ |
qaz | 81:b8ef2a762318 | 2 | // Cloned from mbed-os-example-ble-HeartRate (after main.cpp was reverted to 14 Dec 2018), because for example where's ble/BLE.h |
qaz | 81:b8ef2a762318 | 3 | // Taking stuff across from Niall's project bit by bit, starting with the includes. |
mbed_official | 10:ac3615194d04 | 4 | #include <events/mbed_events.h> |
mbed_official | 1:72c60abef7e7 | 5 | #include <mbed.h> |
qaz | 81:b8ef2a762318 | 6 | #include "mbed.h" |
mbed_official | 1:72c60abef7e7 | 7 | #include "ble/BLE.h" |
qaz | 80:caccea4da07b | 8 | #include "ble/Gap.h" |
mbed_official | 1:72c60abef7e7 | 9 | #include "ble/services/HeartRateService.h" |
qaz | 81:b8ef2a762318 | 10 | #include "max32630fthr.h" |
qaz | 81:b8ef2a762318 | 11 | #include "HX711.h" |
qaz | 81:b8ef2a762318 | 12 | #include "bmi160.h" |
qaz | 81:b8ef2a762318 | 13 | //#include "SDFileSystem.h" // Error: Class "FATFileSystem" has no member "_ffs" in "SDFileSystem/FATFileSystem/ChaN/diskio.cpp", Line: 25, Col: 37. Compile error fixed by removing the SDFileSystem library from BlueCrutch. Compile was immediately successful. 24/10/19 |
qaz | 81:b8ef2a762318 | 14 | // I have another SD card library, under FTHR_USBMSD_BD, which at least compiled - 24/10/19 |
qaz | 81:b8ef2a762318 | 15 | #include "SDBlockDevice.h" |
qaz | 81:b8ef2a762318 | 16 | #include "USBMSD_BD.h" |
qaz | 81:b8ef2a762318 | 17 | #include "FATFileSystem.h" // Put in, aping what was in the FTHDR_USBMSD_BD example |
mbed_official | 1:72c60abef7e7 | 18 | |
qaz | 82:f01379c0f435 | 19 | Thread ble_thread; |
qaz | 82:f01379c0f435 | 20 | |
qaz | 80:caccea4da07b | 21 | DigitalOut led1(LED1, 1); |
mbed_official | 1:72c60abef7e7 | 22 | |
qaz | 80:caccea4da07b | 23 | const static char DEVICE_NAME[] = "HRM"; |
qaz | 80:caccea4da07b | 24 | static const uint16_t uuid16_list[] = {GattService::UUID_HEART_RATE_SERVICE}; |
qaz | 80:caccea4da07b | 25 | |
qaz | 80:caccea4da07b | 26 | static uint8_t hrmCounter = 100; // init HRM to 100bps |
qaz | 80:caccea4da07b | 27 | static HeartRateService *hrServicePtr; |
qaz | 80:caccea4da07b | 28 | |
qaz | 80:caccea4da07b | 29 | static EventQueue eventQueue(/* event count */ 16 * EVENTS_EVENT_SIZE); |
mbed_official | 1:72c60abef7e7 | 30 | |
qaz | 81:b8ef2a762318 | 31 | /* These are all the initializations from the crutch project - about the next 50 lines */ |
qaz | 81:b8ef2a762318 | 32 | void dumpImuRegisters(BMI160 &imu); |
qaz | 81:b8ef2a762318 | 33 | void printRegister(BMI160 &imu, BMI160::Registers reg); |
qaz | 81:b8ef2a762318 | 34 | void printBlock(BMI160 &imu, BMI160::Registers startReg, BMI160::Registers stopReg); |
qaz | 81:b8ef2a762318 | 35 | MAX32630FTHR pegasus(MAX32630FTHR::VIO_3V3); |
qaz | 81:b8ef2a762318 | 36 | |
qaz | 81:b8ef2a762318 | 37 | InterruptIn button(P2_3); |
qaz | 81:b8ef2a762318 | 38 | DigitalOut rLED(LED1, LED_OFF); |
qaz | 81:b8ef2a762318 | 39 | DigitalOut gLED(LED2, LED_OFF); |
qaz | 81:b8ef2a762318 | 40 | DigitalOut bLED(LED3, LED_OFF); |
qaz | 81:b8ef2a762318 | 41 | void button_callback(void); |
qaz | 81:b8ef2a762318 | 42 | |
qaz | 81:b8ef2a762318 | 43 | I2C i2cBus(P5_7, P6_0); |
qaz | 81:b8ef2a762318 | 44 | |
qaz | 81:b8ef2a762318 | 45 | BMI160_I2C imu(i2cBus, BMI160_I2C::I2C_ADRS_SDO_LO); |
qaz | 81:b8ef2a762318 | 46 | BMI160::SensorData accData; |
qaz | 81:b8ef2a762318 | 47 | BMI160::SensorData gyroData; |
qaz | 81:b8ef2a762318 | 48 | BMI160::SensorTime sensorTime; |
qaz | 81:b8ef2a762318 | 49 | BMI160::SensorTime startTime; |
qaz | 81:b8ef2a762318 | 50 | float imuTemperature; |
qaz | 81:b8ef2a762318 | 51 | |
qaz | 81:b8ef2a762318 | 52 | BMI160::AccConfig accConfig; |
qaz | 81:b8ef2a762318 | 53 | BMI160::GyroConfig gyroConfig; |
qaz | 81:b8ef2a762318 | 54 | |
qaz | 81:b8ef2a762318 | 55 | //SDFileSystem sd(P0_5, P0_6, P0_4, P0_7, "sd"); // mosi, miso, sclk, cs |
qaz | 81:b8ef2a762318 | 56 | // SDFileSystem sd(P0_5, P0_6, P0_4, P0_7, "sd", P2_2, SDFileSystem::SWITCH_NEG_NO, 400000); // Had to comment this out because the SDFileSystem library gave compile time errors in BlueCrutch |
qaz | 81:b8ef2a762318 | 57 | // Trying this as a replacement: |
qaz | 81:b8ef2a762318 | 58 | // Physical block device, can be any device that supports the BlockDevice API |
qaz | 81:b8ef2a762318 | 59 | // HeapBlockDevice bd(512*BLOCK_SIZE, BLOCK_SIZE); |
qaz | 81:b8ef2a762318 | 60 | SDBlockDevice bd(P0_5, P0_6, P0_4, P0_7); // Compiled into the program 24/10/19, so success to that extent at least. |
qaz | 81:b8ef2a762318 | 61 | FATFileSystem fs("fs"); // File system declaration |
qaz | 81:b8ef2a762318 | 62 | USBMSD_BD msd(&bd); // USB MSD |
qaz | 81:b8ef2a762318 | 63 | |
qaz | 82:f01379c0f435 | 64 | //DigitalIn sd_detect(P2_2); |
qaz | 81:b8ef2a762318 | 65 | |
qaz | 81:b8ef2a762318 | 66 | Serial pc(USBTX, USBRX); // USB Serial Terminal |
qaz | 81:b8ef2a762318 | 67 | int calibration_factor = 9500; //-7050 worked for my 440lb max scale setup |
qaz | 81:b8ef2a762318 | 68 | int epoch_time = 1570547100; // 1570547100 = 3:05 on 08/10/19. Will be overwritten |
qaz | 81:b8ef2a762318 | 69 | float zero_factor = 2.0781, weight; |
qaz | 81:b8ef2a762318 | 70 | int averageSamples = 100; |
qaz | 81:b8ef2a762318 | 71 | int seconds_to_blink_if_sd_mount_fails = 5; |
qaz | 81:b8ef2a762318 | 72 | char epoch_string[11]; |
qaz | 81:b8ef2a762318 | 73 | char topline[200]; |
qaz | 81:b8ef2a762318 | 74 | HX711 scale(P3_4, P3_5); |
qaz | 81:b8ef2a762318 | 75 | unsigned char button_pressed=0; |
qaz | 82:f01379c0f435 | 76 | bool waittimeexpired=false, debugging=false, ble_call, blecallcontinuously /* Idea is to return BLE operation to original if true */= false; |
qaz | 81:b8ef2a762318 | 77 | Ticker tick; |
qaz | 81:b8ef2a762318 | 78 | |
qaz | 81:b8ef2a762318 | 79 | void tick_timer() { |
qaz | 81:b8ef2a762318 | 80 | waittimeexpired = true; |
qaz | 81:b8ef2a762318 | 81 | //pc.putc('x'); |
qaz | 81:b8ef2a762318 | 82 | } |
qaz | 81:b8ef2a762318 | 83 | /* End of the initializations from the crutch project */ |
qaz | 81:b8ef2a762318 | 84 | |
qaz | 80:caccea4da07b | 85 | void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) |
qaz | 80:caccea4da07b | 86 | { |
qaz | 80:caccea4da07b | 87 | BLE::Instance().gap().startAdvertising(); // restart advertising |
qaz | 80:caccea4da07b | 88 | } |
mbed_official | 1:72c60abef7e7 | 89 | |
qaz | 80:caccea4da07b | 90 | void updateSensorValue() { |
qaz | 80:caccea4da07b | 91 | // Do blocking calls or whatever is necessary for sensor polling. |
qaz | 80:caccea4da07b | 92 | // In our case, we simply update the HRM measurement. |
qaz | 80:caccea4da07b | 93 | hrmCounter++; |
mbed_official | 1:72c60abef7e7 | 94 | |
qaz | 80:caccea4da07b | 95 | // 100 <= HRM bps <=175 |
qaz | 80:caccea4da07b | 96 | if (hrmCounter == 175) { |
qaz | 80:caccea4da07b | 97 | hrmCounter = 100; |
mbed_official | 1:72c60abef7e7 | 98 | } |
mbed_official | 1:72c60abef7e7 | 99 | |
qaz | 80:caccea4da07b | 100 | hrServicePtr->updateHeartRate(hrmCounter); |
qaz | 80:caccea4da07b | 101 | } |
mbed_official | 1:72c60abef7e7 | 102 | |
qaz | 82:f01379c0f435 | 103 | void periodicCallback(void) { |
qaz | 82:f01379c0f435 | 104 | if ((ble_call) || (blecallcontinuously)) { |
qaz | 83:b67e4bb6a087 | 105 | led1 = /* !led1 */ LED_OFF; /* Do blinky on LED1 while we're waiting for BLE events. It's set to LED_OFF at the moment (24/10/19) because the BLE blinking can get in the way of the lights for writing data, no SD card inserted and calibration and BLE is not yet doing anything useful */ |
mbed_official | 1:72c60abef7e7 | 106 | |
qaz | 82:f01379c0f435 | 107 | if (BLE::Instance().getGapState().connected) { |
qaz | 82:f01379c0f435 | 108 | eventQueue.call(updateSensorValue); |
qaz | 82:f01379c0f435 | 109 | } |
qaz | 82:f01379c0f435 | 110 | } else { |
qaz | 82:f01379c0f435 | 111 | led1 = LED_OFF; // Don't leave the lights on |
qaz | 80:caccea4da07b | 112 | } |
qaz | 80:caccea4da07b | 113 | } |
mbed_official | 1:72c60abef7e7 | 114 | |
qaz | 80:caccea4da07b | 115 | void onBleInitError(BLE &ble, ble_error_t error) |
qaz | 80:caccea4da07b | 116 | { |
qaz | 80:caccea4da07b | 117 | (void)ble; |
qaz | 80:caccea4da07b | 118 | (void)error; |
qaz | 80:caccea4da07b | 119 | /* Initialization error handling should go here */ |
qaz | 80:caccea4da07b | 120 | } |
mbed_official | 1:72c60abef7e7 | 121 | |
qaz | 80:caccea4da07b | 122 | void printMacAddress() |
qaz | 80:caccea4da07b | 123 | { |
qaz | 80:caccea4da07b | 124 | /* Print out device MAC address to the console*/ |
qaz | 80:caccea4da07b | 125 | Gap::AddressType_t addr_type; |
qaz | 80:caccea4da07b | 126 | Gap::Address_t address; |
qaz | 80:caccea4da07b | 127 | BLE::Instance().gap().getAddress(&addr_type, address); |
qaz | 80:caccea4da07b | 128 | printf("DEVICE MAC ADDRESS: "); |
qaz | 80:caccea4da07b | 129 | for (int i = 5; i >= 1; i--){ |
qaz | 80:caccea4da07b | 130 | printf("%02x:", address[i]); |
qaz | 80:caccea4da07b | 131 | } |
qaz | 80:caccea4da07b | 132 | printf("%02x\r\n", address[0]); |
qaz | 80:caccea4da07b | 133 | } |
mbed_official | 43:fb2855f7754b | 134 | |
qaz | 80:caccea4da07b | 135 | void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) |
qaz | 80:caccea4da07b | 136 | { |
qaz | 80:caccea4da07b | 137 | BLE& ble = params->ble; |
qaz | 80:caccea4da07b | 138 | ble_error_t error = params->error; |
mbed_official | 1:72c60abef7e7 | 139 | |
qaz | 80:caccea4da07b | 140 | if (error != BLE_ERROR_NONE) { |
qaz | 80:caccea4da07b | 141 | onBleInitError(ble, error); |
qaz | 80:caccea4da07b | 142 | return; |
mbed_official | 1:72c60abef7e7 | 143 | } |
mbed_official | 1:72c60abef7e7 | 144 | |
qaz | 80:caccea4da07b | 145 | if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) { |
qaz | 80:caccea4da07b | 146 | return; |
mbed_official | 1:72c60abef7e7 | 147 | } |
mbed_official | 1:72c60abef7e7 | 148 | |
qaz | 80:caccea4da07b | 149 | ble.gap().onDisconnection(disconnectionCallback); |
mbed_official | 1:72c60abef7e7 | 150 | |
qaz | 80:caccea4da07b | 151 | /* Setup primary service. */ |
qaz | 80:caccea4da07b | 152 | hrServicePtr = new HeartRateService(ble, hrmCounter, HeartRateService::LOCATION_FINGER); |
mbed_official | 1:72c60abef7e7 | 153 | |
qaz | 81:b8ef2a762318 | 154 | /* Setting up GAP mostly has to do with configuring connectability and the payload contained in the advertisement packets.*/ |
qaz | 80:caccea4da07b | 155 | /* Setup advertising. */ |
qaz | 80:caccea4da07b | 156 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); |
qaz | 80:caccea4da07b | 157 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); |
qaz | 80:caccea4da07b | 158 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR); |
qaz | 80:caccea4da07b | 159 | ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); |
qaz | 80:caccea4da07b | 160 | ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); |
qaz | 80:caccea4da07b | 161 | ble.gap().setAdvertisingInterval(1000); /* 1000ms */ |
qaz | 80:caccea4da07b | 162 | ble.gap().startAdvertising(); |
qaz | 81:b8ef2a762318 | 163 | /* The first line (above) is mandatory for Bluetooth Smart, and says that this device only supports Bluetooth low energy. The 'general discoverable' |
qaz | 81:b8ef2a762318 | 164 | is the typical value to set when you want your device to be seen by other devices in order to connect. Next comes the ID for the heart rate sensor |
qaz | 81:b8ef2a762318 | 165 | service and the name of the device. After the payload is set the code sets the advertising type and the advertising interval. In Bluetooth Smart, |
qaz | 81:b8ef2a762318 | 166 | timing values are typically multiples of 625 us. */ |
qaz | 80:caccea4da07b | 167 | printMacAddress(); |
qaz | 80:caccea4da07b | 168 | } |
mbed_official | 1:72c60abef7e7 | 169 | |
qaz | 80:caccea4da07b | 170 | void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) { |
qaz | 80:caccea4da07b | 171 | BLE &ble = BLE::Instance(); |
qaz | 80:caccea4da07b | 172 | eventQueue.call(Callback<void()>(&ble, &BLE::processEvents)); |
mbed_official | 1:72c60abef7e7 | 173 | } |
mbed_official | 1:72c60abef7e7 | 174 | |
qaz | 82:f01379c0f435 | 175 | void bleheartrate() { |
qaz | 80:caccea4da07b | 176 | eventQueue.call_every(500, periodicCallback); |
qaz | 80:caccea4da07b | 177 | BLE &ble = BLE::Instance(); |
qaz | 80:caccea4da07b | 178 | ble.onEventsToProcess(scheduleBleEventsProcessing); |
qaz | 80:caccea4da07b | 179 | ble.init(bleInitComplete); |
qaz | 82:f01379c0f435 | 180 | eventQueue.dispatch_forever(); // https://os.mbed.com/docs/mbed-os/v5.14/tutorials/the-eventqueue-api.html |
qaz | 82:f01379c0f435 | 181 | // have to do break_dispatch somewhere to stop it. Maybe inside the loop not to have BLE on all the time |
qaz | 82:f01379c0f435 | 182 | } |
qaz | 80:caccea4da07b | 183 | |
qaz | 82:f01379c0f435 | 184 | int main() { |
qaz | 82:f01379c0f435 | 185 | pegasus.init(MAX32630FTHR::VIO_3V3); |
qaz | 82:f01379c0f435 | 186 | ble_thread.start(bleheartrate); // Tried to start and stop this in each iteration with break_dispatch. Now using a semaphore |
qaz | 82:f01379c0f435 | 187 | ble_call = false; |
qaz | 82:f01379c0f435 | 188 | |
qaz | 82:f01379c0f435 | 189 | // set PWRSEQ_REG0.pwr_rtcen_run to 1, PWRSEQ_REG0.pwr_rtcen_slip to 1 |
qaz | 82:f01379c0f435 | 190 | // MXC_PWRSEQ->reg0 |= MXC_F_PWRSEQ_REG0_PWR_RTCEN_RUN | MXC_F_PWRSEQ_REG0_PWR_RTCEN_SLP; // needs mbed-dev, which won't load 10/19 |
qaz | 82:f01379c0f435 | 191 | if (debugging) pc.printf("Starting Main Program Thread ...\n"); |
qaz | 82:f01379c0f435 | 192 | //bLED=LED_ON; // Just to verify program has loaded |
qaz | 82:f01379c0f435 | 193 | //wait(0.5); |
qaz | 82:f01379c0f435 | 194 | //bLED=LED_OFF; |
qaz | 82:f01379c0f435 | 195 | gLED = LED_ON; |
qaz | 82:f01379c0f435 | 196 | rLED = LED_ON; |
qaz | 82:f01379c0f435 | 197 | i2cBus.frequency(400000); |
qaz | 82:f01379c0f435 | 198 | scale.tare(); |
qaz | 82:f01379c0f435 | 199 | scale.setScale(calibration_factor); //Adjust to default calibration factor |
qaz | 82:f01379c0f435 | 200 | |
qaz | 82:f01379c0f435 | 201 | uint32_t failures = 0; |
qaz | 82:f01379c0f435 | 202 | |
qaz | 82:f01379c0f435 | 203 | if(imu.setSensorPowerMode(BMI160::GYRO, BMI160::NORMAL) != BMI160::RTN_NO_ERROR) { |
qaz | 82:f01379c0f435 | 204 | //printf("Failed to set gyroscope power mode\n"); |
qaz | 82:f01379c0f435 | 205 | failures++; |
qaz | 82:f01379c0f435 | 206 | } |
qaz | 82:f01379c0f435 | 207 | wait_ms(100); |
qaz | 82:f01379c0f435 | 208 | |
qaz | 82:f01379c0f435 | 209 | if(imu.setSensorPowerMode(BMI160::ACC, BMI160::NORMAL) != BMI160::RTN_NO_ERROR) { |
qaz | 82:f01379c0f435 | 210 | //printf("Failed to set accelerometer power mode\n"); |
qaz | 82:f01379c0f435 | 211 | failures++; |
qaz | 82:f01379c0f435 | 212 | } |
qaz | 82:f01379c0f435 | 213 | wait_ms(100); |
qaz | 82:f01379c0f435 | 214 | |
qaz | 82:f01379c0f435 | 215 | //example of using getSensorConfig |
qaz | 82:f01379c0f435 | 216 | if(imu.getSensorConfig(accConfig) == BMI160::RTN_NO_ERROR) { |
qaz | 82:f01379c0f435 | 217 | //printf("ACC Range = %d\n", accConfig.range); |
qaz | 82:f01379c0f435 | 218 | //printf("ACC UnderSampling = %d\n", accConfig.us); |
qaz | 82:f01379c0f435 | 219 | //printf("ACC BandWidthParam = %d\n", accConfig.bwp); |
qaz | 82:f01379c0f435 | 220 | //printf("ACC OutputDataRate = %d\n\n", accConfig.odr); |
qaz | 82:f01379c0f435 | 221 | } else { |
qaz | 82:f01379c0f435 | 222 | //printf("Failed to get accelerometer configuration\n"); |
qaz | 82:f01379c0f435 | 223 | failures++; |
qaz | 82:f01379c0f435 | 224 | } |
qaz | 82:f01379c0f435 | 225 | |
qaz | 82:f01379c0f435 | 226 | //example of setting user defined configuration |
qaz | 82:f01379c0f435 | 227 | accConfig.range = BMI160::SENS_4G; |
qaz | 82:f01379c0f435 | 228 | accConfig.us = BMI160::ACC_US_OFF; |
qaz | 82:f01379c0f435 | 229 | accConfig.bwp = BMI160::ACC_BWP_2; |
qaz | 82:f01379c0f435 | 230 | accConfig.odr = BMI160::ACC_ODR_8; |
qaz | 82:f01379c0f435 | 231 | if(imu.setSensorConfig(accConfig) == BMI160::RTN_NO_ERROR) { |
qaz | 82:f01379c0f435 | 232 | //printf("ACC Range = %d\n", accConfig.range); |
qaz | 82:f01379c0f435 | 233 | //printf("ACC UnderSampling = %d\n", accConfig.us); |
qaz | 82:f01379c0f435 | 234 | //printf("ACC BandWidthParam = %d\n", accConfig.bwp); |
qaz | 82:f01379c0f435 | 235 | //printf("ACC OutputDataRate = %d\n\n", accConfig.odr); |
qaz | 82:f01379c0f435 | 236 | } else { |
qaz | 82:f01379c0f435 | 237 | //printf("Failed to set accelerometer configuration\n"); |
qaz | 82:f01379c0f435 | 238 | failures++; |
qaz | 82:f01379c0f435 | 239 | } |
qaz | 82:f01379c0f435 | 240 | |
qaz | 82:f01379c0f435 | 241 | if(imu.getSensorConfig(gyroConfig) == BMI160::RTN_NO_ERROR) { |
qaz | 82:f01379c0f435 | 242 | //printf("GYRO Range = %d\n", gyroConfig.range); |
qaz | 82:f01379c0f435 | 243 | //printf("GYRO BandWidthParam = %d\n", gyroConfig.bwp); |
qaz | 82:f01379c0f435 | 244 | //printf("GYRO OutputDataRate = %d\n\n", gyroConfig.odr); |
qaz | 82:f01379c0f435 | 245 | } else { |
qaz | 82:f01379c0f435 | 246 | //printf("Failed to get gyroscope configuration\n"); |
qaz | 82:f01379c0f435 | 247 | failures++; |
qaz | 82:f01379c0f435 | 248 | } |
qaz | 82:f01379c0f435 | 249 | |
qaz | 82:f01379c0f435 | 250 | wait(1.0); |
qaz | 82:f01379c0f435 | 251 | //printf("\033[H"); //home |
qaz | 82:f01379c0f435 | 252 | //printf("\033[0J"); //erase from cursor to end of screen |
qaz | 82:f01379c0f435 | 253 | |
qaz | 82:f01379c0f435 | 254 | /*if(failures == 0) |
qaz | 82:f01379c0f435 | 255 | // FORMAT_CODE_END |
qaz | 82:f01379c0f435 | 256 | //{ |
qaz | 82:f01379c0f435 | 257 | |
qaz | 82:f01379c0f435 | 258 | BMI160::SensorData accData; |
qaz | 82:f01379c0f435 | 259 | BMI160::SensorData gyroData; |
qaz | 82:f01379c0f435 | 260 | BMI160::SensorTime sensorTime; |
qaz | 82:f01379c0f435 | 261 | |
qaz | 82:f01379c0f435 | 262 | // }*/ |
qaz | 82:f01379c0f435 | 263 | |
qaz | 82:f01379c0f435 | 264 | rLED = LED_OFF; |
qaz | 82:f01379c0f435 | 265 | gLED = LED_OFF; |
qaz | 82:f01379c0f435 | 266 | |
qaz | 82:f01379c0f435 | 267 | button.rise(&button_callback); // attach the address of the flip function to the rising edge |
qaz | 82:f01379c0f435 | 268 | |
qaz | 82:f01379c0f435 | 269 | button_pressed=0; |
qaz | 82:f01379c0f435 | 270 | |
qaz | 82:f01379c0f435 | 271 | while (true) { |
qaz | 82:f01379c0f435 | 272 | |
qaz | 83:b67e4bb6a087 | 273 | if(button_pressed>=1) { // double-pressed if for calibration (ideally). Set to triple-pressed to reduce sensitivity (see below). |
qaz | 82:f01379c0f435 | 274 | tick.attach_us(&tick_timer, 1000); |
qaz | 82:f01379c0f435 | 275 | gLED = LED_ON; |
qaz | 82:f01379c0f435 | 276 | rLED = LED_OFF; |
qaz | 82:f01379c0f435 | 277 | //float raw = scaleRaw.read(); |
qaz | 82:f01379c0f435 | 278 | // maybe calibrate against weighing scales reading here |
qaz | 82:f01379c0f435 | 279 | float timer=0; |
qaz | 82:f01379c0f435 | 280 | time_t seconds = time(NULL); |
mbed_official | 1:72c60abef7e7 | 281 | |
qaz | 82:f01379c0f435 | 282 | char filename[40]; |
qaz | 82:f01379c0f435 | 283 | if (debugging) pc.printf("%s\n", filename); |
qaz | 82:f01379c0f435 | 284 | rLED = LED_ON; |
qaz | 82:f01379c0f435 | 285 | if (fs.mount(&bd) == 0) { // SDBlock stuff. changed from "if (sd.mount() == 0)" |
qaz | 82:f01379c0f435 | 286 | if (debugging) pc.printf("Mounted SD card\n"); |
qaz | 82:f01379c0f435 | 287 | FILE *ft = fopen("/fs/time.txt", "r"); // changed from "/sd/"... |
qaz | 82:f01379c0f435 | 288 | if(ft != NULL) { |
qaz | 82:f01379c0f435 | 289 | fscanf(ft, "%d", &epoch_time); |
qaz | 82:f01379c0f435 | 290 | fclose(ft); |
qaz | 82:f01379c0f435 | 291 | set_time(epoch_time); // handy to have this, since it allows users to take out the SD card and reset the time from graphgen.xlsx |
qaz | 82:f01379c0f435 | 292 | seconds = time(NULL); // no idea why it seemed necessary to subtract 2^20 from the time to get the time stamping to work properly |
qaz | 82:f01379c0f435 | 293 | } else if (debugging) pc.printf("Failed to open time.txt!"); |
qaz | 82:f01379c0f435 | 294 | strftime(filename, 40, "/fs/%a_%d_%m_%Y_%H_%M_%S.csv", localtime(&seconds)); // changed from "/sd/"... |
qaz | 82:f01379c0f435 | 295 | FILE *fc = fopen("/fs/calibration.txt", "r"); // changed from "/sd/"... |
qaz | 82:f01379c0f435 | 296 | if(fc != NULL) { |
qaz | 82:f01379c0f435 | 297 | |
qaz | 82:f01379c0f435 | 298 | while (fscanf(fc, "%d", &calibration_factor) != EOF) { |
qaz | 82:f01379c0f435 | 299 | //i++; |
qaz | 82:f01379c0f435 | 300 | } |
qaz | 82:f01379c0f435 | 301 | scale.setScale(calibration_factor); //Adjust to this calibration factor |
qaz | 82:f01379c0f435 | 302 | fclose(fc); |
qaz | 82:f01379c0f435 | 303 | } |
qaz | 82:f01379c0f435 | 304 | |
qaz | 82:f01379c0f435 | 305 | if (debugging) pc.printf("-!-"); |
qaz | 82:f01379c0f435 | 306 | FILE *fp = fopen(filename, "w"); |
qaz | 82:f01379c0f435 | 307 | if(fp != NULL) { |
qaz | 82:f01379c0f435 | 308 | if (debugging) pc.printf("-+-"); |
qaz | 82:f01379c0f435 | 309 | ble_call = true; // Turn on calling. This is read in periodicCallback(void) |
qaz | 82:f01379c0f435 | 310 | sprintf(topline, "Time,Weight,ACC xAxis,ACC yAxis,ACC zAxis,GYRO xAxis,GYRO yAxis,GYRO zAxis,Calibration factor=%d\n", calibration_factor); |
qaz | 82:f01379c0f435 | 311 | fprintf(fp, topline); |
qaz | 82:f01379c0f435 | 312 | rLED = LED_OFF; |
qaz | 82:f01379c0f435 | 313 | imu.getSensorTime(startTime); |
qaz | 82:f01379c0f435 | 314 | char my_string[256]; |
qaz | 82:f01379c0f435 | 315 | |
qaz | 82:f01379c0f435 | 316 | while(timer<=20) { |
qaz | 82:f01379c0f435 | 317 | imu.getGyroAccXYZandSensorTime(accData, gyroData, sensorTime, accConfig.range, gyroConfig.range); |
qaz | 82:f01379c0f435 | 318 | |
qaz | 82:f01379c0f435 | 319 | weight = scale.getGram(); |
qaz | 82:f01379c0f435 | 320 | waittimeexpired = false; |
qaz | 82:f01379c0f435 | 321 | if (debugging) pc.printf("Going to wait"); |
qaz | 82:f01379c0f435 | 322 | while (waittimeexpired&waittimeexpired==false); // Loop until another ticker sets the variable |
qaz | 82:f01379c0f435 | 323 | if (debugging) pc.printf("Finished waiting"); |
qaz | 82:f01379c0f435 | 324 | sprintf(my_string, "%.3f,%.3f,%4.3f,%4.3f,%4.3f,%5.1f,%5.1f,%5.1f,\n" |
qaz | 82:f01379c0f435 | 325 | , sensorTime.seconds-startTime.seconds |
qaz | 82:f01379c0f435 | 326 | , weight |
qaz | 82:f01379c0f435 | 327 | , accData.xAxis.scaled |
qaz | 82:f01379c0f435 | 328 | , accData.yAxis.scaled |
qaz | 82:f01379c0f435 | 329 | , accData.zAxis.scaled |
qaz | 82:f01379c0f435 | 330 | , gyroData.xAxis.scaled |
qaz | 82:f01379c0f435 | 331 | , gyroData.yAxis.scaled |
qaz | 82:f01379c0f435 | 332 | , gyroData.zAxis.scaled); |
qaz | 82:f01379c0f435 | 333 | |
qaz | 82:f01379c0f435 | 334 | //printf(my_string); |
qaz | 82:f01379c0f435 | 335 | fprintf(fp, my_string); |
qaz | 82:f01379c0f435 | 336 | timer=sensorTime.seconds-startTime.seconds; |
qaz | 82:f01379c0f435 | 337 | //wait(0.01f); |
qaz | 82:f01379c0f435 | 338 | |
qaz | 82:f01379c0f435 | 339 | } // while (timer<=20) |
qaz | 82:f01379c0f435 | 340 | fclose(fp); |
qaz | 82:f01379c0f435 | 341 | seconds = time(NULL); |
qaz | 82:f01379c0f435 | 342 | //pc.printf("seconds %d\n", seconds); |
qaz | 82:f01379c0f435 | 343 | FILE *fs = fopen("/fs/time.txt", "w"); // changed from "/sd/"... |
qaz | 82:f01379c0f435 | 344 | char time_buf[11]; |
qaz | 82:f01379c0f435 | 345 | sprintf(time_buf, "%u", seconds); |
qaz | 82:f01379c0f435 | 346 | //pc.printf("time_buf: %s\n", time_buf); |
qaz | 82:f01379c0f435 | 347 | fprintf(fs, "%s", time_buf); |
qaz | 82:f01379c0f435 | 348 | fclose(fs); |
qaz | 82:f01379c0f435 | 349 | |
qaz | 82:f01379c0f435 | 350 | } else { |
qaz | 82:f01379c0f435 | 351 | if (debugging) pc.printf("Failed to open csv file!"); |
qaz | 82:f01379c0f435 | 352 | gLED = LED_OFF; |
qaz | 82:f01379c0f435 | 353 | wait(2); |
qaz | 82:f01379c0f435 | 354 | rLED=LED_OFF; |
qaz | 82:f01379c0f435 | 355 | } |
qaz | 82:f01379c0f435 | 356 | fs.unmount(); // changed from sd.unmount() |
qaz | 82:f01379c0f435 | 357 | } else { // If sd has not mounted |
qaz | 82:f01379c0f435 | 358 | gLED = LED_OFF; |
qaz | 82:f01379c0f435 | 359 | rLED = LED_OFF; |
qaz | 82:f01379c0f435 | 360 | wait(1.0); // make plenty of time for second press |
qaz | 83:b67e4bb6a087 | 361 | if (button_pressed > 2) { // If double[triple for desensitivity]-click (or more) |
qaz | 82:f01379c0f435 | 362 | // blink blue once and send out a reading on the com port |
qaz | 82:f01379c0f435 | 363 | bLED = LED_ON; |
qaz | 82:f01379c0f435 | 364 | wait(1.0); |
qaz | 82:f01379c0f435 | 365 | bLED = LED_OFF; |
qaz | 82:f01379c0f435 | 366 | wait(1.0); |
qaz | 82:f01379c0f435 | 367 | pc.printf("%f %d", scale.getGram(), calibration_factor); |
qaz | 82:f01379c0f435 | 368 | button_pressed = 0; |
qaz | 82:f01379c0f435 | 369 | } else { // indicate that there is no sd card |
qaz | 82:f01379c0f435 | 370 | for (int isd = 0; isd < seconds_to_blink_if_sd_mount_fails; isd++) { |
qaz | 82:f01379c0f435 | 371 | rLED = LED_ON; |
qaz | 82:f01379c0f435 | 372 | wait(0.5); |
qaz | 82:f01379c0f435 | 373 | rLED = LED_OFF; |
qaz | 82:f01379c0f435 | 374 | wait(0.5); |
qaz | 82:f01379c0f435 | 375 | } |
qaz | 82:f01379c0f435 | 376 | } |
qaz | 82:f01379c0f435 | 377 | rLED = LED_OFF; |
qaz | 82:f01379c0f435 | 378 | |
qaz | 82:f01379c0f435 | 379 | }// if sd.mount == 0 ... else |
qaz | 82:f01379c0f435 | 380 | gLED = LED_OFF; |
qaz | 82:f01379c0f435 | 381 | button_pressed = 0; |
qaz | 82:f01379c0f435 | 382 | tick.detach(); |
qaz | 82:f01379c0f435 | 383 | // eventQueue.break_dispatch(); // basic attempt to stop of BLE. Result was flaky. |
qaz | 82:f01379c0f435 | 384 | // ble_thread.terminate(); |
qaz | 82:f01379c0f435 | 385 | ble_call = false; // This is read in periodicCallback(void) |
qaz | 82:f01379c0f435 | 386 | } // if (button_pressed==1) |
qaz | 82:f01379c0f435 | 387 | // sleep(); // "Note: In most cases, you don't need to call sleep() directly. Mbed OS enters sleep mode automatically any time the system is idle. That is when all your threads are in a waiting state, for example waiting for an event or a timeout." |
qaz | 82:f01379c0f435 | 388 | } // while (1) |
mbed_official | 1:72c60abef7e7 | 389 | } |
qaz | 81:b8ef2a762318 | 390 | |
qaz | 81:b8ef2a762318 | 391 | //***************************************************************************** |
qaz | 81:b8ef2a762318 | 392 | void dumpImuRegisters(BMI160 &imu) { |
qaz | 81:b8ef2a762318 | 393 | printRegister(imu, BMI160::CHIP_ID); |
qaz | 81:b8ef2a762318 | 394 | printBlock(imu, BMI160::ERR_REG,BMI160::FIFO_DATA); |
qaz | 81:b8ef2a762318 | 395 | printBlock(imu, BMI160::ACC_CONF, BMI160::FIFO_CONFIG_1); |
qaz | 81:b8ef2a762318 | 396 | printBlock(imu, BMI160::MAG_IF_0, BMI160::SELF_TEST); |
qaz | 81:b8ef2a762318 | 397 | printBlock(imu, BMI160::NV_CONF, BMI160::STEP_CONF_1); |
qaz | 81:b8ef2a762318 | 398 | printRegister(imu, BMI160::CMD); |
qaz | 81:b8ef2a762318 | 399 | //printf("\n"); |
qaz | 81:b8ef2a762318 | 400 | } |
qaz | 81:b8ef2a762318 | 401 | |
qaz | 81:b8ef2a762318 | 402 | //***************************************************************************** |
qaz | 81:b8ef2a762318 | 403 | void printRegister(BMI160 &imu, BMI160::Registers reg) { |
qaz | 81:b8ef2a762318 | 404 | uint8_t data; |
qaz | 81:b8ef2a762318 | 405 | if(imu.readRegister(reg, &data) == BMI160::RTN_NO_ERROR) { |
qaz | 81:b8ef2a762318 | 406 | //printf("IMU Register 0x%02x = 0x%02x\n", reg, data); |
qaz | 81:b8ef2a762318 | 407 | } else { |
qaz | 81:b8ef2a762318 | 408 | //printf("Failed to read register\n"); |
qaz | 81:b8ef2a762318 | 409 | } |
qaz | 81:b8ef2a762318 | 410 | } |
qaz | 81:b8ef2a762318 | 411 | |
qaz | 81:b8ef2a762318 | 412 | |
qaz | 81:b8ef2a762318 | 413 | //***************************************************************************** |
qaz | 81:b8ef2a762318 | 414 | void printBlock(BMI160 &imu, BMI160::Registers startReg, BMI160::Registers stopReg) { |
qaz | 81:b8ef2a762318 | 415 | uint8_t numBytes = ((stopReg - startReg) + 1); |
qaz | 81:b8ef2a762318 | 416 | uint8_t buff[numBytes]; |
qaz | 81:b8ef2a762318 | 417 | uint8_t offset = static_cast<uint8_t>(startReg); |
qaz | 81:b8ef2a762318 | 418 | |
qaz | 81:b8ef2a762318 | 419 | if(imu.readBlock(startReg, stopReg, buff) == BMI160::RTN_NO_ERROR) { |
qaz | 81:b8ef2a762318 | 420 | for(uint8_t idx = offset; idx < (numBytes + offset); idx++) { |
qaz | 81:b8ef2a762318 | 421 | //printf("IMU Register 0x%02x = 0x%02x\n", idx, buff[idx - offset]); |
qaz | 81:b8ef2a762318 | 422 | } |
qaz | 81:b8ef2a762318 | 423 | } else { |
qaz | 81:b8ef2a762318 | 424 | //printf("Failed to read block\n"); |
qaz | 81:b8ef2a762318 | 425 | } |
qaz | 81:b8ef2a762318 | 426 | } |
qaz | 81:b8ef2a762318 | 427 | void button_callback() { |
qaz | 81:b8ef2a762318 | 428 | |
qaz | 81:b8ef2a762318 | 429 | button_pressed++; // changed to allow detection of double presses |
qaz | 81:b8ef2a762318 | 430 | |
qaz | 81:b8ef2a762318 | 431 | } |