Page 1 of 1

Incorrect Data being sent via BT LE? (Firmware Bug?)

Posted: July 24th, 2015, 11:04 am
by horseshoe7
Sometimes I notice that data coming from the PM5 is very wrong. It's noticeable with the elapsedTime and distance properties:

Here is some log output of my app. t: and dst: are of interest:

>> 17:00:22:600 V | (-[PMRowingServiceCharacteristicGeneralStatus updateRowingMachineWithData:]:100)
t:33.6s dst: 56.4m, wktTp: JustRow-Splits, intTp: Distance, wktSt: WorkoutRow, row: Inactive, stk: WAITING_FOR_WHEEL_TO_ACCELERATE_STATE, wktDurTp: DISTANCE_DURATION

>> 17:00:23:110 V | (-[PMRowingServiceCharacteristicGeneralStatus updateRowingMachineWithData:]:100)
t:33.6s dst: 3355499.8m, wktTp: JustRow-Splits, intTp: Distance, wktSt: WorkoutRow, row: Inactive, stk: WAITING_FOR_WHEEL_TO_ACCELERATE_STATE, wktDurTp: DISTANCE_DURATION

The first line is correct, and you can see that the rower is refreshing data at about 500ms, it's default.

Sometimes I get this with the elapsedTime field as well. Has anyone else seen this?? Also strange are the console output timestamps and those coming from the data. the data says it's the same time, but they clearly happened 500ms apart.

Re: Incorrect Data being sent via BT LE? (Firmware Bug?)

Posted: July 24th, 2015, 4:59 pm
by dxpack
I have not seen that issue. I am receiving and displaying consistently accurate Elapsed Time and Distance values for numerous brief test workouts and some 10+ minute workouts. Could you post your code that processes the incoming notification values? What is updateRowingMachineWithData: doing? Sounds like it's sending data to the PM5. What is the 100 message you're sending?

The app I'm working on subscribes to all 3 of the General characteristics, processes each, and outputs 1 combined set, with duplicate values (Elapsed Time for example) overwritten by the last in. I'm not checking Elapsed Time vs. system time stamp.

Re: Incorrect Data being sent via BT LE? (Firmware Bug?)

Posted: July 28th, 2015, 7:31 am
by horseshoe7
That's just log output. updateRowingMachine is the data object on my side. 100 is the line number in the .m file that made the call to the console log.

The idea is that I have an object PM5RowingMachine : NSObject that has a lot of properties on it. Via the service characteristics, I parse the data payload and set the properties on the PM5RowingMachine *_rower; object. Then I can just use KVO to observe values I care about.

I will eventually abstract this further and take some of the properties on the rower object and make them part of a workout object. But I need to understand more about the BT implementation first.

I haven't got into sending commands to the rower yet.

I really wish the Concept2 people would put more resources on documenting this. I mean there's a market there for developers. Otherwise they build the Rolls Royce of Egometers.

Code: Select all

