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@82:f01379c0f435, 2019-10-25 (annotated)
- Committer:
- qaz
- Date:
- Fri Oct 25 10:33:47 2019 +0000
- Revision:
- 82:f01379c0f435
- Parent:
- 81:b8ef2a762318
- Child:
- 83:b67e4bb6a087
This now runs BLE stuff in its own thread, writes data to file, flashes if no SD card in place, sends data on BLE if there is data to be written. Not final of course, only a placeholder for sending valid data on BLE.
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 | 82:f01379c0f435 | 105 | led1 = !led1; /* Do blinky on LED1 while we're waiting for BLE events */ |
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 | 82:f01379c0f435 | 273 | if(button_pressed>=1) { // double-pressed if for calibration |
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 | 82:f01379c0f435 | 361 | if (button_pressed > 1) { // If double-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 | } |