Open skaterSteve opened 6 years ago
Hi Stave,
When you create a custom feature you have to:
To crate a valid extension of the class BlueSTSDKFeature you have to:
-(instancetype) initWhitNode:(BlueSTSDKNode *)node{
self = [super initWhitNode:node name:FEATURE_NAME];
return self;
}
or in swift
public override init(whitNode node: BlueSTSDKNode) {
super.init(whitNode: node, name: MyFeature.FEATURE_NAME)
}
-(NSArray<BlueSTSDKFeatureField*>*) getFieldsDesc{
return @[[BlueSTSDKFeatureField createWithName:FEATURE_DATA_NAME
unit:FEATURE_UNIT
type:FEATURE_TYPE
min:@FEATURE_MIN
max:@FEATURE_MAX]];
}
or in Swift:
public override func getFieldsDesc() -> [BlueSTSDKFeatureField] {
return [BlueSTSDKFeatureField(name: MyFeature.DATA_NAME,
unit: MyFeature.DATA_MIN,
type: .uInt8,
min: NSNumber(value: MyFeature.DATA_MIN),
max: NSNumber(value: MyFeature.DATA_MAX))]
}
Implement the extractData method: this method is called each time the SDK receives a notification (or a read) from your feature and its responsibility is to parse the bytes and extract the actual values that the node sent, and pack it into a BlueSTSDKSample object that will be notified to the user thought the BlueSTSDKFeatureDeletage. in theory a single characteristics can export multiple Feature, so this method has an offset parameter that tell you where the unparsed data starts. a simple implementation can be:
-(BlueSTSDKExtractResult*) extractData:(uint64_t)timestamp data:(NSData*)rawData dataOffset:(uint32_t)offset{
if(rawData.length-offset < 2){
@throw [NSException
exceptionWithName:BLUESTSDK_LOCALIZE(@"Invalid data",nil)
reason:BLUESTSDK_LOCALIZE(@"The feature need almost 2 byte for extract the data",nil)
userInfo:nil];
}//if
float angle = [rawData extractLeUInt16FromOffset:offset]/100.0f;
NSArray *data = @[@(angle)];
BlueSTSDKFeatureSample *sample = [BlueSTSDKFeatureSample sampleWithTimestamp:timestamp data:data ];
return [BlueSTSDKExtractResult resutlWithSample:sample nReadData:2];
}
or
public override func extractData(_ timestamp: UInt64, data: Data, dataOffset offset: UInt32) -> BlueSTSDKExtractResult {
if ((data.count - Int(offset)) < 2) {
NSException(name: NSExceptionName(rawValue: "Invalid Data"),
reason: "No Bytes",
userInfo: nil).raise()
return BlueSTSDKExtractResult(whitSample: nil, nReadData: 0)
}
let RSSIValue = NSNumber(value: (data as NSData).extractLeUInt16(fromOffset: UInt(offset)/100.0))
let sample = BlueSTSDKFeatureSample(timestamp: timestamp, data: [RSSIValue])
return BlueSTSDKExtractResult(whitSample: sample, nReadData: 2)
}
note: the first 2 bytes of the notification will be used to extract a timestamp.. this field should be an increasing number that can be use to know if a sample is more recent than another or when the sample was acquired, if you don't care you can extend BlueSTSDKDeviceTimestampFeature instead of BlueSTSDKFeature, in this case the timestamp value will be the current time and you can parse also the first 2 bytes of the notification (offset will start from 0 instead of from 2)
for example:
+ (int32_t)getHeartRate:(BlueSTSDKFeatureSample *)sample {
if(sample.data.count>=HEART_RATE_INDEX)
return [sample.data[HEART_RATE_INDEX] intValue];
return -1;
}
now that you have a your custom Feature you have to register it. there are 2 way of doing that. If you are using an "ST" characteristics, so something like: XXXXX-0001-11e1-ac36-0002a5d5c51b you have to use the addFeatureForNode before start the discovery like:
let charMap = [
0x00080000 : MyFeature1.self,
0x00040000 : MyFeature2.self,
0x00008000 : MyFeature3..self
]
let nodeId = 0x02
BlueSTSDKManager.sharedInstance().addFeature(forNode: nodeId, features: charMap)
note that each key associated to a feature must have only 1 bit to 1..
By the way this is not your case and I'm thinking to deprecate this way in the next update..
In you case you have to register directly the characteristics/feature pair to the node before connecting, using the method:
(NSDictionary<CBUUID *, NSArray<Class> * > *)getManagedCharacteristics {
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
CBUUID *uuid = [CBUUID UUIDWithString:@"0a000000-000D-11e1-ac36-0002a5d5c51b"];
[dict add:uuid feature:[MyFeature1 class]];
// add all your Features
return dict;
}
....
[node addExternalCharacteristics:[ self getManagedCharacteristics]];
...
or in Swift:
public func getManagedCharacteristics() -> [CBUUID:[AnyClass]]{
var temp:[CBUUID:[AnyClass]]=[:]
temp.updateValue([MyFeature1.self],
forKey: CBUUID(string: "0a000000-000D-11e1-ac36-0002a5d5c51b"))
// add all your Features
return temp;
}
...
node.addExternalCharacteristics(getManagedCharacteristics());
...
I hope that this is more clear.
Best Regards Giovanni
Hi Giovanni,
Thank you for responding so quickly and the the detailed description.
I am confused by Step 1 - my problem is importing initWhitNode to create the constructor properly. I have a single view application right now for simplicity.
When I place the function from Step 1, my error is:
No visible @interface for 'UIViewController' declares the selector 'initWhitNode:name:'
I am placing this at:
`#import "BlueSTSDKFeature.h" ...
@interface ViewController() <BlueSTSDKFeatureDelegate,......> @end
@implementation ViewController { BlueSTSDKManager mManager; NSArray mNodes; ..... } .....
-(void)viewDidLoad { .....} . .
Xcode doesn't seem to recognize that method in this context. I tried adding to declarations to headers and @interface and within @implementation... but that didn't make error go away.
I did notice that in viewDidLoad if I write:
mNodes[0] initWhitNode: (.....)
This method appears! But not the one with name as a function.
I am not very familiar with how to do add a method to a class, so please excuse me if this is very obvious.
Best Regards, Steve
Hi Steve,
You don't have to create a Feature instance, the sdk will allocate it for you, when you connect to the node. You have to create a new class different from your view controller, better if in its .h/.m file. Take a look to a simple one like the Compass to create your one: header, source
Best Regards Giovanni
Hi Giovanni,
I apologize for such a delayed response... Thank you for pointing me to the Compass as reference, this makes sense to me now!
Hello,
I am trying to add new features so that I can use in the BlueSTSDK iOS on the SensorTile. I am using ALLMEMS1_ST firmware.
I have defined and added a new Service and corresponding Characteristics. I took care to follow the patterns in the ALLMEMS1_ST uuid definitions. I didn't choose 0x10 as uuid[15] as in the example because I noticed COPY_MIC_ANGLE_UUID ( is 100000000-0000-11e1-ac36-0002a5d5c51b) in case that mattered.
I have defined as such:
The API is able to discover the service! I am trying to follow "How to add a new Feature" section in the Readme. Would you please clarify my confusions on step 1 and 2?
Thank you!