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(&timestampTimer);
    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;
}