Use READ_REGISTER to read custom register on sensors

Hello,

I am currently going through the CPP functions and try to create some functions, one thing I want to do is to read the BOSCH POWER_MODE register (namely, the PWR_CTRL and PWR_CONF registers). I see that some of the CPP reading function is done through SEND_COMMAND with READ_REGISTER(ORDINAL(register_id)) as parameters. For example, the [read_accelerometer_bosch_acceleration_config] function in Cpp SDK set the context and callback to the states variable, the send READ_REGISTER command to retrieve config data.

My question is that how should we setup our own callbacks for other registers in Cpp SDK? Is there specific callback naming we should use?

Thanks

Comments

  • @JCagle95 Those functions are accessing registers that the metawear interface exposes, and not always raw registers of the peripheral sensors. Sometimes there is a direct mapping. If you don't see a particular register defined in the header files then it doesn't exist -- all of the useful ones are exposed to C++ already.

    Are you working with an MMS (BMI260) or MMR (BMI160) device? I can tell you how those registers are being managed by firmware. Normally the firmware is doing some management of raw sensor registers that control power or operating modes, as there are often timing or other sequencing constraints that make it impractical at the API level.

  • @Matt Thanks for the reply. I am working with MMS (BMI270) device. Based on reading the source codes, the power register is exposed as

    uint8_t command[2] = {MBL_MW_MODULE_ACCELEROMETER, READ_REGISTER(ORDINAL(AccelerometerBmi270Register::POWER_MODE))};
    SEND_COMMAND;
    

    I assume that in order to actually retrieve the data we also have to use the piecewise_construct similar to read_config functions:

    board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_ACCELEROMETER, READ_REGISTER(ORDINAL(AccelerometerBmi270Register::POWER_MODE))), forward_as_tuple(received_powermode_response));
    

    Are they correct? (I haven't gotten the chance to actually implement them yet as I am still making small utility functions to extract data directly from in-memory "AccBmi270Config" struct. Please let me know if this is the proper way to implement Cpp register reading, or if there are already implemented methods to read those registers. The reason I am asking this is because I am looking for a way to easily identify if a device is currently logging or not. It is possible that a logger exist only because data are not finished downloading yet, but they are actually not logging at the moment.

    Sincerely,

  • To follow up on the discussion, I decided to implement the read register callback today starting with the easy ones such as the CONFIG in Ambient Light sensor, since it is the same processing flow as other sensor but it is somehow not implemented in the Cpp SDK v0.20 in GitHub master branch (probably because ambient light sensor only available in MMS devices.

    To summarize, the reading is relatively straight forward, we implement a read config response like this with simple memcpy because write_config function is also just simply copy the register struct to be sent.

    static int32_t received_config_response(MblMwMetaWearBoard *board, const uint8_t *response, uint8_t len) {
        memcpy(board->module_config.at(MBL_MW_MODULE_AMBIENT_LIGHT), response + 2, sizeof(Ltr329Config));
    
        auto callback = states[board].read_config_completed;
        auto context = states[board].read_config_context;
        states[board].read_config_completed = nullptr;
        states[board].read_config_context = nullptr;
        callback(context, board, MBL_MW_STATUS_OK);
    
        return MBL_MW_STATUS_OK;
    }
    

    Then we implement the unordered map to hold context and callbacks for different boards

    struct AmbientLightState {
        MblMwFnBoardPtrInt read_config_completed;
        void *read_config_context;
    };
    
    static unordered_map<const MblMwMetaWearBoard*, AmbientLightState> states;
    

    Lastly we implement the response forwarding during sensor init:

        board->responses.emplace(piecewise_construct, forward_as_tuple(MBL_MW_MODULE_AMBIENT_LIGHT, READ_REGISTER(ORDINAL(AmbientLightLtr329Register::CONFIG))),
            forward_as_tuple(received_config_response));
    
        AmbientLightState newState = {nullptr};
        states.insert({board, newState});
    

    At the end, we can create a read_config function as either a private function or METAWEAR API for wrapping.

    void mbl_mw_als_ltr329_read_config(const MblMwMetaWearBoard *board, void *context, MblMwFnBoardPtrInt completed) {
        states[board].read_config_context = context;
        states[board].read_config_completed = completed;
    
        uint8_t command[2]= {MBL_MW_MODULE_AMBIENT_LIGHT, READ_REGISTER(ORDINAL(AmbientLightLtr329Register::CONFIG))};
        SEND_COMMAND;
    }
    

    We may either call this directly as standalone function, or simply implement this in the daisy chain of anonymous signal generator in metawearboard.cpp implementation. I do this because Accelerometer, Gyroscope, and Sensor Fusion config readings are already chained inside the function:

    // Helper function - read sensor fusion
    static void read_ambient_light_config_completed(void *context, MblMwMetaWearBoard* board, int32_t value) {
        if (mbl_mw_metawearboard_lookup_module(board, MBL_MW_MODULE_SENSOR_FUSION) != MBL_MW_MODULE_TYPE_NA) {
            mbl_mw_sensor_fusion_read_config(board, context, read_sensor_fusion_config_completed);
        } else {
            read_sensor_fusion_config_completed(context, board, MBL_MW_STATUS_OK);
        }
    }
    
    // Helper function - read light sensor
    static void read_gyro_config_completed(void *context, MblMwMetaWearBoard* board, int32_t value) {
        if (mbl_mw_metawearboard_lookup_module(board, MBL_MW_MODULE_AMBIENT_LIGHT) != MBL_MW_MODULE_TYPE_NA) {
            mbl_mw_als_ltr329_read_config(board, context, read_ambient_light_config_completed);
        } else {
            read_ambient_light_config_completed(context, board, MBL_MW_STATUS_OK);
        }
    }
    

    This would be a basic modification of Cpp SDK to add more sensor config readings and can be expanded to other READ_REGISTER function depending on how you would like to use them. Hopefully this could help others and @Matt please let me know if there are other recommendations when modifying the Cpp SDK for customization.

    Thanks

Sign In or Register to comment.