- (void)updateRowingMachineWithData:(NSData*)data
{
    uint32_t time;
    [data getBytes:&time range:NSMakeRange(0, 3)];
    
    NSTimeInterval elapsed = (NSTimeInterval)time * 0.01;
    
    // HEY, what's this about?
    // I noticed that from time to time in the log, there would be what looked to be bogus data.
    // Assuming it came back from the rower like that.  Therefore ignoring it.
    if (elapsed > 27300000) {
        DDLogWarn(@"Bad data came back from the rower.  Ignoring this payload");
        return;
    }
    
    _rower.elapsedTimeInSeconds = elapsed;

    // distance
    uint32_t distance;
    [data getBytes:&distance range:NSMakeRange(3, 3)];
    _rower.distanceInMeters = (Float32)distance * 0.1f;
    
    // workout type
    uint8_t wType;
    [data getBytes:&wType range:NSMakeRange(6, 1)];
    _rower.workoutType = (OBJ_WORKOUTTYPE_T)wType;
    
    // interval type
    uint8_t iType;
    [data getBytes:&iType range:NSMakeRange(7, 1)];
    _rower.intervalType = (OBJ_INTERVALTYPE_T)iType;
    
    // workout state
    uint8_t wState;
    [data getBytes:&wState range:NSMakeRange(8, 1)];
    _rower.workoutState = (OBJ_WORKOUTSTATE_T)wState;

    // rowing state
    uint8_t rState;
    [data getBytes:&rState range:NSMakeRange(9, 1)];
    _rower.rowingState = (OBJ_ROWINGSTATE_T)rState;
    
    // stroke state
    uint8_t sState;
    [data getBytes:&sState range:NSMakeRange(10, 1)];
    _rower.strokeState = (OBJ_STROKESTATE_T)sState;

    // total work distance.  TODO:  check if it's 0.1 LSB, as it's not clear in dox
    uint32_t twDistance;
    [data getBytes:&twDistance range:NSMakeRange(11, 3)];
    _rower.totalWorkDistanceInMeters = (float)twDistance * 0.1f;
    
    // workout duration
    uint32_t wDuration;
    [data getBytes:&wDuration range:NSMakeRange(14, 3)];
    _rower.workoutDurationInSeconds = (float)wDuration * 0.01f;
    
    // duration type
    uint8_t dType;
    [data getBytes:&dType range:NSMakeRange(17, 1)];
    _rower.workoutDurationType = (DurationTypes)dType;
    
    // drag factor
    uint8_t drag;
    [data getBytes:&drag range:NSMakeRange(18, 1)];
    _rower.dragFactor = (int)drag;
    
    if (YES) {
        DDLogVerbose(@"t:%.1fs \t dst: %.1fm, wktTp: %@, intTp: %@, wktSt: %@, row: %@, stk: %@, wktDurTp: %@ ",
                     _rower.elapsedTimeInSeconds,
                     _rower.distanceInMeters,
                     NSStringFromWorkoutType(_rower.workoutType),
                     NSStringFromIntervalType(_rower.intervalType),
                     NSStringFromWorkoutState(_rower.workoutState),
                     NSStringFromRowingState(_rower.rowingState),
                     NSStringFromStrokeState(_rower.strokeState),
                     NSStringFromDurationType(_rower.workoutDurationType)
                     );

    }
}


Re: Incorrect Data being sent via BT LE? (Firmware Bug?)

Posted: July 28th, 2015, 1:16 pm
by dxpack
I suggest looking into revising your method for extracting the data bytes into UInt32. Sorry, I'm not entirely familiar with ObjC. I noticed your earlier forum post using getBytes:range:, attempted to replicate it in Swift and found I was getting bogus values - appeared to be memory access related, instead of debugging it I simply reverted to my original code that was working.

Code: Select all

var values = Array<UInt8>(count:data.length, repeatedValue:0) // Mutable Array
data.getBytes(&values, length:data.length)
let time: UInt32 = (values.count <  3) ? 0 : UInt32(values[0]) + UInt32(values[1])  * 256 + UInt32(values[2])  * 65536
let distance: UInt32 = (values.count <  6) ? 0 : UInt32(values[3]) + UInt32(values[4])  * 256 + UInt32(values[5])  * 65536 
let wType: UInt8 = (values.count <  7) ? 0 : values[6]
// etc

// or as Doubles (float):

var values = Array<UInt8>(count:data.length, repeatedValue:0) // Mutable Array
data.getBytes(&values, length:data.length)
let dValues = values.map({ return Double($0) })
_rower.elapsedTime = (dValues.count <  3) ? 0.0 : (dValues[0] + dValues[1]  * 256 + dValues[2]  * 65536) / 100
_rower.distanceInMeters = (dValues.count <  6) ? 0.0 : (dValues[3] + dValues[4]  * 256 + dValues[5]  * 65536) / 10
// etc

Re: Incorrect Data being sent via BT LE? (Firmware Bug?)

Posted: July 30th, 2015, 4:11 am
by horseshoe7
It was because I wasn't initializing those uint32_t with a value of 0. So it was using some bogus memory value for the 4th byte.