mirror of https://github.com/ARMmbed/mbed-os.git
commit
5cb43e6bb3
|
@ -7,7 +7,7 @@ NFC offers three modes;
|
|||
2. NFC reader/writer
|
||||
3. NFC peer to peer
|
||||
|
||||
To support new use cases such as commissioning, BLE pairing and identification/authentication of NFC enabled IoT endpoints, Mbed OS should support the card emulation mode.
|
||||
To support new use cases such as commissioning, BLE pairing and identification/authentication of NFC enabled IoT endpoints, Mbed OS should support the card emulation mode.
|
||||
|
||||
However the architecture should be future-proofed and should also be extendable to support other NFC modes in the future.
|
||||
|
||||
|
@ -114,7 +114,7 @@ nfc_rf_protocols_bitmask_t get_supported_rf_protocols() const;
|
|||
Retrieve the list of supported RF protocols.
|
||||
These are mapped against NFC Forum-defined protocols.
|
||||
|
||||
* T1T is based on ISO/IEC 14443A-3 and commonly known as Topaz (Innovision).
|
||||
* T1T is based on ISO/IEC 14443A-3 and commonly known as Topaz (Innovision).
|
||||
* T2T is based on ISO/IEC 14443A-3 and commonly known as Mifare Ultralight/NTAG (NXP).
|
||||
* T3T is based on JIS X6319-4, also known as Felica (Sony).
|
||||
* ISO-DEP is based on ISO/IEC 14443-4 and is the common interface for contactless smartcards. The underlying radio protocol can either be ISO/IEC 14443A or ISO/IEC 14443B.
|
||||
|
@ -261,72 +261,13 @@ The `NFCRemoteTarget` class derives from `NFCTarget` and additionally from `NFCE
|
|||
|
||||
## NDEF API
|
||||
|
||||
![ndef_diagram]
|
||||
|
||||
The NDEF API is constructed with these requirements in mind:
|
||||
* Minimizing memory allocation/copies
|
||||
* NFC Forum compliance
|
||||
* Ease of use
|
||||
* Extensibility
|
||||
|
||||
#### NDEF Message
|
||||
|
||||
A NDEF Message is made of multiple NDEF Records which is reflected by the API:
|
||||
|
||||
```cpp
|
||||
bool parse(const uint8_t* buffer, size_t sz)
|
||||
size_t count()
|
||||
NDEFRecord operator[](size_t n)
|
||||
```
|
||||
|
||||
The message can be mapped with a byte array and individual records are decoded/populated on the fly.
|
||||
|
||||
#### NDEF Message builder
|
||||
|
||||
We're using a builder pattern to encode an NDEF message over a byte array.
|
||||
|
||||
```cpp
|
||||
NDEFMessageBuilder(uint8_t* buffer, size_t max_sz)
|
||||
bool add_record(const NDEFRecord& record)
|
||||
NDEFMessage build()
|
||||
```
|
||||
|
||||
A reference to the array is provided in the constructor and records can be appended by the user (within memory limits).
|
||||
|
||||
Once done a NDEFMessage instance mapped to a subset of the byte array can be generated.
|
||||
|
||||
#### NDEF Record
|
||||
|
||||
The NDEF Record class is closely mapped with the NFC NDEF specification.
|
||||
|
||||
Each record holds:
|
||||
* A Type Name Format indicator - indicates which namespace the type field belongs to ('Well-known NDEF types', MIME, Absolute URI, etc.)
|
||||
* A type field
|
||||
* An optional ID field
|
||||
* The record's value
|
||||
|
||||
All arrays are passed by reference (no copy made).
|
||||
|
||||
```cpp
|
||||
static bool parse(const uint8_t* buffer, size_t max_sz)
|
||||
ssize_t build(const uint8_t* buffer, size_t max_sz)
|
||||
|
||||
uint8_t tnf()
|
||||
void set_tnf(uint8_t tnf)
|
||||
|
||||
const uint8_t* type() const
|
||||
size_t type_size() const
|
||||
void set_type(const uint8_t* type, size_t type_size)
|
||||
|
||||
const uint8_t* id() const
|
||||
size_t id_size() const
|
||||
void set_id(const uint8_t* id, size_t id_size)
|
||||
|
||||
const uint8_t* value() const
|
||||
size_t value_size() const
|
||||
void set_value(const uint8_t* type, size_t type_size)
|
||||
```
|
||||
|
||||
**Helpers**
|
||||
### Common objects
|
||||
|
||||
We will provide multiple helpers to make it easy to create/parse common record types:
|
||||
* URI
|
||||
|
@ -334,11 +275,8 @@ We will provide multiple helpers to make it easy to create/parse common record t
|
|||
* Smart Poster
|
||||
* MIME data
|
||||
|
||||
For instance, the `URIRecord`'s class API is as follows:
|
||||
For instance, the `URI`'s class API is as follows:
|
||||
```cpp
|
||||
static bool is_uri_record(const NDEFRecord& record)
|
||||
static URIRecord as_uri_record(const NDEFRecord& record)
|
||||
|
||||
uri_prefix_t uri_prefix() const
|
||||
void set_uri_prefix(uri_prefix_t prefix)
|
||||
|
||||
|
@ -351,9 +289,162 @@ size_t full_uri_size() const
|
|||
void set_full_uri(const char* uri)
|
||||
```
|
||||
|
||||
This includes some helper classes to check whether a record is an URI record, and if so to construct an `URIRecord` instance from a `NDEFRecord`.
|
||||
**Note:** These types can be replaced by user defined ones if parsing and serialization logic is provided.
|
||||
|
||||
In this case buffers are copied to account for the NULL-terminator character that is not present in the underlying byte buffer.
|
||||
### Parsing
|
||||
|
||||
#### ndef::MessageParser
|
||||
|
||||
![ndef_message_parser_diagram]
|
||||
|
||||
Messages incoming from the peer are parsed by a `MessageParser` which produce
|
||||
`Record` instances to its client. The parsing operation is event-driven: a
|
||||
message parser client registers a delegate inside the message parser. This delegate
|
||||
gets notified whenever an interesting event happens during the parsing.
|
||||
|
||||
```cpp
|
||||
void set_delegate(Delegate* delegate);
|
||||
void parse(const ac_buffer_t& data_buffer);
|
||||
```
|
||||
|
||||
It is important to note that the data_buffer in entry of the parse function must
|
||||
contain the entire NDEF message.
|
||||
|
||||
##### ndef::MessageParser::Delegate
|
||||
|
||||
```cpp
|
||||
virtual void on_parsing_started() { }
|
||||
virtual void on_record_parsed(const Record& record) { }
|
||||
virtual void on_parsing_terminated() { }
|
||||
virtual void on_parsing_error(error_t error) { }
|
||||
```
|
||||
|
||||
The delegate is notified by the parser when the parsing start or end; when an error
|
||||
is encountered or when an ndef `Record` has been parsed.
|
||||
|
||||
To reduce memory consumption `Record` instances generated by the parser are short
|
||||
lived. They are only valid during the callback invocation. If a client is interested
|
||||
by the content of a message parsed and wants to use it after the parsing callback
|
||||
then it must make a copy of the record object.
|
||||
|
||||
#### NDEF Record parsing
|
||||
|
||||
![ndef_record_parser_diagram]
|
||||
|
||||
NDEF records can contain any type of content. Therefore parsing of records is
|
||||
specific to the application. To help the developer; an optional ndef record
|
||||
parsing framework is included. It follows the _chain-of-responsibility_ design
|
||||
pattern that facilitate the integration of record parsers defined by client code.
|
||||
|
||||
##### ndef::RecordParser
|
||||
|
||||
Is is the base building block of the record parsing frame working. It parses a
|
||||
record then return true if the record has been parsed or false otherwise.
|
||||
|
||||
```cpp
|
||||
virtual bool parse(const Record&);
|
||||
```
|
||||
|
||||
##### ndef::RecordParserChain
|
||||
|
||||
It aggregate `RecordParser` instances and defer parsing to the instances it contains.
|
||||
|
||||
```cpp
|
||||
bool parse(const Record& record);
|
||||
void set_next_parser(RecordParser* parser);
|
||||
```
|
||||
|
||||
##### ndef::GenericRecordParser<ParserImplementation, ParsingResult>
|
||||
|
||||
This is a partial implementation of the `RecordParser` interface. It exposes a
|
||||
delegate type that can be implemented and registered by clients of this parser.
|
||||
This delegate expects objects of the parsing result type.
|
||||
|
||||
```cpp
|
||||
bool parse(const Record&)
|
||||
void set_delegate(Delegate* delegate)
|
||||
```
|
||||
|
||||
Implementation of this class must expose the following non virtual function:
|
||||
|
||||
```c++
|
||||
bool do_parse(const Record& record, ParsingResult& parsing_result);
|
||||
```
|
||||
|
||||
If the parsing is successful then it should return true and fill `parsing_result`
|
||||
otherwise it should return false and leave `parsing_result` untouched.
|
||||
|
||||
**Note:** The Curiously recurring template pattern (CRTP) is used to implement
|
||||
the delegation mechanism in a type-safe fashion. This is not achievable with
|
||||
_regular_ polymorphism.
|
||||
|
||||
###### ndef::GenericRecordParser<ParserImplementation, ParsingResult>::Delegate
|
||||
|
||||
This delegate must be implemented by clients of this class. It receives the objects
|
||||
parsed.
|
||||
|
||||
```cpp
|
||||
virtual void on_record_parsed(const ParsingResult& record, const RecordID* id);
|
||||
```
|
||||
|
||||
**Note:** Usually clients are client of an implementation of an
|
||||
ndef::GenericRecordParser<ParserImplementation, ParsingResult> . They can refer
|
||||
to the delegate as `ImplementationName::Delegate`.
|
||||
|
||||
#### Common parsers
|
||||
|
||||
![ndef_common_parsers_diagram]
|
||||
|
||||
Parsers for each common record type exists. They inherit from the
|
||||
`GenericRecordParser` to exposes a common delegate interface:
|
||||
|
||||
```cpp
|
||||
virtual void on_record_parsed(const <ParsedType>& result, const ndef::RecordID* id)
|
||||
```
|
||||
|
||||
#### Simple parser
|
||||
|
||||
The API provide a class named `SimpleMessageParser` that glues together a
|
||||
`MessageParser` and a chain `RecordParser`'s containing the parsers for the common
|
||||
types.
|
||||
|
||||
![ndef_simple_parser_diagram]
|
||||
|
||||
Clients of the class can register a delegate, parse a message or add a new
|
||||
`RecordParser` in the parsing chain.
|
||||
|
||||
```cpp
|
||||
void set_delegate(Delegate* delegate);
|
||||
void parse(const ac_buffer_t& data_buffer);
|
||||
void add_record_parser(ndef::RecordParser* parser);
|
||||
```
|
||||
|
||||
##### Delegate
|
||||
|
||||
This delegate must be implemented by clients of this class. It receives events
|
||||
from the parsing process:
|
||||
|
||||
```cpp
|
||||
virtual void on_parsing_error(ndef::MessageParser::error_t error);
|
||||
virtual void on_parsing_started();
|
||||
virtual void on_text_parsed(const Text& text, const ndef::RecordID* id);
|
||||
virtual void on_mime_parsed(const Mime& text, const ndef::RecordID* id);
|
||||
virtual void on_uri_parsed(const URI& uri, const ndef::RecordID* id);
|
||||
virtual void on_unknown_record_parsed(const ndef::Record& record);
|
||||
virtual void on_parsing_terminated();
|
||||
```
|
||||
|
||||
### Serialization
|
||||
|
||||
The class `MessageBuilder` is used to map a record into an NDEF message. It
|
||||
includes a data buffer that contains the _raw_ message. Client code use the
|
||||
functions `append_record` to append a new record into the message being built.
|
||||
|
||||
![ndef_message_builder_diagram]
|
||||
|
||||
For convenience, serialization functions for common types are provided as well as
|
||||
a specialized `MessageBuilder` named `SimpleMessageBuilder` that exposes them
|
||||
in an object oriented fashion.
|
||||
|
||||
## HAL APIs
|
||||
|
||||
|
@ -363,7 +454,7 @@ The one HAL API that will have to be implemented by vendors to make use of the `
|
|||
|
||||
From the upper layer's point of view, the EEPROM is a byte array that can be read from/written to. Long operations (reads, writes, erasures) must happen asynchronously. Booleans indicate whether a particular operation was succesful. Encoding is handled by the upper layer.
|
||||
|
||||
Address 0 means the start of the NDEF buffer (not necessarily at address 0 in the EEPROM).
|
||||
Address 0 means the start of the NDEF buffer (not necessarily at address 0 in the EEPROM).
|
||||
|
||||
When a buffer is passed to the backend, the reference remains valid till the corresponding event is called.
|
||||
|
||||
|
@ -376,7 +467,7 @@ void backend_read_bytes(uint32_t address, size_t count)
|
|||
void backend_write_bytes(uint32_t address, const uint8_t* bytes, size_t count)
|
||||
void backend_set_size(size_t count)
|
||||
void backend_get_size()
|
||||
void backend_erase_bytes(uint32_t address, size_t size)
|
||||
void backend_erase_bytes(uint32_t address, size_t size)
|
||||
```
|
||||
|
||||
The following events must be called to signal completion of long operations:
|
||||
|
@ -415,10 +506,14 @@ GreenTea tests will be provided to partners to ensure compliance with the NFC EE
|
|||
* Event Queue
|
||||
|
||||
There are currently at least four event queues (Plaftorm, BLE, USB, IP) in mbed OS and NFC will also require an event queing mechanism. We should aim at reusing one of these existing queues with the long term goal of unifying these code bases.
|
||||
|
||||
|
||||
[phase_1_architecture]: phase_1_architecture.png
|
||||
[phase_2_architecture]: phase_2_architecture.png
|
||||
[nfc_controller_diagram]: uml_diagram_controller.png
|
||||
[nfc_endpoints_diagram]: uml_diagram_endpoints.png
|
||||
[ndef_diagram]: uml_diagram_ndef.png
|
||||
[interop_test_rig]: interop_test_rig.png
|
||||
[interop_test_rig]: interop_test_rig.png
|
||||
[ndef_message_parser_diagram]: uml_diagram_ndef_message_parser.png
|
||||
[ndef_record_parser_diagram]: uml_diagram_ndef_record_parser.png
|
||||
[ndef_common_parsers_diagram]: uml_diagram_ndef_common_parsers.png
|
||||
[ndef_simple_parser_diagram]: uml_diagram_ndef_simple_parser.png
|
||||
[ndef_message_builder_diagram]: uml_diagram_ndef_message_builder_diagram.png
|
Binary file not shown.
Before Width: | Height: | Size: 52 KiB |
|
@ -1,86 +0,0 @@
|
|||
@startuml
|
||||
|
||||
class NDEFMessage {
|
||||
+NDEFMessage()
|
||||
+bool parse(const uint8_t* buffer, size_t sz)
|
||||
+size_t count()
|
||||
+NDEFRecord operator[](size_t n)
|
||||
}
|
||||
|
||||
class NDEFMessageBuilder {
|
||||
+NDEFMessageBuilder(uint8_t* buffer, size_t max_sz)
|
||||
+bool add_record(const NDEFRecord& record)
|
||||
+NDEFMessage build()
|
||||
}
|
||||
|
||||
class NDEFRecord {
|
||||
+bool parse(const uint8_t* buffer, size_t max_sz)
|
||||
+ssize_t build(const uint8_t* buffer, size_t max_sz)
|
||||
|
||||
+uint8_t tnf()
|
||||
+void set_tnf(uint8_t tnf)
|
||||
|
||||
+const uint8_t* type() const
|
||||
+size_t type_size() const
|
||||
+void set_type(const uint8_t* type, size_t type_size)
|
||||
|
||||
+const uint8_t* id() const
|
||||
+size_t id_size() const
|
||||
+void set_id(const uint8_t* id, size_t id_size)
|
||||
|
||||
+const uint8_t* value() const
|
||||
+size_t value_size() const
|
||||
+void set_value(const uint8_t* type, size_t type_size)
|
||||
}
|
||||
|
||||
NDEFMessage *-- NDEFRecord
|
||||
NDEFMessageBuilder *-- NDEFRecord
|
||||
|
||||
class URIRecord {
|
||||
{static} +bool is_uri_record(const NDEFRecord& record)
|
||||
{static} +URIRecord as_uri_record(const NDEFRecord& record)
|
||||
|
||||
+uri_prefix_t uri_prefix() const
|
||||
+void set_uri_prefix(uri_prefix_t prefix)
|
||||
|
||||
+bool get_uri(char* uri, size_t max_sz) const
|
||||
+size_t uri_size() const
|
||||
+void set_uri(const char* uri)
|
||||
|
||||
+bool get_full_uri(char* uri, size_t max_sz) const
|
||||
+size_t full_uri_size() const
|
||||
+void set_full_uri(const char* uri)
|
||||
}
|
||||
|
||||
NDEFRecord <-- URIRecord
|
||||
|
||||
class TextRecord {
|
||||
{static} +bool is_text_record(const NDEFRecord& record)
|
||||
{static} +TextRecord as_text_record(const NDEFRecord& record)
|
||||
|
||||
+text_encoding_t encoding() const
|
||||
+void set_encoding(text_encoding_t encoding)
|
||||
|
||||
+bool get_text(char* text, size_t max_sz) const
|
||||
+size_t text_size() const
|
||||
+void set_text(const char* text)
|
||||
}
|
||||
|
||||
NDEFRecord <-- TextRecord
|
||||
|
||||
class MIMERecord {
|
||||
{static} +bool is_mime_record(const NDEFRecord& record)
|
||||
{static} +MIMERecord as_mime_record(const NDEFRecord& record)
|
||||
|
||||
+const char* mime_type() const
|
||||
+size_t mime_type_size() const
|
||||
+void set_mime_type(const char* text)
|
||||
|
||||
+const uint8_t* mime_data() const
|
||||
+size_t mime_data_size() const
|
||||
+void set_mime_data(const uint8_t* type, size_t type_size)
|
||||
}
|
||||
|
||||
NDEFRecord <-- MIMERecord
|
||||
|
||||
@enduml
|
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
|
@ -0,0 +1,58 @@
|
|||
@startuml
|
||||
|
||||
package ndef {
|
||||
|
||||
abstract RecordParser {
|
||||
+RecordParser()
|
||||
+{abstract} bool parse(const Record&)
|
||||
#~RecordParser()
|
||||
}
|
||||
|
||||
abstract GenericRecordParser<ParserImplementation, ParsingResult> {
|
||||
+GenericRecordParser()
|
||||
+bool parse(const Record&)
|
||||
+void set_delegate(Delegate* delegate)
|
||||
#~GenericRecordParser()
|
||||
}
|
||||
|
||||
interface GenericRecordParser::Delegate<ParsingResult> {
|
||||
+{abstract} void on_record_parsed(const ParsingResult& result, const RecordID* id)
|
||||
#~Delegate()
|
||||
}
|
||||
|
||||
RecordParser <|- GenericRecordParser
|
||||
GenericRecordParser +- "0..1" GenericRecordParser::Delegate
|
||||
|
||||
}
|
||||
|
||||
package common {
|
||||
class URI {
|
||||
}
|
||||
class Mime {
|
||||
}
|
||||
class Text {
|
||||
}
|
||||
|
||||
class URIParser {
|
||||
bool do_parse(const ndef::Record& record, URI& uri)
|
||||
}
|
||||
|
||||
class TextParser {
|
||||
bool do_parse(const ndef::Record& record, Text& text)
|
||||
}
|
||||
|
||||
class MimeParser {
|
||||
bool do_parse(const ndef::Record& record, Mime& mime)
|
||||
}
|
||||
|
||||
URI -- URIParser: Produce <
|
||||
Text -- TextParser: Produce <
|
||||
Mime -- MimeParser: Produce <
|
||||
|
||||
URIParser --|> GenericRecordParser
|
||||
TextParser --|> GenericRecordParser
|
||||
MimeParser --|> GenericRecordParser
|
||||
}
|
||||
|
||||
|
||||
@enduml
|
Binary file not shown.
After Width: | Height: | Size: 43 KiB |
|
@ -0,0 +1,64 @@
|
|||
@startuml
|
||||
|
||||
package ndef {
|
||||
|
||||
class MessageBuilder {
|
||||
+MessageBuilder(uint8_t* buffer, size_t capacity)
|
||||
+~MessageBuilder()
|
||||
+bool append_record(const RecordType& type, const RecordPayload* payload, bool is_last_record = false)
|
||||
+bool append_record(const Record& record)
|
||||
+const uint8_t* get_data() const;
|
||||
+size_t get_data_size() const;
|
||||
}
|
||||
|
||||
class Record {
|
||||
}
|
||||
|
||||
class RecordType{
|
||||
}
|
||||
|
||||
class RecordPayload{
|
||||
}
|
||||
|
||||
class RecordID{
|
||||
}
|
||||
|
||||
Record *-- RecordType
|
||||
Record *-- "0..1" RecordPayload
|
||||
Record *-- "0..1" RecordID
|
||||
|
||||
Record - MessageBuilder: insert >
|
||||
|
||||
}
|
||||
|
||||
package common {
|
||||
|
||||
class SimpleMessageBuilder {
|
||||
+SimpleMessageBuilder(uint8_t* buffer, size_t capacity)
|
||||
+~SimpleMessageBuilder()
|
||||
+bool append_uri(const URI&)
|
||||
+bool append_text(const Text&)
|
||||
+bool append_mime(const Mime&)
|
||||
}
|
||||
|
||||
class URI {
|
||||
+friend bool append_record(ndef::MessageBuilder&, const URI&)
|
||||
}
|
||||
|
||||
class Text {
|
||||
+friend bool append_record(ndef::MessageBuilder&, const Text&)
|
||||
}
|
||||
|
||||
class Mime {
|
||||
+friend bool append_record(ndef::MessageBuilder&, const Mime&)
|
||||
}
|
||||
|
||||
SimpleMessageBuilder --|> MessageBuilder
|
||||
|
||||
URI -- SimpleMessageBuilder: wrap >
|
||||
Text -- SimpleMessageBuilder: wrap >
|
||||
Mime -- SimpleMessageBuilder: wrap >
|
||||
|
||||
}
|
||||
|
||||
@enduml
|
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
|
@ -0,0 +1,46 @@
|
|||
@startuml
|
||||
|
||||
package ndef {
|
||||
|
||||
class MessageParser {
|
||||
+MessageParser()
|
||||
+void set_delegate(Delegate* delegate)
|
||||
+void parse(const ac_buffer_t& data_buffer)
|
||||
}
|
||||
|
||||
interface MessageParser::Delegate {
|
||||
+{abstract} void on_parsing_started()
|
||||
+{abstract} void on_record_parsed(const Record& record)
|
||||
+{abstract} void on_parsing_terminated()
|
||||
+{abstract} void on_parsing_error(error_t error)
|
||||
# ~Delegate()
|
||||
}
|
||||
|
||||
enum MessageParser::error_t {
|
||||
}
|
||||
|
||||
MessageParser +-- "0..1" MessageParser::Delegate
|
||||
MessageParser +-- MessageParser::error_t
|
||||
|
||||
note top of "MessageParser::Delegate"
|
||||
Implemented by the client of the parsing operation.
|
||||
end note
|
||||
|
||||
class Record {
|
||||
}
|
||||
class RecordType {
|
||||
}
|
||||
class RecordPayload {
|
||||
}
|
||||
class RecordID {
|
||||
}
|
||||
|
||||
Record *-- RecordType
|
||||
Record *-- "0..1" RecordPayload
|
||||
Record *-- "0..1" RecordID
|
||||
|
||||
MessageParser - Record: Produce >
|
||||
|
||||
}
|
||||
|
||||
@enduml
|
Binary file not shown.
After Width: | Height: | Size: 58 KiB |
|
@ -0,0 +1,73 @@
|
|||
@startuml
|
||||
|
||||
package ndef {
|
||||
|
||||
class Record {
|
||||
}
|
||||
class RecordType {
|
||||
}
|
||||
class RecordPayload {
|
||||
}
|
||||
class RecordID {
|
||||
}
|
||||
|
||||
Record *-- RecordType
|
||||
Record *-- "0..1" RecordPayload
|
||||
Record *-- "0..1" RecordID
|
||||
|
||||
abstract RecordParser {
|
||||
+RecordParser()
|
||||
+{abstract} bool parse(const Record&)
|
||||
#~RecordParser()
|
||||
}
|
||||
|
||||
abstract GenericRecordParser<ParserImplementation, ParsingResult> {
|
||||
+GenericRecordParser()
|
||||
+bool parse(const Record&)
|
||||
+void set_delegate(Delegate* delegate)
|
||||
#~GenericRecordParser()
|
||||
}
|
||||
|
||||
interface GenericRecordParserConcept<ParsingResult> {
|
||||
+bool do_parse(const Record& record, ParsingResult& parsing_result)
|
||||
}
|
||||
|
||||
interface GenericRecordParser::Delegate<ParsingResult> {
|
||||
+{abstract} void on_record_parsed(const ParsingResult& record, const RecordID* id)
|
||||
#~Delegate()
|
||||
}
|
||||
|
||||
RecordParser <|-- GenericRecordParser
|
||||
GenericRecordParser <|-- GenericRecordParserConcept
|
||||
GenericRecordParser +-- "0..1" GenericRecordParser::Delegate
|
||||
|
||||
note as N1
|
||||
GenericRecordParserConcept model the concept that must
|
||||
be implemented by GenericRecordParser childs.
|
||||
It doesn't exist in the hierarchy.
|
||||
end note
|
||||
|
||||
N1 - GenericRecordParser
|
||||
N1 - GenericRecordParserConcept
|
||||
|
||||
note bottom of "GenericRecordParser::Delegate"
|
||||
Implemented by the client of the parsing operation.
|
||||
end note
|
||||
|
||||
class RecordParserChain {
|
||||
+RecordParserChain()
|
||||
+~RecordParserChain()
|
||||
+bool parse(const Record& record)
|
||||
+void set_next_parser(RecordParser* parser)
|
||||
}
|
||||
|
||||
note bottom of "RecordParserChain"
|
||||
Chain of responsibility pattern.
|
||||
end note
|
||||
|
||||
Record - RecordParserChain: Parse >
|
||||
RecordParserChain o- "*" RecordParser
|
||||
|
||||
}
|
||||
|
||||
@enduml
|
Binary file not shown.
After Width: | Height: | Size: 94 KiB |
|
@ -0,0 +1,105 @@
|
|||
@startuml
|
||||
|
||||
package ndef {
|
||||
|
||||
class RecordParserChain {
|
||||
|
||||
}
|
||||
|
||||
abstract RecordParser {
|
||||
|
||||
}
|
||||
|
||||
abstract GenericRecordParser<ParserImplementation, ParsingResult> {
|
||||
|
||||
}
|
||||
|
||||
interface GenericRecordParser::Delegate<ParsingResult> {
|
||||
+{abstract} void on_record_parsed(const ParsingResult& record, const RecordID* id)
|
||||
#~Delegate()
|
||||
}
|
||||
|
||||
class MessageParser {
|
||||
|
||||
}
|
||||
|
||||
interface MessageParser::Delegate {
|
||||
+{abstract} void on_parsing_started()
|
||||
+{abstract} void on_record_parsed(const Record& record)
|
||||
+{abstract} void on_parsing_terminated()
|
||||
+{abstract} void on_parsing_error(error_t error)
|
||||
# ~Delegate()
|
||||
}
|
||||
|
||||
|
||||
MessageParser +-- "0..1" MessageParser::Delegate
|
||||
|
||||
|
||||
RecordParserChain -o RecordParser
|
||||
GenericRecordParser --|> RecordParser
|
||||
GenericRecordParser +- "0..1" GenericRecordParser::Delegate
|
||||
|
||||
RecordParserChain -[hidden]- MessageParser
|
||||
|
||||
}
|
||||
|
||||
package common {
|
||||
|
||||
class SimpleMessageParser {
|
||||
+ SimpleMessageParser()
|
||||
+ ~SimpleMessageParser()
|
||||
+ void set_delegate(Delegate* delegate)
|
||||
+ void parse(const ac_buffer_t& data_buffer)
|
||||
+ void add_record_parser(ndef::RecordParser* parser)
|
||||
- void on_parsing_error(ndef::MessageParser::error_t error)
|
||||
- void on_parsing_started()
|
||||
- void on_record_parsed(const ndef::Record& record)
|
||||
- void on_parsing_terminated()
|
||||
- void on_record_parsed(const URI& uri, const ndef::RecordID* id)
|
||||
- void on_record_parsed(const Text& uri, const ndef::RecordID* id)
|
||||
- void on_record_parsed(const Mime& uri, const ndef::RecordID* id)
|
||||
}
|
||||
|
||||
interface SimpleMessageParser::Delegate {
|
||||
+ {abstract} void on_parsing_error(ndef::MessageParser::error_t error)
|
||||
+ {abstract} void on_parsing_started()
|
||||
+ {abstract} void on_text_parsed(const Text& text, const ndef::RecordID* id)
|
||||
+ {abstract} void on_mime_parsed(const Mime& text, const ndef::RecordID* id)
|
||||
+ {abstract} void on_uri_parsed(const URI& uri, const ndef::RecordID* id)
|
||||
+ {abstract} void on_unknown_record_parsed(const ndef::Record& record)
|
||||
+ {abstract} void on_parsing_terminated()
|
||||
# ~Delegate()
|
||||
}
|
||||
|
||||
SimpleMessageParser::Delegate +- SimpleMessageParser
|
||||
|
||||
class URIParser {
|
||||
|
||||
}
|
||||
|
||||
class TextParser {
|
||||
|
||||
}
|
||||
|
||||
class MimeParser {
|
||||
|
||||
}
|
||||
|
||||
URIParser --|> GenericRecordParser
|
||||
TextParser --|> GenericRecordParser
|
||||
MimeParser --|> GenericRecordParser
|
||||
|
||||
SimpleMessageParser o-- URIParser
|
||||
SimpleMessageParser o-- TextParser
|
||||
SimpleMessageParser o-- MimeParser
|
||||
SimpleMessageParser o-- RecordParserChain
|
||||
SimpleMessageParser o-- MessageParser
|
||||
SimpleMessageParser <|-- MessageParser::Delegate
|
||||
|
||||
SimpleMessageParser <|-- GenericRecordParser::Delegate
|
||||
SimpleMessageParser <|-- GenericRecordParser::Delegate
|
||||
SimpleMessageParser <|-- GenericRecordParser::Delegate
|
||||
|
||||
}
|
||||
|
||||
@enduml
|
Loading…
Reference in New Issue