OOH.. nice one. I had missed that in my template implementation. I'm a big fan of using C++ templating to do type-safe versions of this kind of stuff... This is my template version:
/** Sign extend an unsigned to a signed integer of the same size.
*/
template<typename UINT, typename INT, uint8_t SIGNBIT>
INT sign_extend( UINT uvalue)
{
typedef typename std::make_unsigned<INT>::type uint_t;
uint_t newuvalue = uvalue;
if ( newuvalue & ( UINT(1U) << SIGNBIT) ) {
newuvalue |= ~((uint_t(1U) << SIGNBIT) - 1);
}
return reinterpret_cast<INT &>(uvalue);
}
It could probably be converted into a version that would infer some of the types.. but this should work pretty well and should compile down to close to the same code.
Usage from my code: Where BYTES is a templated integer value parameter.
res = sign_extend < uint32_t, int32_t, BYTES * 8 - 1 > (ures);
I also have a templated buffer extractor that allows for checking available space!
For example this code (which extracts 2 bytes as a signed integer), which should now work with sign extension thanks to your bugfix and the above templated version of sign extension:
int32_t signedValue;
if (!can_buff_int<2>(data, 10, signedValue )) {
ESP_LOGE(TAG, "IoniqISOTP.BMC: BMS Current: Bad Buffer");
} else {
StdMetrics.ms_v_bat_current->SetValue((float)signedValue / 10.0, Amps);
}
//.ichael