2015-06-21 21:43:05 -07:00
|
|
|
/*----------------------------------------------------------------------------*/
|
2017-08-19 23:08:27 -07:00
|
|
|
/* Copyright (c) FIRST 2015-2017. All Rights Reserved. */
|
2015-06-21 21:43:05 -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 "WireDecoder.h"
|
2015-06-21 21:43:05 -07:00
|
|
|
|
2017-08-19 23:08:27 -07:00
|
|
|
#include <stdint.h>
|
|
|
|
|
|
2015-06-21 21:43:05 -07:00
|
|
|
#include <cassert>
|
|
|
|
|
#include <cstdlib>
|
|
|
|
|
#include <cstring>
|
|
|
|
|
|
2017-08-19 23:08:27 -07:00
|
|
|
#include <llvm/MathExtras.h>
|
|
|
|
|
#include <support/leb128.h>
|
2015-06-21 21:43:05 -07:00
|
|
|
|
2015-07-17 07:21:07 -07:00
|
|
|
using namespace nt;
|
2015-06-21 21:43:05 -07:00
|
|
|
|
2015-07-05 16:15:58 -07:00
|
|
|
static double ReadDouble(const char*& buf) {
|
2015-06-26 01:23:36 -07:00
|
|
|
// Fast but non-portable!
|
2017-08-19 23:08:27 -07:00
|
|
|
uint64_t val = (*reinterpret_cast<const unsigned char*>(buf)) & 0xff;
|
2015-06-25 22:57:43 -07:00
|
|
|
++buf;
|
|
|
|
|
val <<= 8;
|
2015-11-28 13:12:30 -08:00
|
|
|
val |= (*reinterpret_cast<const unsigned char*>(buf)) & 0xff;
|
2015-06-25 22:57:43 -07:00
|
|
|
++buf;
|
|
|
|
|
val <<= 8;
|
2015-11-28 13:12:30 -08:00
|
|
|
val |= (*reinterpret_cast<const unsigned char*>(buf)) & 0xff;
|
2015-06-25 22:57:43 -07:00
|
|
|
++buf;
|
|
|
|
|
val <<= 8;
|
2015-11-28 13:12:30 -08:00
|
|
|
val |= (*reinterpret_cast<const unsigned char*>(buf)) & 0xff;
|
2015-06-25 22:57:43 -07:00
|
|
|
++buf;
|
|
|
|
|
val <<= 8;
|
2015-11-28 13:12:30 -08:00
|
|
|
val |= (*reinterpret_cast<const unsigned char*>(buf)) & 0xff;
|
2015-06-25 22:57:43 -07:00
|
|
|
++buf;
|
|
|
|
|
val <<= 8;
|
2015-11-28 13:12:30 -08:00
|
|
|
val |= (*reinterpret_cast<const unsigned char*>(buf)) & 0xff;
|
2015-06-25 22:57:43 -07:00
|
|
|
++buf;
|
|
|
|
|
val <<= 8;
|
2015-11-28 13:12:30 -08:00
|
|
|
val |= (*reinterpret_cast<const unsigned char*>(buf)) & 0xff;
|
2015-06-25 22:57:43 -07:00
|
|
|
++buf;
|
|
|
|
|
val <<= 8;
|
2015-11-28 13:12:30 -08:00
|
|
|
val |= (*reinterpret_cast<const unsigned char*>(buf)) & 0xff;
|
2015-06-25 22:57:43 -07:00
|
|
|
++buf;
|
2015-08-12 17:15:10 -07:00
|
|
|
return llvm::BitsToDouble(val);
|
2015-06-21 22:03:51 -07:00
|
|
|
}
|
|
|
|
|
|
Implement independent instances.
Previously, most of the classes were implemented as singletons so only one
instance was possible.
This change adds an instance handle-based API. In Java, this API is located
in a different package than the old API (edu.wpi.first.networktables).
Backwards compatibility with ITable and the old NetworkTable API is largely
maintained, but a handful of classes have moved to the new package in Java
(ConnectionInfo and PersistentException), and the old JNI has been completed
replaced.
Also:
- Move SetTeam implementation to Dispatcher.
- Consistently pass time through Java and C++ Value API.
- Rename nt_Value.h to NetworkTableValue.h for consistency with Java.
- Improve documentation
- Make C++ and Java APIs more consistent
- Document RPC functions and support RPC in Java.
- Add polling features for entry and connection listeners and use them to
move callback threads to Java level.
- Remove thread start and stop hooks (as polling is available).
- Make Notifiers, RpcServer, Dispatcher, and Storage mockable.
- Set NOTIFY_NEW on immediate entry notifications.
- Make GetTable("/") and GetTable("") equivalent.
- Generate local notification for flags update when loading persistent file.
And many unit test updates/changes:
- Use InitGoogleMock instead of InitGoogleTest in test main.
- Move test printers to TestPrinter.h/cpp.
- Provide printers for StringRef, EntryNotifier, and Handle.
- StorageTest: Check notifications.
- Add entry notifier unit tests.
- Storage: Add test for incoming entry assignment.
- Update connection listener tests.
- Add entry listener unit tests.
Fixes #11, #140, #189, #190, #192, #193, #221
2017-04-23 10:26:17 -07:00
|
|
|
WireDecoder::WireDecoder(wpi::raw_istream& is, unsigned int proto_rev,
|
|
|
|
|
wpi::Logger& logger)
|
|
|
|
|
: m_is(is), m_logger(logger) {
|
2015-06-26 01:23:36 -07:00
|
|
|
// Start with a 1K temporary buffer. Use malloc instead of new so we can
|
|
|
|
|
// realloc.
|
2015-06-25 22:57:43 -07:00
|
|
|
m_allocated = 1024;
|
2015-06-26 01:23:36 -07:00
|
|
|
m_buf = static_cast<char*>(std::malloc(m_allocated));
|
2015-06-25 22:57:43 -07:00
|
|
|
m_proto_rev = proto_rev;
|
|
|
|
|
m_error = nullptr;
|
2015-06-21 21:43:05 -07:00
|
|
|
}
|
|
|
|
|
|
2015-06-25 22:57:43 -07:00
|
|
|
WireDecoder::~WireDecoder() { std::free(m_buf); }
|
2015-06-21 21:43:05 -07:00
|
|
|
|
2015-06-25 22:57:43 -07:00
|
|
|
bool WireDecoder::ReadDouble(double* val) {
|
2015-07-05 16:15:58 -07:00
|
|
|
const char* buf;
|
2015-06-25 22:57:43 -07:00
|
|
|
if (!Read(&buf, 8)) return false;
|
2015-06-26 01:23:36 -07:00
|
|
|
*val = ::ReadDouble(buf);
|
2015-06-25 22:57:43 -07:00
|
|
|
return true;
|
2015-06-21 22:03:51 -07:00
|
|
|
}
|
|
|
|
|
|
2017-08-19 23:08:27 -07:00
|
|
|
void WireDecoder::Realloc(size_t len) {
|
2015-06-26 01:23:36 -07:00
|
|
|
// Double current buffer size until we have enough space.
|
2015-06-25 22:57:43 -07:00
|
|
|
if (m_allocated >= len) return;
|
2017-08-19 23:08:27 -07:00
|
|
|
size_t newlen = m_allocated * 2;
|
2015-06-25 22:57:43 -07:00
|
|
|
while (newlen < len) newlen *= 2;
|
2015-06-26 01:23:36 -07:00
|
|
|
m_buf = static_cast<char*>(std::realloc(m_buf, newlen));
|
2015-06-25 22:57:43 -07:00
|
|
|
m_allocated = newlen;
|
2015-06-21 21:43:05 -07:00
|
|
|
}
|
|
|
|
|
|
2015-06-25 22:57:43 -07:00
|
|
|
bool WireDecoder::ReadType(NT_Type* type) {
|
|
|
|
|
unsigned int itype;
|
|
|
|
|
if (!Read8(&itype)) return false;
|
2015-06-26 01:23:36 -07:00
|
|
|
// Convert from byte value to enum
|
2015-06-25 22:57:43 -07:00
|
|
|
switch (itype) {
|
|
|
|
|
case 0x00:
|
|
|
|
|
*type = NT_BOOLEAN;
|
|
|
|
|
break;
|
|
|
|
|
case 0x01:
|
|
|
|
|
*type = NT_DOUBLE;
|
|
|
|
|
break;
|
|
|
|
|
case 0x02:
|
|
|
|
|
*type = NT_STRING;
|
|
|
|
|
break;
|
|
|
|
|
case 0x03:
|
|
|
|
|
*type = NT_RAW;
|
|
|
|
|
break;
|
|
|
|
|
case 0x10:
|
|
|
|
|
*type = NT_BOOLEAN_ARRAY;
|
|
|
|
|
break;
|
|
|
|
|
case 0x11:
|
|
|
|
|
*type = NT_DOUBLE_ARRAY;
|
|
|
|
|
break;
|
|
|
|
|
case 0x12:
|
|
|
|
|
*type = NT_STRING_ARRAY;
|
|
|
|
|
break;
|
|
|
|
|
case 0x20:
|
|
|
|
|
*type = NT_RPC;
|
|
|
|
|
break;
|
2015-06-21 21:43:05 -07:00
|
|
|
default:
|
2015-07-04 23:10:59 -07:00
|
|
|
*type = NT_UNASSIGNED;
|
2015-06-25 22:57:43 -07:00
|
|
|
m_error = "unrecognized value type";
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
2015-06-21 21:43:05 -07:00
|
|
|
}
|
|
|
|
|
|
2015-07-16 01:38:27 -07:00
|
|
|
std::shared_ptr<Value> WireDecoder::ReadValue(NT_Type type) {
|
2015-06-25 22:57:43 -07:00
|
|
|
switch (type) {
|
|
|
|
|
case NT_BOOLEAN: {
|
|
|
|
|
unsigned int v;
|
2015-07-16 01:38:27 -07:00
|
|
|
if (!Read8(&v)) return nullptr;
|
|
|
|
|
return Value::MakeBoolean(v != 0);
|
2015-06-21 21:43:05 -07:00
|
|
|
}
|
2015-06-25 22:57:43 -07:00
|
|
|
case NT_DOUBLE: {
|
2015-07-16 01:38:27 -07:00
|
|
|
double v;
|
|
|
|
|
if (!ReadDouble(&v)) return nullptr;
|
|
|
|
|
return Value::MakeDouble(v);
|
2015-06-21 21:43:05 -07:00
|
|
|
}
|
2015-07-16 01:38:27 -07:00
|
|
|
case NT_STRING: {
|
|
|
|
|
std::string v;
|
|
|
|
|
if (!ReadString(&v)) return nullptr;
|
|
|
|
|
return Value::MakeString(std::move(v));
|
|
|
|
|
}
|
|
|
|
|
case NT_RAW: {
|
2015-06-25 22:57:43 -07:00
|
|
|
if (m_proto_rev < 0x0300u) {
|
2015-07-16 01:38:27 -07:00
|
|
|
m_error = "received raw value in protocol < 3.0";
|
|
|
|
|
return nullptr;
|
2015-06-25 22:57:43 -07:00
|
|
|
}
|
2015-07-16 01:38:27 -07:00
|
|
|
std::string v;
|
|
|
|
|
if (!ReadString(&v)) return nullptr;
|
|
|
|
|
return Value::MakeRaw(std::move(v));
|
|
|
|
|
}
|
|
|
|
|
case NT_RPC: {
|
|
|
|
|
if (m_proto_rev < 0x0300u) {
|
|
|
|
|
m_error = "received RPC value in protocol < 3.0";
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
std::string v;
|
|
|
|
|
if (!ReadString(&v)) return nullptr;
|
|
|
|
|
return Value::MakeRpc(std::move(v));
|
|
|
|
|
}
|
2015-06-25 22:57:43 -07:00
|
|
|
case NT_BOOLEAN_ARRAY: {
|
|
|
|
|
// size
|
|
|
|
|
unsigned int size;
|
2015-07-16 01:38:27 -07:00
|
|
|
if (!Read8(&size)) return nullptr;
|
2015-06-21 21:43:05 -07:00
|
|
|
|
2015-06-25 22:57:43 -07:00
|
|
|
// array values
|
2015-07-05 16:15:58 -07:00
|
|
|
const char* buf;
|
2015-07-16 01:38:27 -07:00
|
|
|
if (!Read(&buf, size)) return nullptr;
|
|
|
|
|
std::vector<int> v(size);
|
2016-11-03 21:03:45 -07:00
|
|
|
for (unsigned int i = 0; i < size; ++i) v[i] = buf[i] ? 1 : 0;
|
2015-07-16 01:38:27 -07:00
|
|
|
return Value::MakeBooleanArray(std::move(v));
|
2015-06-21 21:43:05 -07:00
|
|
|
}
|
2015-06-25 22:57:43 -07:00
|
|
|
case NT_DOUBLE_ARRAY: {
|
|
|
|
|
// size
|
|
|
|
|
unsigned int size;
|
2015-07-16 01:38:27 -07:00
|
|
|
if (!Read8(&size)) return nullptr;
|
2015-06-21 21:43:05 -07:00
|
|
|
|
2015-06-25 22:57:43 -07:00
|
|
|
// array values
|
2015-07-05 16:15:58 -07:00
|
|
|
const char* buf;
|
2015-07-16 01:38:27 -07:00
|
|
|
if (!Read(&buf, size * 8)) return nullptr;
|
|
|
|
|
std::vector<double> v(size);
|
2016-11-03 21:03:45 -07:00
|
|
|
for (unsigned int i = 0; i < size; ++i) v[i] = ::ReadDouble(buf);
|
2015-07-16 01:38:27 -07:00
|
|
|
return Value::MakeDoubleArray(std::move(v));
|
2015-06-21 21:43:05 -07:00
|
|
|
}
|
2015-06-25 22:57:43 -07:00
|
|
|
case NT_STRING_ARRAY: {
|
|
|
|
|
// size
|
|
|
|
|
unsigned int size;
|
2015-07-16 01:38:27 -07:00
|
|
|
if (!Read8(&size)) return nullptr;
|
2015-06-21 21:43:05 -07:00
|
|
|
|
2015-06-25 22:57:43 -07:00
|
|
|
// array values
|
2015-07-16 01:38:27 -07:00
|
|
|
std::vector<std::string> v(size);
|
2015-06-25 22:57:43 -07:00
|
|
|
for (unsigned int i = 0; i < size; ++i) {
|
2015-07-16 01:38:27 -07:00
|
|
|
if (!ReadString(&v[i])) return nullptr;
|
2015-06-25 22:57:43 -07:00
|
|
|
}
|
2015-07-16 01:38:27 -07:00
|
|
|
return Value::MakeStringArray(std::move(v));
|
2015-06-21 21:43:05 -07:00
|
|
|
}
|
|
|
|
|
default:
|
2015-06-25 22:57:43 -07:00
|
|
|
m_error = "invalid type when trying to read value";
|
2015-07-16 01:38:27 -07:00
|
|
|
return nullptr;
|
2015-06-25 22:57:43 -07:00
|
|
|
}
|
2015-06-21 21:43:05 -07:00
|
|
|
}
|
|
|
|
|
|
2015-07-16 01:38:27 -07:00
|
|
|
bool WireDecoder::ReadString(std::string* str) {
|
|
|
|
|
size_t len;
|
2015-06-25 22:57:43 -07:00
|
|
|
if (m_proto_rev < 0x0300u) {
|
|
|
|
|
unsigned int v;
|
|
|
|
|
if (!Read16(&v)) return false;
|
2015-07-16 01:38:27 -07:00
|
|
|
len = v;
|
2015-06-25 22:57:43 -07:00
|
|
|
} else {
|
2017-08-19 23:08:27 -07:00
|
|
|
uint64_t v;
|
2015-06-25 23:19:24 -07:00
|
|
|
if (!ReadUleb128(&v)) return false;
|
2015-07-16 01:38:27 -07:00
|
|
|
len = v;
|
2015-06-25 22:57:43 -07:00
|
|
|
}
|
2015-07-16 01:38:27 -07:00
|
|
|
const char* buf;
|
|
|
|
|
if (!Read(&buf, len)) return false;
|
|
|
|
|
*str = llvm::StringRef(buf, len);
|
2015-06-25 22:57:43 -07:00
|
|
|
return true;
|
2015-06-21 21:43:05 -07:00
|
|
|
}
|