2015-06-21 22:42:01 -07:00
|
|
|
/*----------------------------------------------------------------------------*/
|
2018-05-13 17:09:56 -07:00
|
|
|
/* Copyright (c) 2015-2018 FIRST. All Rights Reserved. */
|
2015-06-21 22:42:01 -07:00
|
|
|
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
|
|
|
|
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
|
|
|
|
/* the project. */
|
|
|
|
|
/*----------------------------------------------------------------------------*/
|
|
|
|
|
|
2015-06-25 23:12:49 -07:00
|
|
|
#include "WireEncoder.h"
|
2015-06-21 22:42:01 -07:00
|
|
|
|
2017-08-19 23:08:27 -07:00
|
|
|
#include <stdint.h>
|
|
|
|
|
|
2015-06-21 22:42:01 -07:00
|
|
|
#include <cassert>
|
|
|
|
|
#include <cstdlib>
|
|
|
|
|
#include <cstring>
|
|
|
|
|
|
2018-04-29 23:33:19 -07:00
|
|
|
#include <wpi/MathExtras.h>
|
|
|
|
|
#include <wpi/leb128.h>
|
2015-06-21 22:42:01 -07:00
|
|
|
|
2015-07-17 07:21:07 -07:00
|
|
|
using namespace nt;
|
2015-06-21 22:42:01 -07:00
|
|
|
|
2015-06-25 22:57:43 -07:00
|
|
|
WireEncoder::WireEncoder(unsigned int proto_rev) {
|
|
|
|
|
m_proto_rev = proto_rev;
|
|
|
|
|
m_error = nullptr;
|
2015-06-21 22:42:01 -07:00
|
|
|
}
|
|
|
|
|
|
2015-06-25 22:57:43 -07:00
|
|
|
void WireEncoder::WriteDouble(double val) {
|
2015-06-26 01:23:36 -07:00
|
|
|
// The highest performance way to do this, albeit non-portable.
|
2018-04-29 23:33:19 -07:00
|
|
|
uint64_t v = wpi::DoubleToBits(val);
|
2017-08-19 23:08:27 -07:00
|
|
|
m_data.append(
|
|
|
|
|
{static_cast<char>((v >> 56) & 0xff), static_cast<char>((v >> 48) & 0xff),
|
|
|
|
|
static_cast<char>((v >> 40) & 0xff), static_cast<char>((v >> 32) & 0xff),
|
|
|
|
|
static_cast<char>((v >> 24) & 0xff), static_cast<char>((v >> 16) & 0xff),
|
|
|
|
|
static_cast<char>((v >> 8) & 0xff), static_cast<char>(v & 0xff)});
|
2015-06-21 22:42:01 -07:00
|
|
|
}
|
|
|
|
|
|
2017-08-19 23:08:27 -07:00
|
|
|
void WireEncoder::WriteUleb128(uint32_t val) { wpi::WriteUleb128(m_data, val); }
|
2015-06-21 22:42:01 -07:00
|
|
|
|
2015-06-25 22:57:43 -07:00
|
|
|
void WireEncoder::WriteType(NT_Type type) {
|
2015-09-06 11:00:44 -07:00
|
|
|
char ch;
|
2015-06-26 01:23:36 -07:00
|
|
|
// Convert from enum to actual byte value.
|
2015-06-25 22:57:43 -07:00
|
|
|
switch (type) {
|
|
|
|
|
case NT_BOOLEAN:
|
2015-09-06 11:00:44 -07:00
|
|
|
ch = 0x00;
|
2015-06-25 22:57:43 -07:00
|
|
|
break;
|
|
|
|
|
case NT_DOUBLE:
|
2015-09-06 11:00:44 -07:00
|
|
|
ch = 0x01;
|
2015-06-25 22:57:43 -07:00
|
|
|
break;
|
|
|
|
|
case NT_STRING:
|
2015-09-06 11:00:44 -07:00
|
|
|
ch = 0x02;
|
2015-06-25 22:57:43 -07:00
|
|
|
break;
|
2015-06-21 22:42:01 -07:00
|
|
|
case NT_RAW:
|
2015-06-25 22:57:43 -07:00
|
|
|
if (m_proto_rev < 0x0300u) {
|
|
|
|
|
m_error = "raw type not supported in protocol < 3.0";
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-09-06 11:00:44 -07:00
|
|
|
ch = 0x03;
|
2015-06-25 22:57:43 -07:00
|
|
|
break;
|
|
|
|
|
case NT_BOOLEAN_ARRAY:
|
2015-09-06 11:00:44 -07:00
|
|
|
ch = 0x10;
|
2015-06-25 22:57:43 -07:00
|
|
|
break;
|
|
|
|
|
case NT_DOUBLE_ARRAY:
|
2015-09-06 11:00:44 -07:00
|
|
|
ch = 0x11;
|
2015-06-25 22:57:43 -07:00
|
|
|
break;
|
|
|
|
|
case NT_STRING_ARRAY:
|
2015-09-06 11:00:44 -07:00
|
|
|
ch = 0x12;
|
2015-06-25 22:57:43 -07:00
|
|
|
break;
|
2015-06-21 22:42:01 -07:00
|
|
|
case NT_RPC:
|
2015-06-25 22:57:43 -07:00
|
|
|
if (m_proto_rev < 0x0300u) {
|
|
|
|
|
m_error = "RPC type not supported in protocol < 3.0";
|
2015-06-21 22:42:01 -07:00
|
|
|
return;
|
2015-06-25 22:57:43 -07:00
|
|
|
}
|
2015-09-06 11:00:44 -07:00
|
|
|
ch = 0x20;
|
2015-06-25 22:57:43 -07:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
m_error = "unrecognized type";
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-09-06 11:00:44 -07:00
|
|
|
m_data.push_back(ch);
|
2015-06-21 22:42:01 -07:00
|
|
|
}
|
|
|
|
|
|
2017-08-19 23:08:27 -07:00
|
|
|
size_t WireEncoder::GetValueSize(const Value& value) const {
|
2015-07-16 01:38:27 -07:00
|
|
|
switch (value.type()) {
|
2015-06-21 22:42:01 -07:00
|
|
|
case NT_BOOLEAN:
|
2015-06-25 22:57:43 -07:00
|
|
|
return 1;
|
2015-06-21 22:42:01 -07:00
|
|
|
case NT_DOUBLE:
|
2015-06-25 22:57:43 -07:00
|
|
|
return 8;
|
2015-06-21 22:42:01 -07:00
|
|
|
case NT_STRING:
|
2015-07-16 01:38:27 -07:00
|
|
|
return GetStringSize(value.GetString());
|
2015-06-21 22:42:01 -07:00
|
|
|
case NT_RAW:
|
2015-07-16 01:38:27 -07:00
|
|
|
if (m_proto_rev < 0x0300u) return 0;
|
|
|
|
|
return GetStringSize(value.GetRaw());
|
2015-06-21 22:42:01 -07:00
|
|
|
case NT_RPC:
|
2015-06-25 22:57:43 -07:00
|
|
|
if (m_proto_rev < 0x0300u) return 0;
|
2015-07-16 01:38:27 -07:00
|
|
|
return GetStringSize(value.GetRpc());
|
2015-06-26 01:23:36 -07:00
|
|
|
case NT_BOOLEAN_ARRAY: {
|
|
|
|
|
// 1-byte size, 1 byte per element
|
2017-08-19 23:08:27 -07:00
|
|
|
size_t size = value.GetBooleanArray().size();
|
2016-11-03 21:03:45 -07:00
|
|
|
if (size > 0xff) size = 0xff; // size is only 1 byte, truncate
|
2015-06-26 01:23:36 -07:00
|
|
|
return 1 + size;
|
|
|
|
|
}
|
|
|
|
|
case NT_DOUBLE_ARRAY: {
|
|
|
|
|
// 1-byte size, 8 bytes per element
|
2017-08-19 23:08:27 -07:00
|
|
|
size_t size = value.GetDoubleArray().size();
|
2016-11-03 21:03:45 -07:00
|
|
|
if (size > 0xff) size = 0xff; // size is only 1 byte, truncate
|
2015-06-26 01:23:36 -07:00
|
|
|
return 1 + size * 8;
|
|
|
|
|
}
|
2015-06-25 22:57:43 -07:00
|
|
|
case NT_STRING_ARRAY: {
|
2015-07-16 01:38:27 -07:00
|
|
|
auto v = value.GetStringArray();
|
2017-08-19 23:08:27 -07:00
|
|
|
size_t size = v.size();
|
2016-11-03 21:03:45 -07:00
|
|
|
if (size > 0xff) size = 0xff; // size is only 1 byte, truncate
|
2017-08-19 23:08:27 -07:00
|
|
|
size_t len = 1; // 1-byte size
|
|
|
|
|
for (size_t i = 0; i < size; ++i) len += GetStringSize(v[i]);
|
2015-06-25 22:57:43 -07:00
|
|
|
return len;
|
2015-06-21 22:42:01 -07:00
|
|
|
}
|
|
|
|
|
default:
|
2015-06-25 22:57:43 -07:00
|
|
|
return 0;
|
|
|
|
|
}
|
2015-06-21 22:42:01 -07:00
|
|
|
}
|
|
|
|
|
|
2015-07-16 01:38:27 -07:00
|
|
|
void WireEncoder::WriteValue(const Value& value) {
|
|
|
|
|
switch (value.type()) {
|
2015-06-21 22:42:01 -07:00
|
|
|
case NT_BOOLEAN:
|
2015-07-16 01:38:27 -07:00
|
|
|
Write8(value.GetBoolean() ? 1 : 0);
|
2015-06-25 22:57:43 -07:00
|
|
|
break;
|
2015-06-21 22:42:01 -07:00
|
|
|
case NT_DOUBLE:
|
2015-07-16 01:38:27 -07:00
|
|
|
WriteDouble(value.GetDouble());
|
2015-06-25 22:57:43 -07:00
|
|
|
break;
|
2015-06-21 22:42:01 -07:00
|
|
|
case NT_STRING:
|
2015-07-16 01:38:27 -07:00
|
|
|
WriteString(value.GetString());
|
2015-06-25 22:57:43 -07:00
|
|
|
break;
|
2015-06-21 22:42:01 -07:00
|
|
|
case NT_RAW:
|
2015-07-16 01:38:27 -07:00
|
|
|
if (m_proto_rev < 0x0300u) {
|
|
|
|
|
m_error = "raw values not supported in protocol < 3.0";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
WriteString(value.GetRaw());
|
|
|
|
|
break;
|
2015-06-21 22:42:01 -07:00
|
|
|
case NT_RPC:
|
2015-06-25 22:57:43 -07:00
|
|
|
if (m_proto_rev < 0x0300u) {
|
2015-07-16 01:38:27 -07:00
|
|
|
m_error = "RPC values not supported in protocol < 3.0";
|
2015-06-25 22:57:43 -07:00
|
|
|
return;
|
|
|
|
|
}
|
2015-07-16 01:38:27 -07:00
|
|
|
WriteString(value.GetRpc());
|
2015-06-25 22:57:43 -07:00
|
|
|
break;
|
|
|
|
|
case NT_BOOLEAN_ARRAY: {
|
2015-07-16 01:38:27 -07:00
|
|
|
auto v = value.GetBooleanArray();
|
2017-08-19 23:08:27 -07:00
|
|
|
size_t size = v.size();
|
2016-11-03 21:03:45 -07:00
|
|
|
if (size > 0xff) size = 0xff; // size is only 1 byte, truncate
|
2015-06-25 22:57:43 -07:00
|
|
|
Write8(size);
|
|
|
|
|
|
2017-08-19 23:08:27 -07:00
|
|
|
for (size_t i = 0; i < size; ++i) Write8(v[i] ? 1 : 0);
|
2015-06-25 22:57:43 -07:00
|
|
|
break;
|
2015-06-21 22:42:01 -07:00
|
|
|
}
|
2015-06-25 22:57:43 -07:00
|
|
|
case NT_DOUBLE_ARRAY: {
|
2015-07-16 01:38:27 -07:00
|
|
|
auto v = value.GetDoubleArray();
|
2017-08-19 23:08:27 -07:00
|
|
|
size_t size = v.size();
|
2016-11-03 21:03:45 -07:00
|
|
|
if (size > 0xff) size = 0xff; // size is only 1 byte, truncate
|
2015-06-25 22:57:43 -07:00
|
|
|
Write8(size);
|
|
|
|
|
|
2017-08-19 23:08:27 -07:00
|
|
|
for (size_t i = 0; i < size; ++i) WriteDouble(v[i]);
|
2015-06-25 22:57:43 -07:00
|
|
|
break;
|
2015-06-21 22:42:01 -07:00
|
|
|
}
|
2015-06-25 22:57:43 -07:00
|
|
|
case NT_STRING_ARRAY: {
|
2015-07-16 01:38:27 -07:00
|
|
|
auto v = value.GetStringArray();
|
2017-08-19 23:08:27 -07:00
|
|
|
size_t size = v.size();
|
2016-11-03 21:03:45 -07:00
|
|
|
if (size > 0xff) size = 0xff; // size is only 1 byte, truncate
|
2015-06-25 22:57:43 -07:00
|
|
|
Write8(size);
|
|
|
|
|
|
2017-08-19 23:08:27 -07:00
|
|
|
for (size_t i = 0; i < size; ++i) WriteString(v[i]);
|
2015-06-25 22:57:43 -07:00
|
|
|
break;
|
2015-06-21 22:42:01 -07:00
|
|
|
}
|
|
|
|
|
default:
|
2015-06-25 22:57:43 -07:00
|
|
|
m_error = "unrecognized type when writing value";
|
|
|
|
|
return;
|
|
|
|
|
}
|
2015-06-21 22:42:01 -07:00
|
|
|
}
|
|
|
|
|
|
2018-04-29 23:33:19 -07:00
|
|
|
size_t WireEncoder::GetStringSize(wpi::StringRef str) const {
|
2015-06-26 01:23:36 -07:00
|
|
|
if (m_proto_rev < 0x0300u) {
|
2017-08-19 23:08:27 -07:00
|
|
|
size_t len = str.size();
|
2016-11-03 21:03:45 -07:00
|
|
|
if (len > 0xffff) len = 0xffff; // Limited to 64K length; truncate
|
2015-06-26 01:23:36 -07:00
|
|
|
return 2 + len;
|
|
|
|
|
}
|
2016-07-27 00:39:38 -07:00
|
|
|
return wpi::SizeUleb128(str.size()) + str.size();
|
2015-06-21 22:42:01 -07:00
|
|
|
}
|
|
|
|
|
|
2018-04-29 23:33:19 -07:00
|
|
|
void WireEncoder::WriteString(wpi::StringRef str) {
|
2015-06-25 22:57:43 -07:00
|
|
|
// length
|
2017-08-19 23:08:27 -07:00
|
|
|
size_t len = str.size();
|
2015-06-25 22:57:43 -07:00
|
|
|
if (m_proto_rev < 0x0300u) {
|
2016-11-03 21:03:45 -07:00
|
|
|
if (len > 0xffff) len = 0xffff; // Limited to 64K length; truncate
|
2015-06-25 22:57:43 -07:00
|
|
|
Write16(len);
|
2017-08-19 23:08:27 -07:00
|
|
|
} else {
|
2015-06-25 23:19:24 -07:00
|
|
|
WriteUleb128(len);
|
2017-08-19 23:08:27 -07:00
|
|
|
}
|
2015-06-25 22:57:43 -07:00
|
|
|
|
|
|
|
|
// contents
|
2015-09-06 11:00:44 -07:00
|
|
|
m_data.append(str.data(), str.data() + len);
|
2015-06-21 22:42:01 -07:00
|
|
|
}
|