Supplying mbl_mw_datasignal_read_with_parameters with UnsafeRawPointer to Struct

Hello,

I'm trying to set up the analogue readout using the parameter struct, and thus I'm translating this C++ code to Swift:

MblMwGpioAnalogReadParameters read_params= { 0, MBL_MW_GPIO_UNUSED_PIN, MBL_MW_GPIO_UNUSED_PIN, 0 };
mbl_mw_datasignal_read_with_parameters(adc_signal, &read_params);

I'm not at all good with either of these languages, so I've tried a number of things. The two attempts which are possibly close candidates for a solution look like this:

var readParams = MblMwGpioAnalogReadParameters.init(pullup_pin: 0, pulldown_pin: 1, virtual_pin: 0, delay_us: 10)
let pointer = UnsafeRawPointer(&readParams)
mbl_mw_datasignal_read_with_parameters(adc_signal, pointer)

And...

struct ReadParams {
        let first:Int = 0
        let second = MBL_MW_GPIO_UNUSED_PIN
        let third = MBL_MW_GPIO_UNUSED_PIN
        let fourth:Int = 0
}

var testParams:ReadParams
let pointer = UnsafeRawPointer(&testParams)

As you can probably tell, I'm fairly clueless here. The compiler complains about ambiguous use of 'init()' in both cases.
Hope you can provide the correct initialization of the pointer.

