-
Notifications
You must be signed in to change notification settings - Fork 12
Code Autogeneration
The code is autogenerated from the fitgenparser.py utility
It parses the Profiles.xlsx into
-
TypeObjects for each type on the Types tab, -
MessageObjects for each message from the Messages tab linking each fields asFieldobject with the correctType - a
ContextObject to access types, and messages
The parser file naming convention is such that
-
function start with either
swiftorobjcdepending on the language they generate -
function then indicate what they generate:
-
fnamea function name -
funca function -
stmta statement -
expran expression
-
Note that the parser assign for each type in the excel file a number which will be used internally to identify given types with an int value.
This file will be autogenerate and contains
This extension will define a constant for each known message num as well as a name() function to return the String for the name of the message.
This is generated by swift_stmt_extension
This function is a switch on each mesg_num that in return calls the swift function generated to create the Date, Double or string dictionary from the c-structure the parser populated.
As an example the code to generate the file_id message from a uptr from a FIT_MESG buffer pointer is
case 0: // file_id
uptr.withMemoryRebound(to: FIT_FILE_ID_MESG.self, capacity: 1) {
rv = FitMessage( mesg_num: 0,
mesg_values: rzfit_swift_value_dict_for_file_id(ptr: $0),
mesg_enums: rzfit_swift_string_dict_for_file_id(ptr: $0),
mesg_dates: rzfit_swift_date_dict_for_file_id(ptr: $0))
}Each function creating the dictionaries will deference a value from the structure and convert it to the proper swift type either by a type cast or in the case of a Fit Type by calling the appropriate function. Note that in the case of fields whose value or type depend on another field it will handle it properly, as in the following example for file_id handling the field product
func rzfit_swift_string_dict_for_file_id( ptr : UnsafePointer<FIT_FILE_ID_MESG>) -> [String:String] {
var rv : [String:String] = [:]
var x : FIT_FILE_ID_MESG = ptr.pointee
let product_name = withUnsafeBytes(of: &x.product_name) { (rawPtr) -> String in
let ptr = rawPtr.baseAddress!.assumingMemoryBound(to: CChar.self)
return String(cString: ptr)
}
if !product_name.isEmpty {
rv[ "product_name" ] = product_name
}
if( x.manufacturer != FIT_UINT16_INVALID ) {
rv[ "manufacturer" ] = rzfit_swift_string_from_manufacturer(x.manufacturer)
}
if( x.product != FIT_UINT16_INVALID ) {
if x.manufacturer == 263 { // favero_electronics
rv[ "favero_product" ] = rzfit_swift_string_from_favero_product(FIT_UINT16(x.product))
}else if x.manufacturer == 1 { // garmin
rv[ "garmin_product" ] = rzfit_swift_string_from_garmin_product(FIT_UINT16(x.product))
}else if x.manufacturer == 15 { // dynastream
rv[ "garmin_product" ] = rzfit_swift_string_from_garmin_product(FIT_UINT16(x.product))
}else if x.manufacturer == 13 { // dynastream_oem
rv[ "garmin_product" ] = rzfit_swift_string_from_garmin_product(FIT_UINT16(x.product))
}else if x.manufacturer == 89 { // tacx
rv[ "garmin_product" ] = rzfit_swift_string_from_garmin_product(FIT_UINT16(x.product))
}
}
}The .generic parsing is mostly written in objective-c because it is easier to do generic typecasting of addresses in a buffer in c than swift, some of the swift conversion function of message number and field number are also generated in objective-c.
In addition, it generates functions that provide information about fields in a structure FIT_FIELD_INFO are also generated. These will return the scale, offset, fit_type, unit and some flag whether a field is a date or has dependencies to another field. This information is auto generated from the Profile.xlsx file and accounts for field that depend on the value of other fields.
For fields with dependence on reference fields, it will use the current value of FIT_INTERP_FIELD to try to extract the reference field value. The auto generated function look like the following:
static FIT_FIELD_INFO rzfit_objc_field_info_for_file_id(FIT_UINT16 field, FIT_INTERP_FIELD * interp){
switch( field ){
case 0: return (FIT_FIELD_INFO){.scale = 0, .offset = 0, .fit_type = 1, .fit_unit = 0, .fit_flag = 0 }; // type
case 1: return (FIT_FIELD_INFO){.scale = 0, .offset = 0, .fit_type = 58, .fit_unit = 0, .fit_flag = 0 }; // manufacturer
case 2: // product
{
FIT_UINT32 manufacturer = fit_interp_string_value(interp, 1);
if( manufacturer == 263 ){ // favero_electronics
return (FIT_FIELD_INFO){.scale = 0, .offset = 0, .fit_type = 161, .fit_unit = 0, .fit_flag = 0 };
}else if( manufacturer == 1 ){ // garmin
return (FIT_FIELD_INFO){.scale = 0, .offset = 0, .fit_type = 59, .fit_unit = 0, .fit_flag = 0 };
}else if( manufacturer == 15 ){ // dynastream
return (FIT_FIELD_INFO){.scale = 0, .offset = 0, .fit_type = 59, .fit_unit = 0, .fit_flag = 0 };
}else if( manufacturer == 13 ){ // dynastream_oem
return (FIT_FIELD_INFO){.scale = 0, .offset = 0, .fit_type = 59, .fit_unit = 0, .fit_flag = 0 };
}else if( manufacturer == 89 ){ // tacx
return (FIT_FIELD_INFO){.scale = 0, .offset = 0, .fit_type = 59, .fit_unit = 0, .fit_flag = 0 };
}
return (FIT_FIELD_INFO){.scale = 0, .offset = 0, .fit_type = FIT_TYPE_PENDING, .fit_unit = 0, .fit_flag = 0 };
}
case 3: return (FIT_FIELD_INFO){.scale = 0, .offset = 0, .fit_type = 0, .fit_unit = 0, .fit_flag = 0 }; // serial_number
case 4: return (FIT_FIELD_INFO){.scale = 0, .offset = 0, .fit_type = 6, .fit_unit = 0, .fit_flag = 1 }; // time_created
case 5: return (FIT_FIELD_INFO){.scale = 0, .offset = 0, .fit_type = 0, .fit_unit = 0, .fit_flag = 0 }; // number
case 8: return (FIT_FIELD_INFO){.scale = 0, .offset = 0, .fit_type = 0, .fit_unit = 0, .fit_flag = 0 }; // product_name
default: return (FIT_FIELD_INFO){.scale = 0, .offset = 0, .fit_type = 0, .fit_unit = 0, .fit_flag = 0 };
}
}