20200716 read Status Register each second
Dependencies: SDFileSystem mbed-os-example-ble-GattServer max32630fthr
main.cpp
- Committer:
- aureliocarella
- Date:
- 2020-07-16
- Revision:
- 21:51e162c130a9
- Parent:
- 0:c671a4833315
File content as of revision 21:51e162c130a9:
/* mbed Microcontroller Library * Copyright (c) 2017 ARM Limited * * 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 <stdio.h> #include "platform/Callback.h" #include "events/EventQueue.h" #include "platform/NonCopyable.h" #include "ble/BLE.h" #include "ble/Gap.h" #include "ble/GattClient.h" #include "ble/GapAdvertisingParams.h" #include "ble/GapAdvertisingData.h" #include "ble/GattServer.h" #include "BLEProcess.h" #include "max32630fthr.h" #include "RpcServer.h" #include "StringInOut.h" #include "Peripherals.h" #include "MAX30001.h" #include "DataLoggingService.h" #include "PushButton.h" #include "Streaming.h" #include "SDFileSystem.h" #include "version.h" using mbed::callback; /** * A Clock service that demonstrate the GattServer features. * * The clock service host three characteristics that model the current hour, * minute and second of the clock. The value of the second characteristic is * incremented automatically by the system. * * A client can subscribe to updates of the clock characteristics and get * notified when one of the value is changed. Clients can also change value of * the second, minute and hour characteristric. */ class ClockService { typedef ClockService Self; public: uint8_t second; uint8_t minute; uint8_t hour; ClockService() : _ecg("485f4145-52b9-4644-af1f-7a6b9322490f", 0), _rr_bpm("0a924ca7-87cd-4699-a3bd-abdcd9cf126a", 0), _max30001_chr("8dd6a1b7-bc75-4741-8a26-264af75807de", 0), _ecg_service( /* uuid */ "51311102-030e-485f-b122-f8f381aa84ed", /* characteristics */ _ecg_characteristics, /* numCharacteristics */ sizeof(_ecg_characteristics) / sizeof(_ecg_characteristics[0]) ), _server(NULL), _event_queue(NULL) { // update internal pointers (value, descriptors and characteristics array) _ecg_characteristics[0] = &_ecg; _ecg_characteristics[1] = &_rr_bpm; _ecg_characteristics[2] = &_max30001_chr; // setup authorization handlers _ecg.setWriteAuthorizationCallback(this, &Self::authorize_client_write); _rr_bpm.setWriteAuthorizationCallback(this, &Self::authorize_client_write); _max30001_chr.setWriteAuthorizationCallback(this, &Self::authorize_client_write); } void start(BLE &ble_interface, events::EventQueue &event_queue) { if (_event_queue) { return; } _server = &ble_interface.gattServer(); _event_queue = &event_queue; // register the service printf("Adding demo service\r\n"); ble_error_t err = _server->addService(_ecg_service); if (err) { printf("Error %u during demo service registration.\r\n", err); return; } // read write handler _server->onDataSent(as_cb(&Self::when_data_sent)); _server->onDataWritten(as_cb(&Self::when_data_written)); _server->onDataRead(as_cb(&Self::when_data_read)); // updates subscribtion handlers _server->onUpdatesEnabled(as_cb(&Self::when_update_enabled)); _server->onUpdatesDisabled(as_cb(&Self::when_update_disabled)); _server->onConfirmationReceived(as_cb(&Self::when_confirmation_received)); // print the handles printf("clock service registered\r\n"); printf("service handle: %u\r\n", _ecg_service.getHandle()); printf("\thour characteristic value handle %u\r\n", _ecg.getValueHandle()); printf("\tminute characteristic value handle %u\r\n", _rr_bpm.getValueHandle()); printf("\tsecond characteristic value handle %u\r\n", _max30001_chr.getValueHandle()); _event_queue->call_every(2000 /* ms */, callback(this, &Self::increment_second)); } private: /** * Handler called when a notification or an indication has been sent. */ void when_data_sent(unsigned count) { printf("sent %u updates\r\n", count); } /** * Handler called after an attribute has been written. */ void when_data_written(const GattWriteCallbackParams *e) { printf("data written:\r\n"); printf("\tconnection handle: %u\r\n", e->connHandle); printf("\tattribute handle: %u", e->handle); if (e->handle == _ecg.getValueHandle()) { printf(" (hour characteristic)\r\n"); hour = e->data[0]; } else if (e->handle == _rr_bpm.getValueHandle()) { printf(" (minute characteristic)\r\n"); minute = e->data[0]; } else if (e->handle == _max30001_chr.getValueHandle()) { printf(" (second characteristic)\r\n"); second = e->data[0]; } else { printf("\r\n"); } printf("\twrite operation: %u\r\n", e->writeOp); printf("\toffset: %u\r\n", e->offset); printf("\tlength: %u\r\n", e->len); printf("\t data: "); for (size_t i = 0; i < e->len; ++i) { printf("%02X", e->data[i]); } printf("\r\n"); } /** * Handler called after an attribute has been read. */ void when_data_read(const GattReadCallbackParams *e) { printf("data read:\r\n"); printf("\tconnection handle: %u\r\n", e->connHandle); printf("\tattribute handle: %u", e->handle); if (e->handle == _ecg.getValueHandle()) { printf(" (hour characteristic)\r\n"); } else if (e->handle == _rr_bpm.getValueHandle()) { printf(" (minute characteristic)\r\n"); } else if (e->handle == _max30001_chr.getValueHandle()) { printf(" (second characteristic)\r\n"); } else { printf("\r\n"); } } /** * Handler called after a client has subscribed to notification or indication. * * @param handle Handle of the characteristic value affected by the change. */ void when_update_enabled(GattAttribute::Handle_t handle) { printf("update enabled on handle %d\r\n", handle); } /** * Handler called after a client has cancelled his subscription from * notification or indication. * * @param handle Handle of the characteristic value affected by the change. */ void when_update_disabled(GattAttribute::Handle_t handle) { printf("update disabled on handle %d\r\n", handle); } /** * Handler called when an indication confirmation has been received. * * @param handle Handle of the characteristic value that has emitted the * indication. */ void when_confirmation_received(GattAttribute::Handle_t handle) { printf("confirmation received on handle %d\r\n", handle); } /** * Handler called when a write request is received. * * This handler verify that the value submitted by the client is valid before * authorizing the operation. */ void authorize_client_write(GattWriteAuthCallbackParams *e) { printf("characteristic %u write authorization\r\n", e->handle); if (e->offset != 0) { printf("Error invalid offset\r\n"); e->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET; return; } if (e->len != 1) { printf("Error invalid len\r\n"); e->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH; return; } if ((e->data[0] >= 60) || ((e->data[0] >= 24) && (e->handle == _ecg.getValueHandle()))) { printf("Error invalid data\r\n"); e->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_WRITE_NOT_PERMITTED; return; } e->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS; } /** * Increment the second counter. */ void increment_second(void) { ble_error_t err = _max30001_chr.get(*_server, second); if (err) { printf("read of the second value returned error %u\r\n", err); return; } second = (second + 1) % 60; uint32_t* mamt; //MAX30001::MAX30001_REG_map_t reg = (MAX30001_REG_map_t)0x01; uint8_t addr = 0x01; //STATUS printf("reg=%d ", addr); int res = Peripherals::max30001()->max30001_reg_read(addr, mamt); printf("MAMT=%d, %x\r\n", res, *mamt); /* printf("RPC"); char reply1[128]; // process the RPC string RPC_call("/System/ReadVer", reply1); //Send reply to debug port printf(reply1);*/ printf("%d-%d-%d\r\n",hour, minute, second); err = _max30001_chr.set(*_server, second); if (err) { printf("write of the second value returned error %u\r\n", err); return; } if (second == 0) { increment_minute(); } } /** * Increment the minute counter. */ void increment_minute(void) { ble_error_t err = _rr_bpm.get(*_server, minute); if (err) { printf("read of the minute value returned error %u\r\n", err); return; } minute = (minute + 1) % 60; err = _rr_bpm.set(*_server, minute); if (err) { printf("write of the minute value returned error %u\r\n", err); return; } if (minute == 0) { increment_hour(); } } /** * Increment the hour counter. */ void increment_hour(void) { ble_error_t err = _ecg.get(*_server, hour); if (err) { printf("read of the hour value returned error %u\r\n", err); return; } hour = (hour + 1) % 24; err = _ecg.set(*_server, hour); if (err) { printf("write of the hour value returned error %u\r\n", err); return; } } private: /** * Helper that construct an event handler from a member function of this * instance. */ template<typename Arg> FunctionPointerWithContext<Arg> as_cb(void (Self::*member)(Arg)) { return makeFunctionPointer(this, member); } /** * Read, Write, Notify, Indicate Characteristic declaration helper. * * @tparam T type of data held by the characteristic. */ template<typename T> class ReadWriteNotifyIndicateCharacteristic : public GattCharacteristic { public: /** * Construct a characteristic that can be read or written and emit * notification or indication. * * @param[in] uuid The UUID of the characteristic. * @param[in] initial_value Initial value contained by the characteristic. */ ReadWriteNotifyIndicateCharacteristic(const UUID & uuid, const T& initial_value) : GattCharacteristic( /* UUID */ uuid, /* Initial value */ &_value, /* Value size */ sizeof(_value), /* Value capacity */ sizeof(_value), /* Properties */ GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE, /* Descriptors */ NULL, /* Num descriptors */ 0, /* variable len */ false ), _value(initial_value) { } /** * Get the value of this characteristic. * * @param[in] server GattServer instance that contain the characteristic * value. * @param[in] dst Variable that will receive the characteristic value. * * @return BLE_ERROR_NONE in case of success or an appropriate error code. */ ble_error_t get(GattServer &server, T& dst) const { uint16_t value_length = sizeof(dst); return server.read(getValueHandle(), &dst, &value_length); } /** * Assign a new value to this characteristic. * * @param[in] server GattServer instance that will receive the new value. * @param[in] value The new value to set. * @param[in] local_only Flag that determine if the change should be kept * locally or forwarded to subscribed clients. */ ble_error_t set( GattServer &server, const uint8_t &value, bool local_only = false ) const { return server.write(getValueHandle(), &value, sizeof(value), local_only); } private: uint8_t _value; }; ReadWriteNotifyIndicateCharacteristic<uint8_t> _ecg; ReadWriteNotifyIndicateCharacteristic<uint8_t> _rr_bpm; ReadWriteNotifyIndicateCharacteristic<uint8_t> _max30001_chr; // list of the characteristics of the clock service GattCharacteristic* _ecg_characteristics[3]; // demo service GattService _ecg_service; GattServer* _server; events::EventQueue *_event_queue; }; //Init PMIC on FTHR board and set logic thresholds to 3.3V MAX32630FTHR pegasus(MAX32630FTHR::VIO_3V3); SDFileSystem sd(P0_5, P0_6, P0_4, P0_7, "sd"); // mosi, miso, sclk, cs //SD card insertion detection pin DigitalIn SDDetect(P2_2, PullUp); /// DigitalOut for CS DigitalOut cs(P5_6); /// SPI Master 2 with SPI0_SS for use with MAX30001 SPI spi(SPI2_MOSI, SPI2_MISO, SPI2_SCK); // used by MAX30001 /// SPI Master 1 QuadSpiInterface quadSpiInterface(SPI1_MOSI, SPI1_MISO, SPI1_SCK, SPI1_SS); // used by S25FS512 /// External Flash S25FS512 s25fs512(&quadSpiInterface); /// ECG device MAX30001 max30001(&spi, &cs); InterruptIn max30001_InterruptB(P5_5); InterruptIn max30001_Interrupt2B(P5_4); /// HSP platform LED HspLed hspLed(LED_RED); /// Packet TimeStamp Timer, set for 1uS Timer timestampTimer; /// HSP Platform push button PushButton pushButton(SW1); // local input state of the RPC int inputState; // RPC request buffer char request[128]; // RPC reply buffer char reply[128]; int main() { // display start banner printf("Maxim Integrated mbed hSensor %d.%d.%d %02d/%02d/%02d\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_MONTH, VERSION_DAY, VERSION_SHORT_YEAR); // turn on red led printf("Init HSPLED...\n"); fflush(stdout); hspLed.on(); // set NVIC priorities for GPIO to prevent priority inversion printf("Init NVIC Priorities...\n"); fflush(stdout); NVIC_SetPriority(GPIO_P0_IRQn, 5); NVIC_SetPriority(GPIO_P1_IRQn, 5); NVIC_SetPriority(GPIO_P2_IRQn, 5); NVIC_SetPriority(GPIO_P3_IRQn, 5); NVIC_SetPriority(GPIO_P4_IRQn, 5); NVIC_SetPriority(GPIO_P5_IRQn, 5); NVIC_SetPriority(GPIO_P6_IRQn, 5); // used by the MAX30001 NVIC_SetPriority(SPIM2_IRQn, 0); // Be able to statically reference these devices anywhere in the application Peripherals::setS25FS512(&s25fs512); Peripherals::setTimestampTimer(×tampTimer); Peripherals::setHspLed(&hspLed); Peripherals::setPushButton(&pushButton); Peripherals::setMAX30001(&max30001); Peripherals::setSdFS(&sd); Peripherals::setSDDetect(&SDDetect); // init the S25FS256 external flash device printf("Init S25FS512...\n"); fflush(stdout); s25fs512.init(); // start blinking led1 printf("Init HSPLED Blink...\n"); fflush(stdout); // // MAX30001 // printf("Init MAX30001 callbacks, interrupts...\n"); fflush(stdout); max30001_InterruptB.disable_irq(); max30001_Interrupt2B.disable_irq(); max30001_InterruptB.mode(PullUp); max30001_InterruptB.fall(&MAX30001Mid_IntB_Handler); max30001_Interrupt2B.mode(PullUp); max30001_Interrupt2B.fall(&MAX30001Mid_Int2B_Handler); max30001_InterruptB.enable_irq(); max30001_Interrupt2B.enable_irq(); MAX30001_AllowInterrupts(1); max30001.max30001_sw_rst(); // Do a software reset of the MAX30001 max30001.max30001_INT_assignment(MAX30001::MAX30001_INT_B, MAX30001::MAX30001_NO_INT, MAX30001::MAX30001_NO_INT, // en_enint_loc, en_eovf_loc, en_fstint_loc, MAX30001::MAX30001_INT_2B, MAX30001::MAX30001_INT_2B, MAX30001::MAX30001_NO_INT, // en_dcloffint_loc, en_bint_loc, en_bovf_loc, MAX30001::MAX30001_INT_2B, MAX30001::MAX30001_INT_2B, MAX30001::MAX30001_NO_INT, // en_bover_loc, en_bundr_loc, en_bcgmon_loc, MAX30001::MAX30001_INT_B, MAX30001::MAX30001_NO_INT, MAX30001::MAX30001_NO_INT, // en_pint_loc, en_povf_loc, en_pedge_loc, MAX30001::MAX30001_INT_2B, MAX30001::MAX30001_INT_B, MAX30001::MAX30001_NO_INT, // en_lonint_loc, en_rrint_loc, en_samp_loc, MAX30001::MAX30001_INT_ODNR, MAX30001::MAX30001_INT_ODNR); // intb_Type, int2b_Type) max30001.onDataAvailable(&StreamPacketUint32); // initialize the RPC server printf("Init RPC Server...\n"); fflush(stdout); RPC_init(); // initialize the logging service printf("Init LoggingService...\n"); fflush(stdout); LoggingService_Init(); // initialize the SD disk sd.disk_initialize(); // start main loop printf("Start main loop...\n"); fflush(stdout); BLE &ble_interface = BLE::Instance(); events::EventQueue event_queue; ClockService demo_service; BLEProcess ble_process(event_queue, ble_interface); ble_process.on_init(callback(&demo_service, &ClockService::start)); // bind the event queue to the ble interface, initialize the interface // and start advertising ble_process.start(); // Process the event queue. event_queue.dispatch_forever(); return 0; }