- Fixed problem where multiple threads calling `get()` would not all be woken up on the completion of the future due to usage of `notify()` instead of `notifyAll()`
- Removed the `Socket` instance
- `init()` now calls `begin()` on the messaging layer and no longer creates a new `Socket` itself
- `close()` now just calls `close()` on the messaging layer
- `transmitRequest(CoapRequest)` now calls `send(CoapPacket)` on the messaging layer instead of via a socket's `send(ubyte[])`
CoapMessagingLayer
- Added a `running` flag
- Added `begin()` which sets the running flag (ours) to `true`, it then creates and opens a `Socket` and then starts the reading loop
- Added `send(CoapPacket)` whcih wire-encoded the packet and then sends it over our `Socket`
- Added `close()` which sets the running flag to false, shutsdown the `Socket` (unblocking any blocking receives) and then closes the `Socket` (releasing the bound datagram port)
- Removed references to the `CoapClient`'s now-non-existent `Socket`
- Removed `getAndReset()`, replaced it with `hasTimedOut(Duration)`
CoapClient
- The `watch()` now uses `CoapRequest`'s new `hasTimedOut(Duration)` method
- Added a `Condition` variable for the `requestsLock` mutex
- Added `transmitRequest(CoapRequest request)` which will take in the `CoapRequest`, yank the `CoapPacket` from it, encode it, send it over the underlying transport and then start the request's timer
- Added some code for a future "watcher" routine
CoapRequest
- Added a `StopWatch` timer which does not auto start
- Added `startTime()` which starts the timer
- Added `getAndReset()` which gets the elapsed time and resets it
- Now takes in the original request packet, `CoapPacket` instead of the token
- Added `getToken()` to fetch the token (for matching purposes)
- Added `getRequestPacket()` to obtain the original request
CoapClient
- Use `getToken()`
- Pass the `CoapPacket` in rather
- On the beginning of each loop print out the `data` buffer from the `idx` till the end of the array
- When handling an extended option delta (16bits) we now extract it, add missing 269, add the current delta.
- THEN we jump over that 16bit entity, now we check the option length type based on previously available information
- So far we support ZERO_TO_TWELVE
- WIP: What to do with the new delta? Do we increment it? If so, how?!?
- Fixed bug in `fromBytes(ubyte[])` whereby we would parse the delta 0-12 option value correctly in the 0-12 length case but would never jump over it idx-wise
- This effectively left us on the starting byte of the option value for the next round, instead of starting on the next `(option delta | option length)`
- Added `flip!(T)(T integral)` for byteswapping
- Added `order!(T)(T integral, Order)` for byte swapping dependent on current system configuration
- Added `CoapOption` for storing options
- `CoapPacket`'s `options` field is now an array of `CoapOption` structs
- `fromBytes(ubyte[])` now prints the partially decoded packet befor message ID and options processing
- Added initial options support
- Options are still not decoding all correctly
- Added `OptionLenType`
- Added `getOptionLenType(ubyte)` which determins the length type based on the 4 bits in the header (lower)
- The `toString()` method now includes the `CoapOptions[]` in its output
Packet (unit tests)
- Added example CoAP packet to play with
- Added new constructor `this(string host, ushort port)`
-This constructor provided name resolution on the host part.
Client (unit tests)
- Updated unit test to use the new `CoapClient` name-resolution-based constructor
- Added new class
- This is stateful management of responses for previously made requests.
- Handles the actual sending and receiving of datagrams and issueing of callbacks etc.
- Added new class
- This allows one to build up a new CoAP request of some form in a method-call-by-method-call manner.
- In order to instantiate one of these please do so via the `CoapClient`.
- Added new class
- This represents a request that has been made. This is normally stored inside the `CoapClient` and used to find matching responses that come through in the messaging layer.
- It is composed of the `token` and the future which was created. Therefore when the messaging layer receives a new CoAP packet it can then try match it to one of these requests, in the event it finds a match it can retrieve the future, place the received `CoapPacket` into it and then wake up anyone doing a blocking `get()` on it.