mirror of https://github.com/ARMmbed/mbed-os.git
NFC: Add payload builder into ndef::MessageBuilder
parent
b5bfcc3fcb
commit
b6e604338e
|
|
@ -38,6 +38,31 @@ namespace ndef {
|
||||||
class MessageBuilder {
|
class MessageBuilder {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* Build a record payload.
|
||||||
|
*/
|
||||||
|
struct PayloadBuilder {
|
||||||
|
/**
|
||||||
|
* Return the size of the payload built by this object.
|
||||||
|
*
|
||||||
|
* @return The size of the payload.
|
||||||
|
*/
|
||||||
|
virtual size_t size() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build the payload in a buffer that has the required size.
|
||||||
|
*
|
||||||
|
* @param buffer The buffer used to construct the payload.
|
||||||
|
*/
|
||||||
|
virtual void build(const Span<uint8_t>& buffer) const = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Non virtual destructor.
|
||||||
|
*/
|
||||||
|
~PayloadBuilder() { }
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new MessageBuilder that can be used to construct valid NDEF
|
* Create a new MessageBuilder that can be used to construct valid NDEF
|
||||||
* messages.
|
* messages.
|
||||||
|
|
@ -67,6 +92,27 @@ public:
|
||||||
bool is_last_record = false
|
bool is_last_record = false
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Append a new record to the message being built.
|
||||||
|
*
|
||||||
|
* @param type The type of the record to insert.
|
||||||
|
* @param builder The builder of the payload.
|
||||||
|
* @param is_last_record true if the record to insert is the last record of
|
||||||
|
* the payload or false otherwise.
|
||||||
|
*
|
||||||
|
* @return true if the record has been successfully inserted or false
|
||||||
|
* otherwise.
|
||||||
|
*
|
||||||
|
* @note insertion can fail if the message is already complete or if the
|
||||||
|
* size remaining in the message buffer is not large enough to makes the
|
||||||
|
* record inserted fit.
|
||||||
|
*/
|
||||||
|
bool append_record(
|
||||||
|
const RecordType &type,
|
||||||
|
const PayloadBuilder &builder,
|
||||||
|
bool is_last_record = false
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append a new record to the message being built.
|
* Append a new record to the message being built.
|
||||||
*
|
*
|
||||||
|
|
@ -78,7 +124,23 @@ public:
|
||||||
* size remaining in the message buffer is not large enough to makes the
|
* size remaining in the message buffer is not large enough to makes the
|
||||||
* record inserted fit.
|
* record inserted fit.
|
||||||
*/
|
*/
|
||||||
bool append_record(const Record &record);
|
bool append_record(
|
||||||
|
const Record &record,
|
||||||
|
const PayloadBuilder *builder = NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute the size of a record.
|
||||||
|
*
|
||||||
|
* @param record The record used to compute the size.
|
||||||
|
* @param builder The payload builder if any.
|
||||||
|
*
|
||||||
|
* @return The size of the payload for the record in input.
|
||||||
|
*/
|
||||||
|
static size_t compute_record_size(
|
||||||
|
const Record &record,
|
||||||
|
const PayloadBuilder* builder = NULL
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset the builder state.
|
* Reset the builder state.
|
||||||
|
|
@ -107,17 +169,17 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// append fields
|
// append fields
|
||||||
void append_header(const Record &record);
|
void append_header(const Record &record, const PayloadBuilder*);
|
||||||
void append_type_length(const Record &record);
|
void append_type_length(const Record &record);
|
||||||
void append_payload_length(const Record &);
|
void append_payload_length(const Record &, const PayloadBuilder*);
|
||||||
void append_id_length(const Record &);
|
void append_id_length(const Record &);
|
||||||
void append_type(const Record &);
|
void append_type(const Record &);
|
||||||
void append_id(const Record &);
|
void append_id(const Record &);
|
||||||
void append_payload(const Record &);
|
void append_payload(const Record &, const PayloadBuilder*);
|
||||||
|
|
||||||
// helpers
|
// helpers
|
||||||
static size_t compute_record_size(const Record &record);
|
static bool is_short_payload(const Record &record, const PayloadBuilder*);
|
||||||
static bool is_short_payload(const Record &record);
|
static size_t get_payload_size(const Record &, const PayloadBuilder*);
|
||||||
|
|
||||||
// builder state.
|
// builder state.
|
||||||
Span<uint8_t> _message_buffer;
|
Span<uint8_t> _message_buffer;
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,24 @@ bool MessageBuilder::append_record(
|
||||||
return append_record(record);
|
return append_record(record);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MessageBuilder::append_record(const Record &record)
|
bool MessageBuilder::append_record(
|
||||||
|
const RecordType &type,
|
||||||
|
const PayloadBuilder &builder,
|
||||||
|
bool is_last_record
|
||||||
|
) {
|
||||||
|
Record record(
|
||||||
|
type,
|
||||||
|
RecordPayload(),
|
||||||
|
RecordID(),
|
||||||
|
/* chunk */ false,
|
||||||
|
is_last_record
|
||||||
|
);
|
||||||
|
|
||||||
|
return append_record(record, &builder);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool MessageBuilder::append_record(const Record &record, const PayloadBuilder *builder)
|
||||||
{
|
{
|
||||||
if (_message_ended) {
|
if (_message_ended) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -88,7 +105,7 @@ bool MessageBuilder::append_record(const Record &record)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!record.payload.empty()) {
|
if (get_payload_size(record, builder)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -107,18 +124,18 @@ bool MessageBuilder::append_record(const Record &record)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t record_size = compute_record_size(record);
|
size_t record_size = compute_record_size(record, builder);
|
||||||
if (record_size > (_message_buffer.size() - _position)) {
|
if (record_size > (_message_buffer.size() - _position)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
append_header(record);
|
append_header(record, builder);
|
||||||
append_type_length(record);
|
append_type_length(record);
|
||||||
append_payload_length(record);
|
append_payload_length(record, builder);
|
||||||
append_id_length(record);
|
append_id_length(record);
|
||||||
append_type(record);
|
append_type(record);
|
||||||
append_id(record);
|
append_id(record);
|
||||||
append_payload(record);
|
append_payload(record, builder);
|
||||||
|
|
||||||
if (record.chunk) {
|
if (record.chunk) {
|
||||||
_in_chunk = true;
|
_in_chunk = true;
|
||||||
|
|
@ -161,12 +178,12 @@ Span<const uint8_t> MessageBuilder::get_message() const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t MessageBuilder::compute_record_size(const Record &record)
|
size_t MessageBuilder::compute_record_size(const Record &record, const PayloadBuilder *builder)
|
||||||
{
|
{
|
||||||
size_t record_size = 0;
|
size_t record_size = 0;
|
||||||
record_size = 1; /* header */
|
record_size = 1; /* header */
|
||||||
record_size += 1; /* type length */
|
record_size += 1; /* type length */
|
||||||
record_size += is_short_payload(record) ? 1 : 4;
|
record_size += is_short_payload(record, builder) ? 1 : 4;
|
||||||
|
|
||||||
if (!record.id.empty()) {
|
if (!record.id.empty()) {
|
||||||
record_size += 1;
|
record_size += 1;
|
||||||
|
|
@ -174,12 +191,12 @@ size_t MessageBuilder::compute_record_size(const Record &record)
|
||||||
|
|
||||||
record_size += record.type.value.size();
|
record_size += record.type.value.size();
|
||||||
record_size += record.id.size();
|
record_size += record.id.size();
|
||||||
record_size += record.payload.size();
|
record_size += get_payload_size(record, builder);
|
||||||
|
|
||||||
return record_size;
|
return record_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageBuilder::append_header(const Record &record)
|
void MessageBuilder::append_header(const Record &record, const PayloadBuilder *builder)
|
||||||
{
|
{
|
||||||
uint8_t header = 0;
|
uint8_t header = 0;
|
||||||
if (!_message_started) {
|
if (!_message_started) {
|
||||||
|
|
@ -196,7 +213,7 @@ void MessageBuilder::append_header(const Record &record)
|
||||||
header |= Header::chunk_flag_bit;
|
header |= Header::chunk_flag_bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_short_payload(record)) {
|
if (is_short_payload(record, builder)) {
|
||||||
header |= Header::short_record_bit;
|
header |= Header::short_record_bit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -213,18 +230,13 @@ void MessageBuilder::append_type_length(const Record &record)
|
||||||
_message_buffer[_position++] = record.type.value.size();
|
_message_buffer[_position++] = record.type.value.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageBuilder::append_payload_length(const Record &record)
|
void MessageBuilder::append_payload_length(const Record &record, const PayloadBuilder *builder)
|
||||||
{
|
{
|
||||||
if (record.payload.empty()) {
|
size_t size = get_payload_size(record, builder);
|
||||||
_message_buffer[_position++] = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_short_payload(record)) {
|
if (is_short_payload(record, builder)) {
|
||||||
_message_buffer[_position++] = record.payload.size();
|
_message_buffer[_position++] = size;
|
||||||
} else {
|
} else {
|
||||||
// TODO: proper host to network
|
|
||||||
uint32_t size = record.payload.size();
|
|
||||||
_message_buffer[_position++] = (size >> 24) & 0xFF;
|
_message_buffer[_position++] = (size >> 24) & 0xFF;
|
||||||
_message_buffer[_position++] = (size >> 16) & 0xFF;
|
_message_buffer[_position++] = (size >> 16) & 0xFF;
|
||||||
_message_buffer[_position++] = (size >> 8) & 0xFF;
|
_message_buffer[_position++] = (size >> 8) & 0xFF;
|
||||||
|
|
@ -269,29 +281,40 @@ void MessageBuilder::append_id(const Record &record)
|
||||||
_position += record.id.size();
|
_position += record.id.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageBuilder::append_payload(const Record &record)
|
void MessageBuilder::append_payload(const Record &record, const PayloadBuilder *builder)
|
||||||
{
|
{
|
||||||
if (record.payload.empty()) {
|
size_t size = get_payload_size(record, builder);
|
||||||
|
if (!size) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (builder) {
|
||||||
|
builder->build(_message_buffer.subspan(_position, size));
|
||||||
|
} else {
|
||||||
memcpy(
|
memcpy(
|
||||||
_message_buffer.data() + _position,
|
_message_buffer.data() + _position,
|
||||||
record.payload.data(),
|
record.payload.data(),
|
||||||
record.payload.size()
|
size
|
||||||
);
|
);
|
||||||
_position += record.payload.size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MessageBuilder::is_short_payload(const Record &record)
|
_position += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MessageBuilder::is_short_payload(const Record &record, const PayloadBuilder *builder)
|
||||||
{
|
{
|
||||||
if (record.payload.size() <= 255) {
|
if (get_payload_size(record, builder) <= 255) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t MessageBuilder::get_payload_size(const Record &record, const PayloadBuilder *builder)
|
||||||
|
{
|
||||||
|
return builder ? builder->size() : record.payload.size();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ndef
|
} // namespace ndef
|
||||||
} // namespace nfc
|
} // namespace nfc
|
||||||
} // namespace mbed
|
} // namespace mbed
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue