[spinel] add support for 64-bit long signed/unsigned integer (#2309)

This commit adds support for encoding/decoding `uint64_t`/`int64_t`
to spinel as primitive types. `X` and `x` are used as format ASCII
character associated with `uint64_t` and `int64_t` respectively.
This commit also updates the `SpinelEncoder` and `SpinelDecoder`
to add methods related to 64-bit long integer. The related unit test
are also updated.
This commit is contained in:
Abtin Keshavarzian
2017-11-01 21:46:09 -07:00
committed by Jonathan Hui
parent d8e2c2f73d
commit 1e6658b3ad
9 changed files with 204 additions and 2 deletions
@@ -42,6 +42,8 @@ Char | Name | Description
`s` | DATATYPE_INT16 | Signed 16-bit integer.
`L` | DATATYPE_UINT32 | Unsigned 32-bit integer.
`l` | DATATYPE_INT32 | Signed 32-bit integer.
`X` | DATATYPE_UINT64 | Unsigned 64-bit integer.
`x` | DATATYPE_INT64 | Signed 64-bit integer.
`i` | DATATYPE_UINT_PACKED | Packed Unsigned Integer. See (#packed-unsigned-integer).
`6` | DATATYPE_IPv6ADDR | IPv6 Address. (Big-endian)
`E` | DATATYPE_EUI64 | EUI-64 Address. (Big-endian)
+48
View File
@@ -337,6 +337,26 @@ spinel_datatype_vunpack_(bool in_place, const uint8_t *data_ptr, spinel_size_t d
break;
}
case SPINEL_DATATYPE_INT64_C:
case SPINEL_DATATYPE_UINT64_C:
{
uint64_t *arg_ptr = va_arg(args->obj, uint64_t *);
require_action(data_len >= sizeof(uint64_t), bail, (ret = -1, errno = EOVERFLOW));
if (arg_ptr)
{
uint32_t l32 = (uint32_t)((data_ptr[3] << 24) | (data_ptr[2] << 16) | (data_ptr[1] << 8) | data_ptr[0]);
uint32_t h32 = (uint32_t)((data_ptr[7] << 24) | (data_ptr[6] << 16) | (data_ptr[5] << 8) | data_ptr[4]);
*arg_ptr = ((uint64_t)l32) | (((uint64_t)h32) << 32);
}
ret += sizeof(uint64_t);
data_ptr += sizeof(uint64_t);
data_len -= sizeof(uint64_t);
break;
}
case SPINEL_DATATYPE_IPv6ADDR_C:
{
require_action(data_len >= sizeof(spinel_ipv6addr_t), bail, (ret = -1, errno = EOVERFLOW));
@@ -748,6 +768,34 @@ spinel_datatype_vpack_(uint8_t *data_ptr, spinel_size_t data_len_max, const char
break;
}
case SPINEL_DATATYPE_INT64_C:
case SPINEL_DATATYPE_UINT64_C:
{
uint64_t arg = (uint64_t)va_arg(args->obj, uint64_t);
ret += sizeof(uint64_t);
if (data_len_max >= sizeof(uint64_t))
{
data_ptr[7] = (arg >> 56) & 0xff;
data_ptr[6] = (arg >> 48) & 0xff;
data_ptr[5] = (arg >> 40) & 0xff;
data_ptr[4] = (arg >> 32) & 0xff;
data_ptr[3] = (arg >> 24) & 0xff;
data_ptr[2] = (arg >> 16) & 0xff;
data_ptr[1] = (arg >> 8) & 0xff;
data_ptr[0] = (arg >> 0) & 0xff;
data_ptr += sizeof(uint64_t);
data_len_max -= sizeof(uint64_t);
}
else
{
data_len_max = 0;
}
break;
}
case SPINEL_DATATYPE_IPv6ADDR_C:
{
spinel_ipv6addr_t *arg = va_arg(args->obj, spinel_ipv6addr_t *);
+4
View File
@@ -1407,6 +1407,8 @@ enum
SPINEL_DATATYPE_INT16_C = 's',
SPINEL_DATATYPE_UINT32_C = 'L',
SPINEL_DATATYPE_INT32_C = 'l',
SPINEL_DATATYPE_UINT64_C = 'X',
SPINEL_DATATYPE_INT64_C = 'x',
SPINEL_DATATYPE_UINT_PACKED_C = 'i',
SPINEL_DATATYPE_IPv6ADDR_C = '6',
SPINEL_DATATYPE_EUI64_C = 'E',
@@ -1429,6 +1431,8 @@ typedef char spinel_datatype_t;
#define SPINEL_DATATYPE_INT16_S "s"
#define SPINEL_DATATYPE_UINT32_S "L"
#define SPINEL_DATATYPE_INT32_S "l"
#define SPINEL_DATATYPE_UINT64_S "X"
#define SPINEL_DATATYPE_INT64_S "x"
#define SPINEL_DATATYPE_UINT_PACKED_S "i"
#define SPINEL_DATATYPE_IPv6ADDR_S "6"
#define SPINEL_DATATYPE_EUI64_S "E"
+33
View File
@@ -172,6 +172,39 @@ exit:
return error;
}
otError SpinelDecoder::ReadUint64(uint64_t &aUint64)
{
otError error = OT_ERROR_NONE;
VerifyOrExit(mIndex + sizeof(uint64_t) <= mEnd, error = OT_ERROR_PARSE);
aUint64 = ((static_cast<uint64_t>(mFrame[mIndex + 0]) << 0) |
(static_cast<uint64_t>(mFrame[mIndex + 1]) << 8) |
(static_cast<uint64_t>(mFrame[mIndex + 2]) << 16) |
(static_cast<uint64_t>(mFrame[mIndex + 3]) << 24) |
(static_cast<uint64_t>(mFrame[mIndex + 4]) << 32) |
(static_cast<uint64_t>(mFrame[mIndex + 5]) << 40) |
(static_cast<uint64_t>(mFrame[mIndex + 6]) << 48) |
(static_cast<uint64_t>(mFrame[mIndex + 7]) << 56));
mIndex += sizeof(uint64_t);
exit:
return error;
}
otError SpinelDecoder::ReadInt64(int64_t &aInt64)
{
otError error = OT_ERROR_NONE;
uint64_t u64;
SuccessOrExit(error = ReadUint64(u64));
aInt64 = static_cast<int64_t>(u64);
exit:
return error;
}
otError SpinelDecoder::ReadUintPacked(unsigned int &aUint)
{
otError error = OT_ERROR_NONE;
+26
View File
@@ -208,6 +208,32 @@ public:
*/
otError ReadUint32(uint32_t &aUint32);
/**
* This method decodes and reads an `int64_t` value form the frame.
*
* On success, the read position gets updated.
*
* @param[out] aInt64 Reference to variable to output the read value.
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadInt64(int64_t &aInt64);
/**
* This method decodes and reads an `uint64_t` value form the frame.
*
* On success, the read position gets updated.
*
* @param[out] aUint64 Reference to variable to output the read value.
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadUint64(uint64_t &aUint64);
/**
* This method decodes (using spinel packed integer format) and reads an unsigned integer value form the frame.
*
+17
View File
@@ -135,6 +135,23 @@ exit:
return error;
}
otError SpinelEncoder::WriteUint64(uint64_t aUint64)
{
otError error = OT_ERROR_NONE;
SuccessOrExit(error = mNcpBuffer.InFrameFeedByte((aUint64 >> 0) & 0xff));
SuccessOrExit(error = mNcpBuffer.InFrameFeedByte((aUint64 >> 8) & 0xff));
SuccessOrExit(error = mNcpBuffer.InFrameFeedByte((aUint64 >> 16) & 0xff));
SuccessOrExit(error = mNcpBuffer.InFrameFeedByte((aUint64 >> 24) & 0xff));
SuccessOrExit(error = mNcpBuffer.InFrameFeedByte((aUint64 >> 32) & 0xff));
SuccessOrExit(error = mNcpBuffer.InFrameFeedByte((aUint64 >> 40) & 0xff));
SuccessOrExit(error = mNcpBuffer.InFrameFeedByte((aUint64 >> 48) & 0xff));
SuccessOrExit(error = mNcpBuffer.InFrameFeedByte((aUint64 >> 56) & 0xff));
exit:
return error;
}
otError SpinelEncoder::WriteUintPacked(unsigned int aUint)
{
uint8_t buffer[6];
+36
View File
@@ -278,6 +278,42 @@ public:
*/
otError WriteInt32(int32_t aInt32) { return WriteUint32(static_cast<uint32_t>(aInt32)); }
/**
* This method encodes and writes a `uint64_t` value to current input frame.
*
* Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this
* method does nothing and returns error status `OT_ERROR_INVALID_STATE`.
*
* If no buffer space is available, this method will discard and clear the current input frame and return the
* error status `OT_ERROR_NO_BUFS`.
*
* @param[in] aUint64 The value to add to input frame.
*
* @retval OT_ERROR_NONE Successfully added given value to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame.
*
*/
otError WriteUint64(uint64_t aUint64);
/**
* This method encodes and writes an `int64_t` value to current input frame.
*
* Before using this method `BeginFrame()` must be called to start and prepare a new input frame. Otherwise, this
* method does nothing and returns error status `OT_ERROR_INVALID_STATE`.
*
* If no buffer space is available, this method will discard and clear the current input frame and return the
* error status `OT_ERROR_NO_BUFS`.
*
* @param[in] aInt64 The value to add to input frame.
*
* @retval OT_ERROR_NONE Successfully added given value to the frame.
* @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the value.
* @retval OT_ERROR_INVALID_STATE `BeginFrame()` has not been called earlier to start the frame.
*
*/
otError WriteInt64(int64_t aInt64) { return WriteUint64(static_cast<uint64_t>(aInt64)); }
/**
* This method encodes (using spinel packed integer format) and writes a value to current input frame.
*
+26 -2
View File
@@ -101,7 +101,8 @@ void TestSpinelDecoder(void)
const int16_t kInt16 = -567;
const uint32_t kUint32 = 0xdeadbeef;
const int32_t kInt32 = -123455678L;
const uint64_t kUint64 = 0xfe10dc32ba549876ULL;
const int64_t kInt64 = -9197712039090021561LL;
const unsigned int kUint_1 = 9;
const unsigned int kUint_2 = 0xa3;
@@ -136,6 +137,8 @@ void TestSpinelDecoder(void)
int16_t i16;
uint32_t u32;
int32_t i32;
uint64_t u64;
int64_t i64;
unsigned int u_1, u_2, u_3, u_4;
const spinel_ipv6addr_t *ip6Addr;
const spinel_eui48_t *eui48;
@@ -164,6 +167,8 @@ void TestSpinelDecoder(void)
SPINEL_DATATYPE_INT16_S
SPINEL_DATATYPE_UINT32_S
SPINEL_DATATYPE_INT32_S
SPINEL_DATATYPE_UINT64_S
SPINEL_DATATYPE_INT64_S
SPINEL_DATATYPE_UINT_PACKED_S
SPINEL_DATATYPE_UINT_PACKED_S
SPINEL_DATATYPE_UINT_PACKED_S
@@ -184,6 +189,8 @@ void TestSpinelDecoder(void)
kInt16,
kUint32,
kInt32,
kUint64,
kInt64,
kUint_1,
kUint_2,
kUint_3,
@@ -216,6 +223,8 @@ void TestSpinelDecoder(void)
SuccessOrQuit(decoder.ReadInt16(i16), "ReadInt16() failed.");
SuccessOrQuit(decoder.ReadUint32(u32), "ReadUint32() failed.");
SuccessOrQuit(decoder.ReadInt32(i32), "ReadUint32() failed.");
SuccessOrQuit(decoder.ReadUint64(u64), "ReadUint64() failed.");
SuccessOrQuit(decoder.ReadInt64(i64), "ReadUint64() failed.");
// Check the state
VerifyOrQuit(decoder.GetReadLength() != 0, "GetReadLength() failed.");
@@ -224,6 +233,7 @@ void TestSpinelDecoder(void)
VerifyOrQuit(decoder.IsAllRead() == false, "IsAllRead() failed.");
SuccessOrQuit(decoder.ReadUintPacked(u_1), "ReadUintPacked() failed.");
SuccessOrQuit(decoder.ReadUintPacked(u_2), "ReadUintPacked() failed.");
SuccessOrQuit(decoder.ReadUintPacked(u_3), "ReadUintPacked() failed.");
SuccessOrQuit(decoder.ReadUintPacked(u_4), "ReadUintPacked() failed.");
@@ -246,7 +256,9 @@ void TestSpinelDecoder(void)
VerifyOrQuit(u16 == kUint16, "ReadUint16() parse failed.");
VerifyOrQuit(i16 == kInt16, "ReadInt16() parse failed.");
VerifyOrQuit(u32 == kUint32, "ReadUint32() parse failed.");
VerifyOrQuit(i32 == kInt32, "ReadUint32() parse failed.");
VerifyOrQuit(i32 == kInt32, "ReadInt32() parse failed.");
VerifyOrQuit(u64 == kUint64, "ReadUint64() parse failed.");
VerifyOrQuit(i64 == kInt64, "ReadInt64() parse failed.");
VerifyOrQuit(u_1 == kUint_1, "ReadUintPacked() parse failed.");
VerifyOrQuit(u_2 == kUint_2, "ReadUintPacked() parse failed.");
VerifyOrQuit(u_3 == kUint_3, "ReadUintPacked() parse failed.");
@@ -292,6 +304,8 @@ void TestSpinelDecoder(void)
// Save position
decoder.SavePosition();
SuccessOrQuit(decoder.ReadUint64(u64), "ReadUint64() failed.");
SuccessOrQuit(decoder.ReadInt64(i64), "ReadUint64() failed.");
SuccessOrQuit(decoder.ReadUintPacked(u_1), "ReadUintPacked() failed.");
SuccessOrQuit(decoder.ReadUintPacked(u_2), "ReadUintPacked() failed.");
SuccessOrQuit(decoder.ReadUintPacked(u_3), "ReadUintPacked() failed.");
@@ -306,6 +320,8 @@ void TestSpinelDecoder(void)
VerifyOrQuit(i16 == kInt16, "ReadInt16() parse failed.");
VerifyOrQuit(u32 == kUint32, "ReadUint32() parse failed.");
VerifyOrQuit(i32 == kInt32, "ReadUint32() parse failed.");
VerifyOrQuit(u64 == kUint64, "ReadUint64() parse failed.");
VerifyOrQuit(i64 == kInt64, "ReadInt64() parse failed.");
VerifyOrQuit(u_1 == kUint_1, "ReadUintPacked() parse failed.");
VerifyOrQuit(u_2 == kUint_2, "ReadUintPacked() parse failed.");
VerifyOrQuit(u_3 == kUint_3, "ReadUintPacked() parse failed.");
@@ -314,12 +330,16 @@ void TestSpinelDecoder(void)
SuccessOrQuit(decoder.ResetToSaved(), "ResetToSaved() failed");
SuccessOrQuit(decoder.ReadUint64(u64), "ReadUint64() failed.");
SuccessOrQuit(decoder.ReadInt64(i64), "ReadUint64() failed.");
SuccessOrQuit(decoder.ReadUintPacked(u_1), "ReadUintPacked() failed.");
SuccessOrQuit(decoder.ReadUintPacked(u_2), "ReadUintPacked() failed.");
SuccessOrQuit(decoder.ReadUintPacked(u_3), "ReadUintPacked() failed.");
SuccessOrQuit(decoder.ReadUintPacked(u_4), "ReadUintPacked() failed.");
SuccessOrQuit(decoder.ReadIp6Address(ip6Addr), "ReadIp6Addr() failed.");
VerifyOrQuit(u64 == kUint64, "ReadUint64() parse failed.");
VerifyOrQuit(i64 == kInt64, "ReadInt64() parse failed.");
VerifyOrQuit(u_1 == kUint_1, "ReadUintPacked() parse failed.");
VerifyOrQuit(u_2 == kUint_2, "ReadUintPacked() parse failed.");
VerifyOrQuit(u_3 == kUint_3, "ReadUintPacked() parse failed.");
@@ -329,12 +349,16 @@ void TestSpinelDecoder(void)
// Go back to save position again.
SuccessOrQuit(decoder.ResetToSaved(), "ResetToSaved() failed");
SuccessOrQuit(decoder.ReadUint64(u64), "ReadUint64() failed.");
SuccessOrQuit(decoder.ReadInt64(i64), "ReadUint64() failed.");
SuccessOrQuit(decoder.ReadUintPacked(u_1), "ReadUintPacked() failed.");
SuccessOrQuit(decoder.ReadUintPacked(u_2), "ReadUintPacked() failed.");
SuccessOrQuit(decoder.ReadUintPacked(u_3), "ReadUintPacked() failed.");
SuccessOrQuit(decoder.ReadUintPacked(u_4), "ReadUintPacked() failed.");
SuccessOrQuit(decoder.ReadIp6Address(ip6Addr), "ReadIp6Addr() failed.");
VerifyOrQuit(u64 == kUint64, "ReadUint64() parse failed.");
VerifyOrQuit(i64 == kInt64, "ReadInt64() parse failed.");
VerifyOrQuit(u_1 == kUint_1, "ReadUintPacked() parse failed.");
VerifyOrQuit(u_2 == kUint_2, "ReadUintPacked() parse failed.");
VerifyOrQuit(u_3 == kUint_3, "ReadUintPacked() parse failed.");
+12
View File
@@ -117,6 +117,8 @@ void TestSpinelEncoder(void)
const int16_t kInt16 = -567;
const uint32_t kUint32 = 0xdeadbeef;
const int32_t kInt32 = -123455678L;
const uint64_t kUint64 = 0xfe10dc32ba549876ULL;
const int64_t kInt64 = -9197712039090021561LL;
const unsigned int kUint_1 = 9;
const unsigned int kUint_2 = 0xa3;
const unsigned int kUint_3 = 0x8765;
@@ -149,6 +151,8 @@ void TestSpinelEncoder(void)
int16_t i16;
uint32_t u32;
int32_t i32;
uint64_t u64;
int64_t i64;
unsigned int u_1, u_2, u_3, u_4;
spinel_ipv6addr_t *ip6Addr;
spinel_eui48_t *eui48;
@@ -172,6 +176,8 @@ void TestSpinelEncoder(void)
SuccessOrQuit(encoder.WriteInt16(kInt16), "WriteInt16() failed.");
SuccessOrQuit(encoder.WriteUint32(kUint32), "WriteUint32() failed.");
SuccessOrQuit(encoder.WriteInt32(kInt32), "WriteUint32() failed.");
SuccessOrQuit(encoder.WriteUint64(kUint64), "WriteUint64() failed.");
SuccessOrQuit(encoder.WriteInt64(kInt64), "WriteUint64() failed.");
SuccessOrQuit(encoder.WriteUintPacked(kUint_1), "WriteUintPacked() failed.");
SuccessOrQuit(encoder.WriteUintPacked(kUint_2), "WriteUintPacked() failed.");
SuccessOrQuit(encoder.WriteUintPacked(kUint_3), "WriteUintPacked() failed.");
@@ -200,6 +206,8 @@ void TestSpinelEncoder(void)
SPINEL_DATATYPE_INT16_S
SPINEL_DATATYPE_UINT32_S
SPINEL_DATATYPE_INT32_S
SPINEL_DATATYPE_UINT64_S
SPINEL_DATATYPE_INT64_S
SPINEL_DATATYPE_UINT_PACKED_S
SPINEL_DATATYPE_UINT_PACKED_S
SPINEL_DATATYPE_UINT_PACKED_S
@@ -219,6 +227,8 @@ void TestSpinelEncoder(void)
&i16,
&u32,
&i32,
&u64,
&i64,
&u_1,
&u_2,
&u_3,
@@ -241,6 +251,8 @@ void TestSpinelEncoder(void)
VerifyOrQuit(i16 == kInt16, "WriteInt16() parse failed.");
VerifyOrQuit(u32 == kUint32, "WriteUint32() parse failed.");
VerifyOrQuit(i32 == kInt32, "WriteUint32() parse failed.");
VerifyOrQuit(u64 == kUint64, "WriteUint64() parse failed.");
VerifyOrQuit(i64 == kInt64, "WriteUint64() parse failed.");
VerifyOrQuit(u_1 == kUint_1, "WriteUintPacked() parse failed.");
VerifyOrQuit(u_2 == kUint_2, "WriteUintPacked() parse failed.");
VerifyOrQuit(u_3 == kUint_3, "WriteUintPacked() parse failed.");