Comments

  • Oh. Silly me. I missed the most obvious. Here's the whole function:

    func testAnalog() {
            let adc_signal = mbl_mw_gpio_get_analog_input_data_signal(device.board, 0, MBL_MW_GPIO_ANALOG_READ_MODE_ABS_REF)
    
            mbl_mw_datasignal_subscribe(adc_signal!, bridge(obj: self)) { (context, data) in
                let dataSignal = data!.pointee.valueAs() as UInt32
                DispatchQueue.main.async{
                    print(dataSignal)
                }
            }    
    
            var readParams = MblMwGpioAnalogReadParameters.init(pullup_pin: 0, pulldown_pin: 1, virtual_pin: 0, delay_us: 10)
            mbl_mw_datasignal_read_with_parameters(adc_signal, &readParams)
        }
    

    I'm posting it all because I don't think it's quite right yet.
    I only get a single value, no continuous data stream. What am I missing here?

  • I had hoped to return with some functions ready for copy/paste, but I've had a hard time wrapping my head around all these nested Tasks, and my grasp of the flow control is lacking, I must admit.

    I do think I'm getting close, but continue to fail the final printout of the voltage and I need some feedback.
    Based on the starter project, I changed the setup() call in MainTableViewController to setupAnalogRead() :

    func setupAnalogRead(_ device: MetaWear) -> Task<()> {
            var voltSignal: OpaquePointer!
            return device.getVoltSignal().continueOnSuccessWithTask { signal -> Task<OpaquePointer> in
                voltSignal = signal
                return device.timerCreate(period: 100)
                }.continueOnSuccessWithTask { timer -> Task<Void> in
                    self.voltTimerId = mbl_mw_timer_get_id(timer)
                    mbl_mw_timer_start(timer)
                    mbl_mw_event_record_commands(timer)
                    mbl_mw_datasignal_read(voltSignal)
                    return timer.eventEndRecord()
                }.continueOnSuccessWith {
                    self.serializedState = device.serialize()
                    self.saveToUrl(device.uniqueUrl)
            }
        }
    

    It's basically the same, except without the logging and another timer id.

    In DeviceState, I've added this function to the MetaWear extension:

    func getVoltSignal() -> Task<OpaquePointer> {
            guard mbl_mw_metawearboard_lookup_module(board, MBL_MW_MODULE_GPIO) != MBL_MW_MODULE_TYPE_NA else {
                return Task<OpaquePointer>(error: MetaWearError.operationFailed(message: "No GPIO module"))
            }
            let tempSignal = mbl_mw_gpio_get_analog_input_data_signal(board, 0,      MBL_MW_GPIO_ANALOG_READ_MODE_ABS_REF)
            return Task<OpaquePointer>(tempSignal!)
        }
    

    Finally, in stead of calling doDownload function, I call this:

        func printVoltData(state: DeviceState) {
                let voltSignal = mbl_mw_logger_lookup_id(device.board, state.voltTimerId)
    
                mbl_mw_datasignal_subscribe(voltSignal!, bridge(obj: self)) { (context, data) in
                    let dataSignal = data!.pointee.valueAs() as UInt32
                    DispatchQueue.main.async{
                        //let mySelf = Unmanaged<GraphicsViewController>.fromOpaque(context!).takeUnretainedValue()
                        print("data: \(dataSignal)")
                    }
                }
            }
    

    ...which is where the shit hits the fan. This is just one of many variations I've tried, and it's obviously displaying my lack of understanding. I get a nil value error when unpacking voltSignal (I think).

    I'm simply cannot fathom how to get a hold of this data signal using these Tasks.

    I had a look in your old MetaWearApiTest project, which used a very different and simpler solution:

    @IBAction func readAnalogAbsolutePressed(_ sender: Any) {
            let pin = device.gpio!.pins[gpioPinSelector.selectedSegmentIndex]
            pin.analogAbsolute!.readAsync().success { result in
                self.gpioAnalogAbsoluteValue.text = String(format: "%.3fV", result.value.doubleValue)
            }
        }
    

    I have not tried this, since you didn't recommend it. Will it still work with the current firmware?

    If not, I hope to get a hint or two on where I'm going wrong here.
    Is it just the last bit about printing, or have I gone completely off the rails?

    Thanks for your time.

  • You're over complicating things. All you need to do is use the linked code as a reference for how to create a timer, and integrate that block into your existing code.

    You can use the older api if you want, we don't actively maintain it anymore though.

  • Hi Eric,
    Thanks for your feedback.

    I finally managed to set up a simple timer (just flashing a LED for now).

    I do this in DeviceState, but once I move to my graphics scene (new ViewController), and start reading Fusion data, the timer stops.

    Should I be looking at something like mbl_mw_dataprocessor_fuser_create in order to read gpio and Fusion data at the same time?

    Also, do you know of other examples of Timer use? I still have trouble figuring out where to set it up, exactly.

  • @Tobias said:
    Hi Eric,
    Thanks for your feedback.

    I finally managed to set up a simple timer (just flashing a LED for now).

    I do this in DeviceState, but once I move to my graphics scene (new ViewController), and start reading Fusion data, the timer stops.

    Tiimer should keep running. Does the same thing happen if you run the same code in a simple iOS app?

    Should I be looking at something like mbl_mw_dataprocessor_fuser_create in order to read gpio and Fusion data at the same time?

    No, fuser does not read data.

    Also, do you know of other examples of Timer use? I still have trouble figuring out where to set it up, exactly.

    Set it up where you are setting up sensor fusion.

  • edited February 26

    Thanks for your help Eric. I do earnestly appreciate it.

    However, considering our investment in your sensors, I have to repeat that your iOS documentation is lacking.

    Take this function as an example, which cost me close to a full day of frustrated confusion:
    mbl_mw_datasignal_read(signal: OpaquePointer)

    The documentation I get via xcode reads like this:

    Reads data from sensor represented by the data signal. Data is forwarded to the callback function assigned by the mbl_mw_datasignal_subscribe function

    Ok fine. Then where is this callback function defined? Lo and behold: It isn't.
    It's supposed to be the third parameter to the subscribe function, but that third parameter doesn't exist in Swift/iOS.

    As far as I can tell by now, it's replaced by the closure of the Swift function. You really can't expect developers to just 'get that' out of hand, even if they're not newbies like me.

    I don't know how many costumers you have that use Swift, but speaking for at least one of them, I hope you'll divert some resources to providing documentation that doesn't need to be translated from a completely unrelated language. Perhaps before you release the next firmware version?

    Whatever your choice, your tips are appreciated.
    I've chosen to ask and answer a new question, as this has drifted quite far from the original (and sorry about that).

    https://mbientlab.com/community/discussion/2921/how-to-stream-analog-data

    With reserved gratitude,
    Tobias

Sign In or Register to comment.