diff --git a/a2l/characteristic.go b/a2l/characteristic.go index b6c43b3..d7a882b 100644 --- a/a2l/characteristic.go +++ b/a2l/characteristic.go @@ -20,6 +20,7 @@ type Characteristic struct { //Deposit is the identifier of the corresponding record layout Deposit string DepositSet bool + encoding encodingEnum maxDiff float64 maxDiffSet bool conversion string @@ -45,7 +46,7 @@ type Characteristic struct { guardRails guardRailsKeyword ifData []IfData mapList []MapList - matrixDim matrixDim + MatrixDim MatrixDim maxRefresh MaxRefresh modelLink modelLink number Number @@ -132,6 +133,13 @@ forLoop: break forLoop } log.Info().Msg("characteristic displayIdentifier successfully parsed") + case encodingToken: + c.encoding, err = parseEncodingEnum(tok) + if err != nil { + log.Err(err).Msg("characteristic encoding could not be parsed") + break forLoop + } + log.Info().Msg("characteristic encoding successfully parsed") case ecuAddressExtensionToken: c.ecuAddressExtension, err = parseECUAddressExtension(tok) if err != nil { @@ -188,7 +196,7 @@ forLoop: c.mapList = append(c.mapList, buf) log.Info().Msg("characteristic mapList successfully parsed") case matrixDimToken: - c.matrixDim, err = parseMatrixDim(tok) + c.MatrixDim, err = parseMatrixDim(tok) if err != nil { log.Err(err).Msg("characteristic matrixDim could not be parsed") break forLoop diff --git a/a2l/compu_method.go b/a2l/compu_method.go index 16ef8d8..25a4913 100644 --- a/a2l/compu_method.go +++ b/a2l/compu_method.go @@ -2,6 +2,7 @@ package a2l import ( "errors" + "math" "github.com/rs/zerolog/log" ) @@ -25,6 +26,41 @@ type compuMethod struct { statusStringRef statusStringRef } +func (cm *compuMethod) convDecToPhy(dec float64) (float64, error) { + var err error + switch cm.conversionType { + case Identical: + return dec, nil + case Form: + //implement later. + case Linear: + if !(cm.coeffsLinear.aSet && cm.coeffsLinear.bSet) { + err = errors.New("coeffsLinear not set in compuMethod: " + cm.name) + log.Err(err).Msg("decimal value could not be converted") + return 0, err + } + return cm.coeffsLinear.a*dec + cm.coeffsLinear.b, err + case RatFunc: + if !(cm.coeffs.aSet && cm.coeffs.bSet && cm.coeffs.cSet && cm.coeffs.dSet && cm.coeffs.eSet && cm.coeffs.fSet) { + err = errors.New("coeffs not set in compuMethod: " + cm.name) + log.Err(err).Msg("decimal value could not be converted") + return 0, err + } + phy, err := cm.calcRatFunc(dec) + if err != nil { + log.Err(err).Msg("decimal value could not be converted") + return phy, err + } + case TabIntp: + case TabNointp: + case TabVerb: + default: + err = errors.New("conversion Type undefined in compuMethod: " + cm.name) + log.Err(err).Msg("decimal value could not be converted") + return 0, err + } +} + func parseCompuMethod(tok *tokenGenerator) (compuMethod, error) { cm := compuMethod{} var err error @@ -77,13 +113,13 @@ forLoop: log.Info().Msg("compuMethod statusStringRef successfully parsed") default: if tok.current() == emptyToken { - err = errors.New("unexpected end of file") + err = errors.New("unedecpected end of file") log.Err(err).Msg("compuMethod could not be parsed") break forLoop } else if tok.current() == endCompuMethodToken { break forLoop } else if isKeyword(tok.current()) { - err = errors.New("unexpected token " + tok.current()) + err = errors.New("unedecpected token " + tok.current()) log.Err(err).Msg("compuMethod could not be parsed") break forLoop } else if !cm.nameSet { @@ -115,3 +151,42 @@ forLoop: } return cm, err } + +func (cm *compuMethod) calcRatFunc(dec float64) (float64, error) { + //following formula defines f(Physical) = Decimal + //y = (axx + bx + c) / (dxx + ex + f) + //inverted fi(Decimal) = Physical + //y = (e dec - b)/(2 (a - d dec)) ± sqrt((e dec - b)^2 - 4 (d dec - a) (f dec - c))/(2 (a - d dec)) + firstDivisor := (2 * (cm.coeffs.a - cm.coeffs.d*dec)) + if firstDivisor == 0 { + err = errors.New("rationality function cannot be computed(zero divisor) for compuMethod: " + cm.name) + log.Err(err).Msg("decimal value could not be converted") + return 0, err + } + secondDivisorPositive := (2 * (cm.coeffs.a - cm.coeffs.d*dec)) + + math.Sqrt(math.Pow((cm.coeffs.e*dec-cm.coeffs.b), 2)-4*(cm.coeffs.d*dec-cm.coeffs.a)*(cm.coeffs.f*dec-cm.coeffs.c))/firstDivisor + secondDivisorNegative := (2 * (cm.coeffs.a - cm.coeffs.d*dec)) - + math.Sqrt(math.Pow((cm.coeffs.e*dec-cm.coeffs.b), 2)-4*(cm.coeffs.d*dec-cm.coeffs.a)*(cm.coeffs.f*dec-cm.coeffs.c))/firstDivisor + + if secondDivisorPositive != 0 && secondDivisorNegative != 0 { + plusVal := (cm.coeffs.e*dec - cm.coeffs.b) / secondDivisorPositive + minusVal := (cm.coeffs.e*dec - cm.coeffs.b) / secondDivisorNegative + testVal := (cm.coeffs.a*plusVal*plusVal + cm.coeffs.b*plusVal + cm.coeffs.c) / (cm.coeffs.d*plusVal*plusVal + cm.coeffs.e*plusVal + cm.coeffs.f) + if testVal == dec { + return plusVal, err + } else { + return minusVal, err + } + } else if secondDivisorPositive != 0 { + plusVal := (cm.coeffs.e*dec - cm.coeffs.b) / secondDivisorPositive + return plusVal, err + } else if secondDivisorNegative != 0 { + minusVal := (cm.coeffs.e*dec - cm.coeffs.b) / secondDivisorNegative + return minusVal, err + } else { + err = errors.New("rationality function cannot be computed(zero divisor) for compuMethod: " + cm.name) + log.Err(err).Msg("decimal value could not be converted") + return 0, err + } + +} diff --git a/a2l/enums.go b/a2l/enums.go index 3e86cef..255d7d7 100644 --- a/a2l/enums.go +++ b/a2l/enums.go @@ -470,9 +470,28 @@ const ( //Identical defines a OneToOne conversion from hex to decimal Identical conversionTypeEnum = identicalToken Form conversionTypeEnum = formToken - Linear conversionTypeEnum = linearToken - RatFunc conversionTypeEnum = ratFuncToken - TabIntp conversionTypeEnum = tabIntpToken + /*Linear function of the following type: + f(x)=ax + b + for which: + PHYS=f(INT) + The coefficients a and b have to be + specified by the COEFFS_LINEAR + keyword.*/ + Linear conversionTypeEnum = linearToken + /*RatFunc is a fractional rational function of the following type: + f(x)=(axx + bx + c)/(dxx + ex + f) + for which: + INT = f(PHYS) + Coefficients a, b, c, d, e, f have to be specified by the COEFFS keyword. + Note: For linear functions, use the ConversionType LINEAR, + for ident functions the ConversionType IDENT. + For non linear functions it must be possible to invert the formula within the limits of the + AXIS_PTS, CHARACTERISTIC or MEASUREMENT where it is used. + Otherwise use the ConversionType FORM.*/ + RatFunc conversionTypeEnum = ratFuncToken + //TabIntp defines a table with interpolation + TabIntp conversionTypeEnum = tabIntpToken + //TabIntp defines a table withOut interpolation TabNointp conversionTypeEnum = tabNointpToken //Tab Verb is a table to convert numeric values into strings. e.g.: 1 -> "True" TabVerb conversionTypeEnum = tabVerbToken diff --git a/a2l/instance.go b/a2l/instance.go index 2050c5a..d77b856 100644 --- a/a2l/instance.go +++ b/a2l/instance.go @@ -21,7 +21,7 @@ type instance struct { displayIdentifier DisplayIdentifier ecuAddressExtension ecuAddressExtension ifData []IfData - matrixDim matrixDim + matrixDim MatrixDim maxRefresh MaxRefresh modelLink modelLink overwrite overwrite diff --git a/a2l/matrix_dim.go b/a2l/matrix_dim.go index c5520e7..47af7a8 100644 --- a/a2l/matrix_dim.go +++ b/a2l/matrix_dim.go @@ -7,24 +7,28 @@ import ( "github.com/rs/zerolog/log" ) -type matrixDim struct { - xDim uint16 - xDimSet bool - yDim uint16 - yDimSet bool - zDim uint16 - zDimSet bool +type MatrixDim struct { + DimX uint16 + DimXSet bool + DimY uint16 + DimYSet bool + DimZ uint16 + DimZSet bool + Dim4 uint16 + Dim4Set bool + Dim5 uint16 + Dim5Set bool } -//parseMatrixDim parses the matrix dimensions of higher order Characteristics. -//this function is special because it is the only function that utilizes tokenizer.previous(). -//this is the case because matrixDim is not clearly defined in earlier a2l standards (e.g. 1.6.0). -//therefore it is possible to describe a curve with "MATRIX_DIM 1" and "MATRIX_DIM 1 0 0". -//so the parser checks whether the token is a keyword in which case it rolls back the tokenizer one value and exits -//or if it finds a number that can be parsed. -//if it could parse x, y and z dim it will exit normally. -func parseMatrixDim(tok *tokenGenerator) (matrixDim, error) { - md := matrixDim{} +// parseMatrixDim parses the matrix dimensions of higher order Characteristics. +// this function is special because it is the only function that utilizes tokenizer.previous(). +// this is the case because matrixDim is not clearly defined in earlier a2l standards (e.g. 1.6.0). +// therefore it is possible to describe a curve with "MATRIX_DIM 1" and "MATRIX_DIM 1 0 0". +// so the parser checks whether the token is a keyword in which case it rolls back the tokenizer one value and exits +// or if it finds a number that can be parsed. +// if it could parse x, y and z dim it will exit normally. +func parseMatrixDim(tok *tokenGenerator) (MatrixDim, error) { + md := MatrixDim{} var err error forLoop: for { @@ -39,34 +43,52 @@ forLoop: tok.previous() log.Info().Str("previous token", tok.current()).Msg("matrixDim rolled back to:") break forLoop - } else if !md.xDimSet { + } else if !md.DimXSet { var buf uint64 buf, err = strconv.ParseUint(tok.current(), 10, 16) if err != nil { log.Err(err).Msg("matrixDim xDim could not be parsed") break forLoop } - md.xDim = uint16(buf) - md.xDimSet = true + md.DimX = uint16(buf) + md.DimXSet = true log.Info().Msg("matrixDim xDim successfully parsed") - } else if !md.yDimSet { + } else if !md.DimYSet { var buf uint64 buf, err = strconv.ParseUint(tok.current(), 10, 16) if err != nil { log.Err(err).Msg("matrixDim yDim could not be parsed") break forLoop } - md.yDim = uint16(buf) + md.DimY = uint16(buf) log.Info().Msg("matrixDim yDim successfully parsed") - } else if !md.zDimSet { + } else if !md.DimZSet { var buf uint64 buf, err = strconv.ParseUint(tok.current(), 10, 16) if err != nil { log.Err(err).Msg("matrixDim zDim could not be parsed") break forLoop } - md.zDim = uint16(buf) + md.DimZ = uint16(buf) log.Info().Msg("matrixDim zDim successfully parsed") + } else if !md.Dim4Set { + var buf uint64 + buf, err = strconv.ParseUint(tok.current(), 10, 16) + if err != nil { + log.Err(err).Msg("matrixDim 4Dim could not be parsed") + break forLoop + } + md.Dim4 = uint16(buf) + log.Info().Msg("matrixDim 4Dim successfully parsed") + } else if !md.Dim5Set { + var buf uint64 + buf, err = strconv.ParseUint(tok.current(), 10, 16) + if err != nil { + log.Err(err).Msg("matrixDim 5Dim could not be parsed") + break forLoop + } + md.Dim5 = uint16(buf) + log.Info().Msg("matrixDim 5Dim successfully parsed") break forLoop } } diff --git a/a2l/measurement.go b/a2l/measurement.go index a78b346..199dfbe 100644 --- a/a2l/measurement.go +++ b/a2l/measurement.go @@ -38,7 +38,7 @@ type measurement struct { functionList FunctionList ifData []IfData layout layout - matrixDim matrixDim + matrixDim MatrixDim maxRefresh MaxRefresh modelLink modelLink physUnit physUnit diff --git a/a2l/structure_component.go b/a2l/structure_component.go index 5457861..6d872cd 100644 --- a/a2l/structure_component.go +++ b/a2l/structure_component.go @@ -15,7 +15,7 @@ type structureComponent struct { addressOffsetSet bool addressType addrTypeEnum layout layout - matrixDim matrixDim + matrixDim MatrixDim symbolTypeLink symbolTypeLink } diff --git a/a2l/tokens.go b/a2l/tokens.go index 1a74f15..35dac5a 100644 --- a/a2l/tokens.go +++ b/a2l/tokens.go @@ -140,6 +140,7 @@ const ecuCalibrationOffsetToken = "ECU_CALIBRATION_OFFSET" const ecuToken = "ECU" const eepromToken = "EEPROM" const emptyToken = "" +const encodingToken = "ENCODING" const endA2mlToken = "/end A2ML" const endAnnotationTextToken = "/end ANNOTATION_TEXT" const endAnnotationToken = "/end ANNOTATION" @@ -538,6 +539,7 @@ var keywordMap = map[string]uint8{ "/end VARIANT_CODING": 0, "/end VIRTUAL_CHARACTERISTIC": 0, "/end VIRTUAL": 0, + "ENCODING": 0, "EPK": 0, "ERROR_MASK": 0, "EXTENDED_LIMITS": 0, diff --git a/a2l/type_def_characteristic.go b/a2l/type_def_characteristic.go index e8e8da9..e1f7cf6 100644 --- a/a2l/type_def_characteristic.go +++ b/a2l/type_def_characteristic.go @@ -31,7 +31,7 @@ type typeDefCharacteristic struct { encoding encodingEnum extendedLimits extendedLimits format format - matrixDim matrixDim + matrixDim MatrixDim number Number physUnit physUnit stepSize StepSize diff --git a/a2l/type_def_measurement.go b/a2l/type_def_measurement.go index 74fa282..d644333 100644 --- a/a2l/type_def_measurement.go +++ b/a2l/type_def_measurement.go @@ -31,7 +31,7 @@ type typeDefMeasurement struct { errorMask errorMask format format layout layout - matrixDim matrixDim + matrixDim MatrixDim physUnit physUnit } diff --git a/axis_pts.go b/axis_pts.go index 9f0ecb8..e5a19b9 100644 --- a/axis_pts.go +++ b/axis_pts.go @@ -7,171 +7,200 @@ import ( "github.com/rs/zerolog/log" ) +//check access type. DIRECT is the most used. Just read value from a given address. +//in case other access types are set this gets more complicated as either offsets or pointers are leveraged to +//define the position of the calibration objects. + // getAxisPointsX retrieves Axis Points according to their layout specified within the record layout and their values as calibrated in the hex file -func (cv *CharacteristicValues) getAxisPointsX(cd *CalibrationData, rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { - var val []interface{} - var buf interface{} +func (cv *CharacteristicValues) getAxisPointsX(cd *CalibrationData, rl *a2l.RecordLayout, curPos *uint32) ([]float64, error) { + var val []float64 + var bufByte []byte + var bufFloat float64 var err error - var i uint32 - var noAxisPts uint32 + var i int64 + var noAxisPts int64 if rl.FixNoAxisPtsX.NumberOfAxisPointsSet { - noAxisPts = uint32(rl.FixNoAxisPtsX.NumberOfAxisPoints) + noAxisPts = int64(rl.FixNoAxisPtsX.NumberOfAxisPoints) } else if !rl.FixNoAxisPtsX.NumberOfAxisPointsSet { - buf, isInt := cv.noAxisPtsXValue.(int) - if !isInt { - err = errors.New("could not convert number of axisPts datatype to int") + if cv.noAxisPtsXValue <= 0 { + err = errors.New("number of axisPts is smaller or equal to zero") log.Err(err).Msg("could not retrieve NoAxisPointsX value") return nil, err } - noAxisPts = uint32(buf) + noAxisPts = cv.noAxisPtsXValue } else { err = errors.New("number of axis points could not be determined") log.Err(err).Msg("could not convert axisPointsX values") return nil, err } for i = 0; i < noAxisPts; i++ { - buf, err = cd.getValue(curPos, rl.AxisPtsX.Datatype, rl) + bufByte, err = cd.getValue(curPos, rl.AxisPtsX.Datatype, rl) + if err != nil { + log.Err(err).Msg("could not retrieve axisPointsX value") + return nil, err + } + bufFloat, err = cd.convertByteSliceToDatatype(bufByte, rl.AxisPtsX.Datatype) if err != nil { log.Err(err).Msg("could not retrieve axisPointsX value") return nil, err } - val = append(val, buf) + val = append(val, bufFloat) *curPos += uint32(rl.AxisPtsX.Datatype.GetDatatypeLength()) } return val, err } // getAxisPointsY retrieves Axis Points according to their layout specified within the record layout and their values as calibrated in the hex file -func (cv *CharacteristicValues) getAxisPointsY(cd *CalibrationData, rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { - var val []interface{} - var buf interface{} +func (cv *CharacteristicValues) getAxisPointsY(cd *CalibrationData, rl *a2l.RecordLayout, curPos *uint32) ([]float64, error) { + var val []float64 + var bufByte []byte + var bufFloat float64 var err error - var i uint32 - var noAxisPts uint32 + var i int64 + var noAxisPts int64 if rl.FixNoAxisPtsY.NumberOfAxisPointsSet { - noAxisPts = uint32(rl.FixNoAxisPtsY.NumberOfAxisPoints) + noAxisPts = int64(rl.FixNoAxisPtsY.NumberOfAxisPoints) } else if !rl.FixNoAxisPtsY.NumberOfAxisPointsSet { - buf, isInt := cv.noAxisPtsYValue.(int) - if !isInt { - err = errors.New("could not convert number of axisPts datatype to int") + if cv.noAxisPtsYValue <= 0 { + err = errors.New("number of axisPts is smaller or equal to zero") log.Err(err).Msg("could not retrieve NoAxisPointsY value") return nil, err } - noAxisPts = uint32(buf) + noAxisPts = cv.noAxisPtsYValue } else { err = errors.New("number of axis points could not be determined") log.Err(err).Msg("could not convert axisPointsY values") return nil, err } for i = 0; i < noAxisPts; i++ { - buf, err = cd.getValue(curPos, rl.AxisPtsY.Datatype, rl) + bufByte, err = cd.getValue(curPos, rl.AxisPtsY.Datatype, rl) if err != nil { log.Err(err).Msg("could not retrieve axisPointsY value") return nil, err } - val = append(val, buf) + bufFloat, err = cd.convertByteSliceToDatatype(bufByte, rl.AxisPtsY.Datatype) + if err != nil { + log.Err(err).Msg("could not retrieve axisPointsY value") + return nil, err + } + val = append(val, bufFloat) *curPos += uint32(rl.AxisPtsY.Datatype.GetDatatypeLength()) } return val, err } // getAxisPointsZ retrieves Axis Points according to their layout specified within the record layout and their values as calibrated in the hex file -func (cv *CharacteristicValues) getAxisPointsZ(cd *CalibrationData, rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { - var val []interface{} - var buf interface{} +func (cv *CharacteristicValues) getAxisPointsZ(cd *CalibrationData, rl *a2l.RecordLayout, curPos *uint32) ([]float64, error) { + var val []float64 + var bufByte []byte + var bufFloat float64 var err error - var i uint32 - var noAxisPts uint32 + var i int64 + var noAxisPts int64 if rl.FixNoAxisPtsZ.NumberOfAxisPointsSet { - noAxisPts = uint32(rl.FixNoAxisPtsZ.NumberOfAxisPoints) + noAxisPts = int64(rl.FixNoAxisPtsZ.NumberOfAxisPoints) } else if !rl.FixNoAxisPtsZ.NumberOfAxisPointsSet { - buf, isInt := cv.noAxisPtsZValue.(int) - if !isInt { - err = errors.New("could not convert number of axisPts datatype to int") + if cv.noAxisPtsZValue <= 0 { + err = errors.New("number of axisPts is smaller or equal to zero") log.Err(err).Msg("could not retrieve NoAxisPointsZ value") return nil, err } - noAxisPts = uint32(buf) + noAxisPts = cv.noAxisPtsZValue } else { err = errors.New("number of axis points could not be determined") log.Err(err).Msg("could not convert axisPointsZ values") return nil, err } for i = 0; i < noAxisPts; i++ { - buf, err = cd.getValue(curPos, rl.AxisPtsZ.Datatype, rl) + bufByte, err = cd.getValue(curPos, rl.AxisPtsZ.Datatype, rl) if err != nil { log.Err(err).Msg("could not retrieve axisPointsZ value") return nil, err } - val = append(val, buf) + bufFloat, err = cd.convertByteSliceToDatatype(bufByte, rl.AxisPtsZ.Datatype) + if err != nil { + log.Err(err).Msg("could not retrieve axisPointsZ value") + return nil, err + } + val = append(val, bufFloat) *curPos += uint32(rl.AxisPtsZ.Datatype.GetDatatypeLength()) } return val, err } // getAxisPoints4 retrieves Axis Points according to their layout specified within the record layout and their values as calibrated in the hex file -func (cv *CharacteristicValues) getAxisPoints4(cd *CalibrationData, rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { - var val []interface{} - var buf interface{} +func (cv *CharacteristicValues) getAxisPoints4(cd *CalibrationData, rl *a2l.RecordLayout, curPos *uint32) ([]float64, error) { + var val []float64 + var bufByte []byte + var bufFloat float64 var err error - var i uint32 - var noAxisPts uint32 + var i int64 + var noAxisPts int64 if rl.FixNoAxisPts4.NumberOfAxisPointsSet { - noAxisPts = uint32(rl.FixNoAxisPts4.NumberOfAxisPoints) + noAxisPts = int64(rl.FixNoAxisPts4.NumberOfAxisPoints) } else if !rl.FixNoAxisPts4.NumberOfAxisPointsSet { - buf, isInt := cv.noAxisPts4Value.(int) - if !isInt { - err = errors.New("could not convert number of axisPts datatype to int") + if cv.noAxisPts4Value <= 0 { + err = errors.New("number of axisPts is smaller or equal to zero") log.Err(err).Msg("could not retrieve NoAxisPoints4 value") return nil, err } - noAxisPts = uint32(buf) + noAxisPts = cv.noAxisPts4Value } else { err = errors.New("number of axis points could not be determined") log.Err(err).Msg("could not convert axisPoints4 values") return nil, err } for i = 0; i < noAxisPts; i++ { - buf, err = cd.getValue(curPos, rl.AxisPts4.Datatype, rl) + bufByte, err = cd.getValue(curPos, rl.AxisPts4.Datatype, rl) + if err != nil { + log.Err(err).Msg("could not retrieve axisPoints4 value") + return nil, err + } + bufFloat, err = cd.convertByteSliceToDatatype(bufByte, rl.AxisPts4.Datatype) if err != nil { log.Err(err).Msg("could not retrieve axisPoints4 value") return nil, err } - val = append(val, buf) + val = append(val, bufFloat) *curPos += uint32(rl.AxisPts4.Datatype.GetDatatypeLength()) } return val, err } // getAxisPoints5 retrieves Axis Points according to their layout specified within the record layout and their values as calibrated in the hex file -func (cv *CharacteristicValues) getAxisPoints5(cd *CalibrationData, rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { - var val []interface{} - var buf interface{} +func (cv *CharacteristicValues) getAxisPoints5(cd *CalibrationData, rl *a2l.RecordLayout, curPos *uint32) ([]float64, error) { + var val []float64 + var bufByte []byte + var bufFloat float64 var err error - var i uint32 - var noAxisPts uint32 + var i int64 + var noAxisPts int64 if rl.FixNoAxisPts5.NumberOfAxisPointsSet { - noAxisPts = uint32(rl.FixNoAxisPts5.NumberOfAxisPoints) + noAxisPts = int64(rl.FixNoAxisPts5.NumberOfAxisPoints) } else if !rl.FixNoAxisPts5.NumberOfAxisPointsSet { - buf, isInt := cv.noAxisPts5Value.(int) - if !isInt { - err = errors.New("could not convert number of axisPts datatype to int") + if cv.noAxisPts5Value <= 0 { + err = errors.New("number of axisPts is smaller or equal to zero") log.Err(err).Msg("could not retrieve NoAxisPoints5 value") return nil, err } - noAxisPts = uint32(buf) + noAxisPts = cv.noAxisPts5Value } else { err = errors.New("number of axis points could not be determined") log.Err(err).Msg("could not convert axisPoints5 values") return nil, err } for i = 0; i < noAxisPts; i++ { - buf, err = cd.getValue(curPos, rl.AxisPts5.Datatype, rl) + bufByte, err = cd.getValue(curPos, rl.AxisPts5.Datatype, rl) + if err != nil { + log.Err(err).Msg("could not retrieve axisPoints5 value") + return nil, err + } + bufFloat, err = cd.convertByteSliceToDatatype(bufByte, rl.AxisPts5.Datatype) if err != nil { log.Err(err).Msg("could not retrieve axisPoints5 value") return nil, err } - val = append(val, buf) + val = append(val, bufFloat) *curPos += uint32(rl.AxisPts5.Datatype.GetDatatypeLength()) } return val, err diff --git a/calib_data.go b/calib_data.go index 3684c21..f9777bd 100644 --- a/calib_data.go +++ b/calib_data.go @@ -720,16 +720,19 @@ func (cd *CalibrationData) getValuesFromHex(cv *CharacteristicValues) { } } -func (cd *CalibrationData) getValue(curPos *uint32, dte a2l.DataTypeEnum, rl *a2l.RecordLayout) (interface{}, error) { +func (cd *CalibrationData) getValue(curPos *uint32, dte a2l.DataTypeEnum, rl *a2l.RecordLayout) ([]byte, error) { bytes, err := cd.getBytes(cd.getNextAlignedAddress(*curPos, dte, rl), uint32(dte.GetDatatypeLength())) if err != nil { log.Err(err).Msg("could not retrieve value as byteSlice") return nil, err } - data, err := cd.convertByteSliceToDatatype(bytes, dte) - if err != nil { - log.Err(err).Msg("could not convert byteSlice to dataType") - return nil, err - } - return data, nil + return bytes, nil +} + +func convertNumericToInt[num Numeric](n num) int64 { + return int64(n) +} + +func convertNumericToFloat[num Numeric](n num) float64 { + return float64(n) } diff --git a/characteristic_values.go b/characteristic_values.go index dcf3cea..1bf0876 100644 --- a/characteristic_values.go +++ b/characteristic_values.go @@ -1,47 +1,93 @@ package calibrationReader import ( + "errors" + "github.com/asap2Go/calibrationReader/a2l" + "github.com/rs/zerolog/log" ) type CharacteristicValues struct { characteristic *a2l.Characteristic recordLayout *a2l.RecordLayout - AxisXValues interface{} - AxisYValues interface{} - AxisZValues interface{} - Axis4Values interface{} - Axis5Values interface{} - distOpXValue interface{} - distOpYValue interface{} - distOpZValue interface{} - distOp4Value interface{} - distOp5Value interface{} + AxisXValues []float64 + AxisYValues []float64 + AxisZValues []float64 + Axis4Values []float64 + Axis5Values []float64 + distOpXValue int64 + distOpYValue int64 + distOpZValue int64 + distOp4Value int64 + distOp5Value int64 identificationValue interface{} - noAxisPtsXValue interface{} - noAxisPtsYValue interface{} - noAxisPtsZValue interface{} - noAxisPts4Value interface{} - noAxisPts5Value interface{} - noRescaleXValue interface{} - offsetXValue interface{} - offsetYValue interface{} - offsetZValue interface{} - offset4Value interface{} - offset5Value interface{} - shiftOpXValue interface{} - shiftOpYValue interface{} - shiftOpZValue interface{} - shiftOp4Value interface{} - shiftOp5Value interface{} - ValuesDec interface{} - ValuesPhy interface{} + noAxisPtsXValue int64 + noAxisPtsYValue int64 + noAxisPtsZValue int64 + noAxisPts4Value int64 + noAxisPts5Value int64 + noRescaleXValue int64 + offsetXValue int64 + offsetYValue int64 + offsetZValue int64 + offset4Value int64 + offset5Value int64 + shiftOpXValue int64 + shiftOpYValue int64 + shiftOpZValue int64 + shiftOp4Value int64 + shiftOp5Value int64 + ValuesBin [][]byte + ValuesPhy []float64 } -func (cv *CharacteristicValues) getCharacteristicValueDecimal() (interface{}, error) { - return nil, nil +//check access type. DIRECT is the most used. Just read value from a given address. +//in case other access types are set this gets more complicated as either offsets or pointers are leveraged to +//define the position of the calibration objects. +//for VALUE Type: just read one value at curPos +//for higher level objects: read the number of elements defined by the matrix dim or NoAxisPts fields with the direction (row, column, alternate, ...) specified. +//for applicable objects check whether STATIC_RECORD_LAYOUT and STATIC_ ADDRESS_OFFSET are set +//to determine how to read the FNC_Values correctly, this can lead to hard to detect errors when not implemented. + +func (cv *CharacteristicValues) getFncValues(cd *CalibrationData, rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { + if !rl.FncValues.DatatypeSet { + err := errors.New("fncValues datatype not set") + log.Err(err).Msg("could not determine datatype of FncValues of characteristic " + cv.characteristic.Name) + return nil, err + } + val, err := cv.getValuesByCharacteristicType(cd, rl, curPos) + if err != nil { + log.Err(err).Msg("could not retrieve fncValues value") + return nil, err + } + + return val, err } -func (cv *CharacteristicValues) getCharacteristicValuePhysical() (interface{}, error) { +func (cv *CharacteristicValues) getValuesByCharacteristicType(cd *CalibrationData, rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { + if !cv.characteristic.TypeSet { + err := errors.New("characteristic type not set") + log.Err(err).Msg("could not determine type of characteristic " + cv.characteristic.Name) + return nil, err + } + + switch cv.characteristic.Type { + case a2l.ASCII: + case a2l.Curve: + case a2l.Map: + case a2l.Cuboid: + case a2l.Cube4: + case a2l.Cube5: + case a2l.ValBlk: + case a2l.Value: + //ToDo: + case a2l.Derived: + case a2l.ExtendedSi: + default: + err := errors.New("characteristic type not defined") + log.Err(err).Msg("could not determine type of characteristic " + cv.characteristic.Name) + return nil, err + } + return nil, nil } diff --git a/offset_distance_op.go b/distOp.go similarity index 62% rename from offset_distance_op.go rename to distOp.go index 22bba22..b71553a 100644 --- a/offset_distance_op.go +++ b/distOp.go @@ -8,81 +8,106 @@ import ( ) // getDistOpX retrieves the distance operator according to its layout specified within the record layout and their values as calibrated in the hex file -func (cd *CalibrationData) getDistOpX(rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { +func (cd *CalibrationData) getDistOpX(rl *a2l.RecordLayout, curPos *uint32) (int64, error) { if !rl.DistOpX.DatatypeSet { err := errors.New("distOpX datatype not set") log.Err(err).Msg("could not retrieve distOpX value") - return nil, err + return 0, err } - val, err := cd.getValue(curPos, rl.DistOpX.Datatype, rl) + bufBytes, err := cd.getValue(curPos, rl.DistOpX.Datatype, rl) if err != nil { log.Err(err).Msg("could not retrieve distOpX value") - return nil, err + return 0, err + } + val, err := cd.convertByteSliceToDatatype(bufBytes, rl.DistOpX.Datatype) + if err != nil { + log.Err(err).Msg("could not retrieve distOpX value") + return 0, err } *curPos += uint32(rl.DistOpX.Datatype.GetDatatypeLength()) - return val, err + return int64(val), err } // getDistOpY retrieves the distance operator according to its layout specified within the record layout and their values as calibrated in the hex file -func (cd *CalibrationData) getDistOpY(rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { +func (cd *CalibrationData) getDistOpY(rl *a2l.RecordLayout, curPos *uint32) (int64, error) { if !rl.DistOpY.DatatypeSet { err := errors.New("distOpY datatype not set") log.Err(err).Msg("could not retrieve distOpY value") - return nil, err + return 0, err + } + bufBytes, err := cd.getValue(curPos, rl.DistOpY.Datatype, rl) + if err != nil { + log.Err(err).Msg("could not retrieve distOpY value") + return 0, err } - val, err := cd.getValue(curPos, rl.DistOpY.Datatype, rl) + val, err := cd.convertByteSliceToDatatype(bufBytes, rl.DistOpY.Datatype) if err != nil { log.Err(err).Msg("could not retrieve distOpY value") - return nil, err + return 0, err } *curPos += uint32(rl.DistOpY.Datatype.GetDatatypeLength()) - return val, err + return int64(val), err } // getDistOpZ retrieves the distance operator according to its layout specified within the record layout and their values as calibrated in the hex file -func (cd *CalibrationData) getDistOpZ(rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { +func (cd *CalibrationData) getDistOpZ(rl *a2l.RecordLayout, curPos *uint32) (int64, error) { if !rl.DistOpZ.DatatypeSet { err := errors.New("distOpZ datatype not set") log.Err(err).Msg("could not retrieve distOpZ value") - return nil, err + return 0, err } - val, err := cd.getValue(curPos, rl.DistOpZ.Datatype, rl) + bufBytes, err := cd.getValue(curPos, rl.DistOpZ.Datatype, rl) if err != nil { log.Err(err).Msg("could not retrieve distOpZ value") - return nil, err + return 0, err + } + val, err := cd.convertByteSliceToDatatype(bufBytes, rl.DistOpZ.Datatype) + if err != nil { + log.Err(err).Msg("could not retrieve distOpZ value") + return 0, err } *curPos += uint32(rl.DistOpZ.Datatype.GetDatatypeLength()) - return val, err + return int64(val), err } // getDistOp4 retrieves the distance operator according to its layout specified within the record layout and their values as calibrated in the hex file -func (cd *CalibrationData) getDistOp4(rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { +func (cd *CalibrationData) getDistOp4(rl *a2l.RecordLayout, curPos *uint32) (int64, error) { if !rl.DistOp4.DatatypeSet { err := errors.New("distOp4 datatype not set") log.Err(err).Msg("could not retrieve distOp4 value") - return nil, err + return 0, err + } + bufBytes, err := cd.getValue(curPos, rl.DistOp4.Datatype, rl) + if err != nil { + log.Err(err).Msg("could not retrieve distOp4 value") + return 0, err } - val, err := cd.getValue(curPos, rl.DistOp4.Datatype, rl) + val, err := cd.convertByteSliceToDatatype(bufBytes, rl.DistOp4.Datatype) if err != nil { log.Err(err).Msg("could not retrieve distOp4 value") - return nil, err + return 0, err } *curPos += uint32(rl.DistOp4.Datatype.GetDatatypeLength()) - return val, err + return int64(val), err } // getDistOp5 retrieves the distance operator according to its layout specified within the record layout and their values as calibrated in the hex file -func (cd *CalibrationData) getDistOp5(rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { +func (cd *CalibrationData) getDistOp5(rl *a2l.RecordLayout, curPos *uint32) (int64, error) { if !rl.DistOp5.DatatypeSet { err := errors.New("distOp5 datatype not set") log.Err(err).Msg("could not retrieve distOp5 value") - return nil, err + return 0, err + } + bufBytes, err := cd.getValue(curPos, rl.DistOp5.Datatype, rl) + if err != nil { + log.Err(err).Msg("could not retrieve distOp5 value") + return 0, err } - val, err := cd.getValue(curPos, rl.DistOp5.Datatype, rl) + val, err := cd.convertByteSliceToDatatype(bufBytes, rl.DistOp5.Datatype) if err != nil { log.Err(err).Msg("could not retrieve distOp5 value") - return nil, err + return 0, err } *curPos += uint32(rl.DistOp5.Datatype.GetDatatypeLength()) - return val, err + return int64(val), err } diff --git a/fnc_values.go b/fnc_values.go index 61861a6..8358f7f 100644 --- a/fnc_values.go +++ b/fnc_values.go @@ -7,53 +7,61 @@ import ( "github.com/rs/zerolog/log" ) -//check access type. DIRECT is the most used. Just read value from a given address. -//in case other access types are set this gets more complicated as either offsets or pointers are leveraged to -//define the position of the calibration objects. -//for VALUE Type: just read one value at curPos -//for higher level objects: read the number of elements defined by the matrix dim or NoAxisPts fields with the direction (row, column, alternate, ...) specified. -//for applicable objects check whether STATIC_RECORD_LAYOUT and STATIC_ ADDRESS_OFFSET are set -//to determine how to read the FNC_Values correctly, this can lead to hard to detect errors when not implemented. +// getFncValues1D retrieves Axis Points according to their layout specified within the record layout and their values as calibrated in the hex file +func (cv *CharacteristicValues) getFncValues1D(cd *CalibrationData, rl *a2l.RecordLayout, curPos *uint32) (float64, []byte, error) { + var bufByte []byte + var bufFloat float64 + var err error -func (cv *CharacteristicValues) getFncValues(cd *CalibrationData, rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { - if !rl.FncValues.DatatypeSet { - err := errors.New("fncValues datatype not set") - log.Err(err).Msg("could not determine datatype of FncValues of characteristic " + cv.characteristic.Name) - return nil, err + bufByte, err = cd.getValue(curPos, rl.FncValues.Datatype, rl) + if err != nil { + log.Err(err).Msg("could not retrieve FncValues values") + return 0.0, bufByte, err } - val, err := cv.getValuesByCharacteristicType(cd, rl, curPos) + bufFloat, err = cd.convertByteSliceToDatatype(bufByte, rl.FncValues.Datatype) if err != nil { - log.Err(err).Msg("could not retrieve fncValues value") - return nil, err + log.Err(err).Msg("could not retrieve FncValues values") + return 0.0, bufByte, err } - - return val, err + *curPos += uint32(rl.FncValues.Datatype.GetDatatypeLength()) + return bufFloat, bufByte, err } -func (cv *CharacteristicValues) getValuesByCharacteristicType(cd *CalibrationData, rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { - if !cv.characteristic.TypeSet { - err := errors.New("characteristic type not set") - log.Err(err).Msg("could not determine type of characteristic " + cv.characteristic.Name) +// getFncValues2D retrieves Axis Points according to their layout specified within the record layout and their values as calibrated in the hex file +func (cv *CharacteristicValues) getFncValues2D(cd *CalibrationData, rl *a2l.RecordLayout, curPos *uint32) ([]float64, error) { + var val []float64 + var bufByte []byte + var bufFloat float64 + var err error + var i int64 + var noFncValues int64 + if rl.FixNoAxisPtsX.NumberOfAxisPointsSet { + noFncValues = int64(rl.FixNoAxisPtsX.NumberOfAxisPoints) + } else if !rl.FixNoAxisPtsX.NumberOfAxisPointsSet { + if cv.characteristic.MatrixDim.DimX <= 0 { + err = errors.New("number of FncValues is smaller or equal to zero") + log.Err(err).Msg("could not retrieve NoFncValues value") + return nil, err + } + noFncValues = cv.noFncValuesXValue + } else { + err = errors.New("number of FncValues could not be determined") + log.Err(err).Msg("could not convert FncValues values") return nil, err } - - switch cv.characteristic.Type { - case a2l.ASCII: - case a2l.Curve: - case a2l.Map: - case a2l.Cuboid: - case a2l.Cube4: - case a2l.Cube5: - case a2l.ValBlk: - case a2l.Value: - //ToDo: - case a2l.Derived: - case a2l.ExtendedSi: - default: - err := errors.New("characteristic type not defined") - log.Err(err).Msg("could not determine type of characteristic " + cv.characteristic.Name) - return nil, err + for i = 0; i < noFncValues; i++ { + bufByte, err = cd.getValue(curPos, rl.AxisPtsX.Datatype, rl) + if err != nil { + log.Err(err).Msg("could not retrieve FncValues values") + return nil, err + } + bufFloat, err = cd.convertByteSliceToDatatype(bufByte, rl.AxisPtsX.Datatype) + if err != nil { + log.Err(err).Msg("could not retrieve FncValues values") + return nil, err + } + val = append(val, bufFloat) + *curPos += uint32(rl.AxisPtsX.Datatype.GetDatatypeLength()) } - - return nil, nil + return val, err } diff --git a/no_axis_pts.go b/no_axis_pts.go index 1030f72..766b01f 100644 --- a/no_axis_pts.go +++ b/no_axis_pts.go @@ -8,81 +8,106 @@ import ( ) // getAxisPtsX retrieves the number of X-axis points according to its layout specified within the record layout and their values as calibrated in the hex file -func (cd *CalibrationData) getNoAxisPtsX(rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { +func (cd *CalibrationData) getNoAxisPtsX(rl *a2l.RecordLayout, curPos *uint32) (int64, error) { if !rl.NoAxisPtsX.DatatypeSet { err := errors.New("noAxisPtsX datatype not set") log.Err(err).Msg("could not retrieve noAxisPtsX value") - return nil, err + return 0, err } - val, err := cd.getValue(curPos, rl.NoAxisPtsX.Datatype, rl) + bufBytes, err := cd.getValue(curPos, rl.NoAxisPtsX.Datatype, rl) if err != nil { log.Err(err).Msg("could not retrieve noAxisPtsX value") - return nil, err + return 0, err + } + val, err := cd.convertByteSliceToDatatype(bufBytes, rl.NoAxisPtsX.Datatype) + if err != nil { + log.Err(err).Msg("could not retrieve noAxisPtsX value") + return 0, err } *curPos += uint32(rl.NoAxisPtsX.Datatype.GetDatatypeLength()) - return val, err + return int64(val), err } -// getAxisPtsY retrieves the number of Y-axis points according to its layout specified within the record layout and their values as calibrated in the hex file -func (cd *CalibrationData) getNoAxisPtsY(rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { +// getAxisPtsY retrieves the number of X-axis points according to its layout specified within the record layout and their values as calibrated in the hex file +func (cd *CalibrationData) getNoAxisPtsY(rl *a2l.RecordLayout, curPos *uint32) (int64, error) { if !rl.NoAxisPtsY.DatatypeSet { err := errors.New("noAxisPtsY datatype not set") log.Err(err).Msg("could not retrieve noAxisPtsY value") - return nil, err + return 0, err + } + bufBytes, err := cd.getValue(curPos, rl.NoAxisPtsY.Datatype, rl) + if err != nil { + log.Err(err).Msg("could not retrieve noAxisPtsY value") + return 0, err } - val, err := cd.getValue(curPos, rl.NoAxisPtsY.Datatype, rl) + val, err := cd.convertByteSliceToDatatype(bufBytes, rl.NoAxisPtsY.Datatype) if err != nil { log.Err(err).Msg("could not retrieve noAxisPtsY value") - return nil, err + return 0, err } *curPos += uint32(rl.NoAxisPtsY.Datatype.GetDatatypeLength()) - return val, err + return int64(val), err } -// getAxisPtsZ retrieves the number of Z-axis points according to its layout specified within the record layout and their values as calibrated in the hex file -func (cd *CalibrationData) getNoAxisPtsZ(rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { +// getAxisPtsZ retrieves the number of X-axis points according to its layout specified within the record layout and their values as calibrated in the hex file +func (cd *CalibrationData) getNoAxisPtsZ(rl *a2l.RecordLayout, curPos *uint32) (int64, error) { if !rl.NoAxisPtsZ.DatatypeSet { err := errors.New("noAxisPtsZ datatype not set") log.Err(err).Msg("could not retrieve noAxisPtsZ value") - return nil, err + return 0, err } - val, err := cd.getValue(curPos, rl.NoAxisPtsZ.Datatype, rl) + bufBytes, err := cd.getValue(curPos, rl.NoAxisPtsZ.Datatype, rl) if err != nil { log.Err(err).Msg("could not retrieve noAxisPtsZ value") - return nil, err + return 0, err + } + val, err := cd.convertByteSliceToDatatype(bufBytes, rl.NoAxisPtsZ.Datatype) + if err != nil { + log.Err(err).Msg("could not retrieve noAxisPtsZ value") + return 0, err } *curPos += uint32(rl.NoAxisPtsZ.Datatype.GetDatatypeLength()) - return val, err + return int64(val), err } -// getAxisPts4 retrieves the number of 4-axis points according to its layout specified within the record layout and their values as calibrated in the hex file -func (cd *CalibrationData) getNoAxisPts4(rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { +// getAxisPts4 retrieves the number of X-axis points according to its layout specified within the record layout and their values as calibrated in the hex file +func (cd *CalibrationData) getNoAxisPts4(rl *a2l.RecordLayout, curPos *uint32) (int64, error) { if !rl.NoAxisPts4.DatatypeSet { err := errors.New("noAxisPts4 datatype not set") log.Err(err).Msg("could not retrieve noAxisPts4 value") - return nil, err + return 0, err + } + bufBytes, err := cd.getValue(curPos, rl.NoAxisPts4.Datatype, rl) + if err != nil { + log.Err(err).Msg("could not retrieve noAxisPts4 value") + return 0, err } - val, err := cd.getValue(curPos, rl.NoAxisPts4.Datatype, rl) + val, err := cd.convertByteSliceToDatatype(bufBytes, rl.NoAxisPts4.Datatype) if err != nil { log.Err(err).Msg("could not retrieve noAxisPts4 value") - return nil, err + return 0, err } *curPos += uint32(rl.NoAxisPts4.Datatype.GetDatatypeLength()) - return val, err + return int64(val), err } -// getAxisPts5 retrieves the number of 5-axis points according to its layout specified within the record layout and their values as calibrated in the hex file -func (cd *CalibrationData) getNoAxisPts5(rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { +// getAxisPts5 retrieves the number of X-axis points according to its layout specified within the record layout and their values as calibrated in the hex file +func (cd *CalibrationData) getNoAxisPts5(rl *a2l.RecordLayout, curPos *uint32) (int64, error) { if !rl.NoAxisPts5.DatatypeSet { err := errors.New("noAxisPts5 datatype not set") log.Err(err).Msg("could not retrieve noAxisPts5 value") - return nil, err + return 0, err + } + bufBytes, err := cd.getValue(curPos, rl.NoAxisPts5.Datatype, rl) + if err != nil { + log.Err(err).Msg("could not retrieve noAxisPts5 value") + return 0, err } - val, err := cd.getValue(curPos, rl.NoAxisPts5.Datatype, rl) + val, err := cd.convertByteSliceToDatatype(bufBytes, rl.NoAxisPts5.Datatype) if err != nil { log.Err(err).Msg("could not retrieve noAxisPts5 value") - return nil, err + return 0, err } *curPos += uint32(rl.NoAxisPts5.Datatype.GetDatatypeLength()) - return val, err + return int64(val), err } diff --git a/no_rescale_x.go b/no_rescale_x.go index 0714444..a90ae17 100644 --- a/no_rescale_x.go +++ b/no_rescale_x.go @@ -8,17 +8,22 @@ import ( ) // getNoRescaleX retrieves the number of Rescale X-axis pairs according to its layout specified within the record layout and their values as calibrated in the hex file -func (cd *CalibrationData) getNoRescaleX(rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { +func (cd *CalibrationData) getNoRescaleX(rl *a2l.RecordLayout, curPos *uint32) (int64, error) { if !rl.NoRescaleX.DatatypeSet { err := errors.New("noRescaleX datatype not set") - log.Err(err).Msg("could not retrieve NoRescaleX value") - return nil, err + log.Err(err).Msg("could not retrieve noRescaleX value") + return 0, err + } + bufBytes, err := cd.getValue(curPos, rl.NoRescaleX.Datatype, rl) + if err != nil { + log.Err(err).Msg("could not retrieve noRescaleX value") + return 0, err } - val, err := cd.getValue(curPos, rl.NoRescaleX.Datatype, rl) + val, err := cd.convertByteSliceToDatatype(bufBytes, rl.NoRescaleX.Datatype) if err != nil { log.Err(err).Msg("could not retrieve noRescaleX value") - return nil, err + return 0, err } *curPos += uint32(rl.NoRescaleX.Datatype.GetDatatypeLength()) - return val, err + return int64(val), err } diff --git a/offset.go b/offsetOp.go similarity index 62% rename from offset.go rename to offsetOp.go index 9943122..f5a194d 100644 --- a/offset.go +++ b/offsetOp.go @@ -8,81 +8,106 @@ import ( ) // getOffsetX retrieves the offset operator according to its layout specified within the record layout and their values as calibrated in the hex file -func (cd *CalibrationData) getOffsetX(rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { +func (cd *CalibrationData) getOffsetX(rl *a2l.RecordLayout, curPos *uint32) (int64, error) { if !rl.OffsetX.DatatypeSet { err := errors.New("offsetX datatype not set") log.Err(err).Msg("could not retrieve offsetX value") - return nil, err + return 0, err } - val, err := cd.getValue(curPos, rl.OffsetX.Datatype, rl) + bufBytes, err := cd.getValue(curPos, rl.OffsetX.Datatype, rl) if err != nil { log.Err(err).Msg("could not retrieve offsetX value") - return nil, err + return 0, err + } + val, err := cd.convertByteSliceToDatatype(bufBytes, rl.OffsetX.Datatype) + if err != nil { + log.Err(err).Msg("could not retrieve offsetX value") + return 0, err } *curPos += uint32(rl.OffsetX.Datatype.GetDatatypeLength()) - return val, err + return int64(val), err } // getOffsetY retrieves the offset operator according to its layout specified within the record layout and their values as calibrated in the hex file -func (cd *CalibrationData) getOffsetY(rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { +func (cd *CalibrationData) getOffsetY(rl *a2l.RecordLayout, curPos *uint32) (int64, error) { if !rl.OffsetY.DatatypeSet { err := errors.New("offsetY datatype not set") log.Err(err).Msg("could not retrieve offsetY value") - return nil, err + return 0, err + } + bufBytes, err := cd.getValue(curPos, rl.OffsetY.Datatype, rl) + if err != nil { + log.Err(err).Msg("could not retrieve offsetY value") + return 0, err } - val, err := cd.getValue(curPos, rl.OffsetY.Datatype, rl) + val, err := cd.convertByteSliceToDatatype(bufBytes, rl.OffsetY.Datatype) if err != nil { log.Err(err).Msg("could not retrieve offsetY value") - return nil, err + return 0, err } *curPos += uint32(rl.OffsetY.Datatype.GetDatatypeLength()) - return val, err + return int64(val), err } // getOffsetZ retrieves the offset operator according to its layout specified within the record layout and their values as calibrated in the hex file -func (cd *CalibrationData) getOffsetZ(rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { +func (cd *CalibrationData) getOffsetZ(rl *a2l.RecordLayout, curPos *uint32) (int64, error) { if !rl.OffsetZ.DatatypeSet { err := errors.New("offsetZ datatype not set") log.Err(err).Msg("could not retrieve offsetZ value") - return nil, err + return 0, err } - val, err := cd.getValue(curPos, rl.OffsetZ.Datatype, rl) + bufBytes, err := cd.getValue(curPos, rl.OffsetZ.Datatype, rl) if err != nil { log.Err(err).Msg("could not retrieve offsetZ value") - return nil, err + return 0, err + } + val, err := cd.convertByteSliceToDatatype(bufBytes, rl.OffsetZ.Datatype) + if err != nil { + log.Err(err).Msg("could not retrieve offsetZ value") + return 0, err } *curPos += uint32(rl.OffsetZ.Datatype.GetDatatypeLength()) - return val, err + return int64(val), err } // getOffset4 retrieves the offset operator according to its layout specified within the record layout and their values as calibrated in the hex file -func (cd *CalibrationData) getOffset4(rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { +func (cd *CalibrationData) getOffset4(rl *a2l.RecordLayout, curPos *uint32) (int64, error) { if !rl.Offset4.DatatypeSet { err := errors.New("offset4 datatype not set") log.Err(err).Msg("could not retrieve offset4 value") - return nil, err + return 0, err + } + bufBytes, err := cd.getValue(curPos, rl.Offset4.Datatype, rl) + if err != nil { + log.Err(err).Msg("could not retrieve offset4 value") + return 0, err } - val, err := cd.getValue(curPos, rl.Offset4.Datatype, rl) + val, err := cd.convertByteSliceToDatatype(bufBytes, rl.Offset4.Datatype) if err != nil { log.Err(err).Msg("could not retrieve offset4 value") - return nil, err + return 0, err } *curPos += uint32(rl.Offset4.Datatype.GetDatatypeLength()) - return val, err + return int64(val), err } // getOffset5 retrieves the offset operator according to its layout specified within the record layout and their values as calibrated in the hex file -func (cd *CalibrationData) getOffset5(rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { +func (cd *CalibrationData) getOffset5(rl *a2l.RecordLayout, curPos *uint32) (int64, error) { if !rl.Offset5.DatatypeSet { err := errors.New("offset5 datatype not set") log.Err(err).Msg("could not retrieve offset5 value") - return nil, err + return 0, err + } + bufBytes, err := cd.getValue(curPos, rl.Offset5.Datatype, rl) + if err != nil { + log.Err(err).Msg("could not retrieve offset5 value") + return 0, err } - val, err := cd.getValue(curPos, rl.Offset5.Datatype, rl) + val, err := cd.convertByteSliceToDatatype(bufBytes, rl.Offset5.Datatype) if err != nil { log.Err(err).Msg("could not retrieve offset5 value") - return nil, err + return 0, err } *curPos += uint32(rl.Offset5.Datatype.GetDatatypeLength()) - return val, err + return int64(val), err } diff --git a/record_manager.go b/record_manager.go index e405047..cfd1a53 100644 --- a/record_manager.go +++ b/record_manager.go @@ -135,96 +135,96 @@ func (cd *CalibrationData) convertStringToUint32Address(str string) (uint32, err // if not enough bytes are supplied the conversion fails. // if MsbFirstMswLast or MsbLastMswFirst are used as binary encoding then the conversion fails // as those are not implemented -func (cd *CalibrationData) convertByteSliceToDatatype(byteSlice []byte, dte a2l.DataTypeEnum) (interface{}, error) { +func (cd *CalibrationData) convertByteSliceToDatatype(byteSlice []byte, dte a2l.DataTypeEnum) (float64, error) { //bounds check if len(byteSlice) == 0 || len(byteSlice)*8 < int(dte.GetDatatypeLength()) { err := errors.New("byte slice holds " + fmt.Sprintf("%d", len(byteSlice)) + " bytes. " + strconv.Itoa(int(dte.GetDatatypeLength()/8)) + " bytes necessary to convert to datatype " + dte.String()) log.Err(err).Msg("conversion failed") - return nil, err + return 0.0, err } //check which byteorder is used modCom := &cd.A2l.Project.Modules[cd.ModuleIndex].ModCommon if modCom.ByteOrder.ByteOrder == a2l.MsbFirstMswLast || modCom.ByteOrder.ByteOrder == a2l.MsbLastMswFirst { err := errors.New("unexpected byte order") log.Err(err).Msg("byte order " + string(modCom.ByteOrder.ByteOrder) + "not implemented") - return nil, err + return 0.0, err } if !modCom.ByteOrder.ByteOrderSet || modCom.ByteOrder.ByteOrder == a2l.BigEndian || modCom.ByteOrder.ByteOrder == a2l.MsbFirst { switch dte { case a2l.UBYTE: - return byteSlice[0], nil + return float64(byteSlice[0]), nil case a2l.SBYTE: - return int8(byteSlice[0]), nil + return float64(int8(byteSlice[0])), nil case a2l.UWORD: val := binary.BigEndian.Uint32(byteSlice) - return val, nil + return float64(val), nil case a2l.SWORD: val := int32(binary.BigEndian.Uint32(byteSlice)) - return val, nil + return float64(val), nil case a2l.ULONG: val := binary.BigEndian.Uint64(byteSlice) - return val, nil + return float64(val), nil case a2l.SLONG: val := int64(binary.BigEndian.Uint64(byteSlice)) - return val, nil + return float64(val), nil case a2l.AUint64: val := binary.BigEndian.Uint64(byteSlice) - return val, nil + return float64(val), nil case a2l.AInt64: val := int64(binary.BigEndian.Uint64(byteSlice)) - return val, nil + return float64(val), nil case a2l.Float16Ieee: val := float16.Frombits(binary.BigEndian.Uint16(byteSlice)) - return val, nil + return float64(val), nil case a2l.Float32Ieee: val := math.Float32frombits(binary.BigEndian.Uint32(byteSlice)) - return val, nil + return float64(val), nil case a2l.Float64Ieee: val := math.Float64frombits(binary.BigEndian.Uint64(byteSlice)) - return val, nil + return float64(val), nil default: err := errors.New("unexpected datatype") log.Err(err).Msg("datatype " + dte.String() + " not implemented") - return nil, err + return 0.0, err } } else { switch dte { case a2l.UBYTE: - return byteSlice[0], nil + return float64(byteSlice[0]), nil case a2l.SBYTE: - return int8(byteSlice[0]), nil + return float64(int8(byteSlice[0])), nil case a2l.UWORD: val := binary.LittleEndian.Uint32(byteSlice) - return val, nil + return float64(val), nil case a2l.SWORD: val := int32(binary.LittleEndian.Uint32(byteSlice)) - return val, nil + return float64(val), nil case a2l.ULONG: val := binary.LittleEndian.Uint64(byteSlice) - return val, nil + return float64(val), nil case a2l.SLONG: val := int64(binary.LittleEndian.Uint64(byteSlice)) - return val, nil + return float64(val), nil case a2l.AUint64: val := binary.LittleEndian.Uint64(byteSlice) - return val, nil + return float64(val), nil case a2l.AInt64: val := int64(binary.LittleEndian.Uint64(byteSlice)) - return val, nil + return float64(val), nil case a2l.Float16Ieee: val := float16.Frombits(binary.LittleEndian.Uint16(byteSlice)) - return val, nil + return float64(val), nil case a2l.Float32Ieee: val := math.Float32frombits(binary.LittleEndian.Uint32(byteSlice)) - return val, nil + return float64(val), nil case a2l.Float64Ieee: val := math.Float64frombits(binary.LittleEndian.Uint64(byteSlice)) - return val, nil + return float64(val), nil default: err := errors.New("unexpected datatype") log.Err(err).Msg("datatype " + dte.String() + " not implemented") - return nil, err + return 0.0, err } } } diff --git a/shiftOp.go b/shiftOp.go index bc0cd46..256ee1b 100644 --- a/shiftOp.go +++ b/shiftOp.go @@ -8,81 +8,106 @@ import ( ) // getShiftOpX retrieves the shift operator according to its layout specified within the record layout and their values as calibrated in the hex file -func (cd *CalibrationData) getShiftOpX(rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { +func (cd *CalibrationData) getShiftOpX(rl *a2l.RecordLayout, curPos *uint32) (int64, error) { if !rl.ShiftOpX.DatatypeSet { - err := errors.New("shiftX datatype not set") - log.Err(err).Msg("could not retrieve shiftX value") - return nil, err + err := errors.New("shiftOpX datatype not set") + log.Err(err).Msg("could not retrieve shiftOpX value") + return 0, err } - val, err := cd.getValue(curPos, rl.ShiftOpX.Datatype, rl) + bufBytes, err := cd.getValue(curPos, rl.ShiftOpX.Datatype, rl) if err != nil { - log.Err(err).Msg("could not retrieve shiftX value") - return nil, err + log.Err(err).Msg("could not retrieve shiftOpX value") + return 0, err + } + val, err := cd.convertByteSliceToDatatype(bufBytes, rl.ShiftOpX.Datatype) + if err != nil { + log.Err(err).Msg("could not retrieve shiftOpX value") + return 0, err } *curPos += uint32(rl.ShiftOpX.Datatype.GetDatatypeLength()) - return val, err + return int64(val), err } // getShiftOpY retrieves the shift operator according to its layout specified within the record layout and their values as calibrated in the hex file -func (cd *CalibrationData) getShiftOpY(rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { +func (cd *CalibrationData) getShiftOpY(rl *a2l.RecordLayout, curPos *uint32) (int64, error) { if !rl.ShiftOpY.DatatypeSet { - err := errors.New("shiftY datatype not set") - log.Err(err).Msg("could not retrieve shiftY value") - return nil, err + err := errors.New("shiftOpY datatype not set") + log.Err(err).Msg("could not retrieve shiftOpY value") + return 0, err } - val, err := cd.getValue(curPos, rl.ShiftOpY.Datatype, rl) + bufBytes, err := cd.getValue(curPos, rl.ShiftOpY.Datatype, rl) if err != nil { - log.Err(err).Msg("could not retrieve shiftY value") - return nil, err + log.Err(err).Msg("could not retrieve shiftOpY value") + return 0, err + } + val, err := cd.convertByteSliceToDatatype(bufBytes, rl.ShiftOpY.Datatype) + if err != nil { + log.Err(err).Msg("could not retrieve shiftOpY value") + return 0, err } *curPos += uint32(rl.ShiftOpY.Datatype.GetDatatypeLength()) - return val, err + return int64(val), err } // getShiftOpZ retrieves the shift operator according to its layout specified within the record layout and their values as calibrated in the hex file -func (cd *CalibrationData) getShiftOpZ(rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { +func (cd *CalibrationData) getShiftOpZ(rl *a2l.RecordLayout, curPos *uint32) (int64, error) { if !rl.ShiftOpZ.DatatypeSet { - err := errors.New("shiftZ datatype not set") - log.Err(err).Msg("could not retrieve shiftZ value") - return nil, err + err := errors.New("shiftOpZ datatype not set") + log.Err(err).Msg("could not retrieve shiftOpZ value") + return 0, err + } + bufBytes, err := cd.getValue(curPos, rl.ShiftOpZ.Datatype, rl) + if err != nil { + log.Err(err).Msg("could not retrieve shiftOpZ value") + return 0, err } - val, err := cd.getValue(curPos, rl.ShiftOpZ.Datatype, rl) + val, err := cd.convertByteSliceToDatatype(bufBytes, rl.ShiftOpZ.Datatype) if err != nil { - log.Err(err).Msg("could not retrieve shiftZ value") - return nil, err + log.Err(err).Msg("could not retrieve shiftOpZ value") + return 0, err } *curPos += uint32(rl.ShiftOpZ.Datatype.GetDatatypeLength()) - return val, err + return int64(val), err } -// getShiftOp4 retrieves the shift operator according to its layout specified within the record layout and their values as calibrated in the hex file -func (cd *CalibrationData) getShiftOp4(rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { +// / getShiftOp4 retrieves the shift operator according to its layout specified within the record layout and their values as calibrated in the hex file +func (cd *CalibrationData) getShiftOp4(rl *a2l.RecordLayout, curPos *uint32) (int64, error) { if !rl.ShiftOp4.DatatypeSet { - err := errors.New("shift4 datatype not set") - log.Err(err).Msg("could not retrieve shift4 value") - return nil, err + err := errors.New("shiftOp4 datatype not set") + log.Err(err).Msg("could not retrieve shiftOp4 value") + return 0, err + } + bufBytes, err := cd.getValue(curPos, rl.ShiftOp4.Datatype, rl) + if err != nil { + log.Err(err).Msg("could not retrieve shiftOp4 value") + return 0, err } - val, err := cd.getValue(curPos, rl.ShiftOp4.Datatype, rl) + val, err := cd.convertByteSliceToDatatype(bufBytes, rl.ShiftOp4.Datatype) if err != nil { - log.Err(err).Msg("could not retrieve shift4 value") - return nil, err + log.Err(err).Msg("could not retrieve shiftOp4 value") + return 0, err } *curPos += uint32(rl.ShiftOp4.Datatype.GetDatatypeLength()) - return val, err + return int64(val), err } // getShiftOp5 retrieves the shift operator according to its layout specified within the record layout and their values as calibrated in the hex file -func (cd *CalibrationData) getShiftOp5(rl *a2l.RecordLayout, curPos *uint32) (interface{}, error) { +func (cd *CalibrationData) getShiftOp5(rl *a2l.RecordLayout, curPos *uint32) (int64, error) { if !rl.ShiftOp5.DatatypeSet { - err := errors.New("shift5 datatype not set") - log.Err(err).Msg("could not retrieve shift5 value") - return nil, err + err := errors.New("shiftOp5 datatype not set") + log.Err(err).Msg("could not retrieve shiftOp5 value") + return 0, err + } + bufBytes, err := cd.getValue(curPos, rl.ShiftOp5.Datatype, rl) + if err != nil { + log.Err(err).Msg("could not retrieve shiftOp5 value") + return 0, err } - val, err := cd.getValue(curPos, rl.ShiftOp5.Datatype, rl) + val, err := cd.convertByteSliceToDatatype(bufBytes, rl.ShiftOp5.Datatype) if err != nil { - log.Err(err).Msg("could not retrieve shift5 value") - return nil, err + log.Err(err).Msg("could not retrieve shiftOp5 value") + return 0, err } *curPos += uint32(rl.ShiftOp5.Datatype.GetDatatypeLength()) - return val, err + return int64(val), err }