MAC layer is now a class rather than being a blob.
In addition to that Mac commands are now being handled in
a seperate subsystem (a class of its own). In future we
will do the same with othe sublayers of MAC like MLME, MCPS etc.
The drive behind this exercise is to make MAC and supporting layers
into an object oriented system.
Major bug fixes include:
- last join time inclusion in band parameters
- disabling rx2 window if we missed the slot already
- MLME uplink schdule hook
- nbRep according to spec
- maintaining datarate after successful joining
- suppressing MLME requests if MAC is in TX_DELAYED state
- Uplink dwell time verification
Some missing features are implemented. Details are as follows.
Support for LinkCheckRequet:
An application API is added, add_link_check_request() to delegate a
request for Link Check Request MAC command.
* Application provides a callback function that needs to be called on reception of
link check response.
* Mac command is piggybacked with data frames.
This API makes the sticky MAC command stick with the application payloads until/unless
the application un-sticks the said mac command using remove_link_check_request() API.
Handling fPending bit:
If in the Downlink, we get the fPending bit set in fctrl octet,
we attempt to send an empty message back to Network Server to
open additional Receive windows. This operation is independent
of the application. An RX_DONE event is queued bedore generating
the said empty message. Specification does not mention what can be the
type of that empty message. We have decided it to be of CONFIRMED
type as it gives us an added benefit of retries if the corresponding
RX slots are missed.
Radio event callbacks as Mbed callbacks:
radio_events_t structure has been carrying C-style callbacks which was
inherited from the legacy code. These callbacks has now been changed to
Mbed Callbacks that makes sure that we can be object oriented from now
on.
Application should be able to add some optional callbacks if it needs to.
Ofcourse there is a penalty of 8-12 bytes per callback, but there can be
certain needs of the application that needs to be met for example setting
up a link check request etc.
We have introduced a structure that contains callbacks for the application use.
- 'events' callback is mandatory, user must assign it. Because this callback brings
state changes for the application. We cannot segregate this into individual handlers
because of RAM penalty.
- Other calbacks (none of them are implemented yet are optional).
Example of using the API is provided with doxygen
Receive API should return the length of data written to the user buffer
as the Posix APIs suggest rather than sending the pending length of data
back.
That has actually been a typo mistake which actually wnt in even with doicumentation :)
The EventQueue thread in LoRaMac.cpp is disbanded and the LoRaWAN
protocol is redesigned to store a pointer for an application
provided EventQueue. It means that now the stack runs in the
same thread as application. Application provided EventQueue is used
to defer ISRs from radio driver and timer callbacks as well as the
application events are queued to the same event loop.
All network interfaces for LoRaWAN protocol must implement this
class. In order to be compatible with Mbed-OS applications, any
implementation of this class must use the data structures and
Mbed-OS timers provided.
lorawan_data_structures may look repetitive but this is essential
as we have a plan to use a reference implementation for LoRaWAN mac
layer from Semtech. Some of the data structures provide seemless
transition from semtech implementation (as MAC layer) to the Mbed-OS
control layers above.
features/lorawan/lorastack is the placeholder for future items like mac and
phy layers. system/ will contain all the common bits.
All Mbed-OS drivers for LoRa radio devices must implement
this pure virtual class in order to be compliant with Mbed-OS
applications.
This class comes loaded with all necessary data structures.
The implementations of this class can come out of tree.
Documentation states that nsapi_dns_query_multiple returns the number of
addresses found on success - it was returning 0.
Overloads using SocketAddress are relying on the return value, meaning
those calls didn't work at all.
Fixes#5921.
Previously, send() was somewhat soft - it only ever made one send
call to the underlying stack, so it would typically take as much data
as would fit in the buffer, and only block if it was unable to write
anything.
This is not the intent of a POSIX socket/filehandle write. It should try
to send everything if blocking, and only send less if interrupted by a
signal:
- If the O_NONBLOCK flag is clear, write() shall block the calling
thread until the data can be accepted.
- If the O_NONBLOCK flag is set, write() shall not block the thread.
If some data can be written without blocking the thread, write()
shall write what it can and return the number of bytes written.
Otherwise, it shall return -1 and set errno to [EAGAIN].
This "send all" behaviour is of slightly limited usefulness in POSIX, as
you still usually have to worry about the interruption possibility:
- If write() is interrupted by a signal before it writes any data, it
shall return -1 with errno set to [EINTR].
- If write() is interrupted by a signal after it successfully writes
some data, it shall return the number of bytes written.
But as mbed OS does not have the possibility of signal interruption, if we
strengthen send to write everything, we can make applications' lives
easier - they can just do "send(large amount)" confident that it will
all go in one call (if no errors).
So, rework to make multiple sends to the underlying stack, blocking as
necessary, until all data is written.
This change does not apply to recv(), which is correct in only blocking until
some data is available:
- If O_NONBLOCK is set, read() shall return -1 and set errno to [EAGAIN].
- If O_NONBLOCK is clear, read() shall block the calling thread until some
data becomes available.
- The use of the O_NONBLOCK flag has no effect if there is some data
available.
From C++11 and beyond string literals must be seperated by space
so that they are recongizable as seperate tokens.
Context macro in PPPCellularInterface (CTX) has been causing issues
as it was not augmented with a space from a nearby string literal.
Cellular example had build issues with IAR8, combination of define and string
as argument to send function resulted in above error. Typecasting to const char *
didn't help, hence replacing the define explicitly.
Basic TCP/UDP tests for PPP based onboard cellular modems.
Tests basic public APIs defined in CellularBase.h
A customer port must pass this test set, hence verifying their
particular implementation.
For keep supporting external APIs with the same name (supposedly there are a larger
number of users of those APIs), BufferedSerial and ATParser are being renamed.
BufferedSerial becomes UARTSerial, will complement a future USBSerial etc.
ATParser becomes ATCmdParser.
* UARTSerial moves to /drivers
* APN_db.h is moved from platform to cellular/util/.
* Original CellularInterface is restored for backward compatability (again, supposedly there
are users of that).
* A new file, CellularBase is added which will now servce as the base class for all
upcoming drivers.
* Special restructuring for the driver has been undertaken. This makes a clear cut distinction
between an on-board or an off-board implementation.
- PPPCellularInterface is a generic network interface that works with a generic FileHandle
and PPP. A derived class is needed to pass that FileHandle.
- PPPCellularInterface provides some base functionality like network registration, AT setup,
PPP connection etc. Lower level job is delegated to the derived classes and various modem
specific APIs are provided which are supposed to be overridden.
- UARTCellularInterface is derived from PPPCellularInterface. It constructs a FileHandle and
passes it back to PPPCellularInterface as well as provides modem hangupf functionality.
In future we could proive a USBInterface that would derive from PPPCellularInterface and could
pass the FileHandle back.
- OnboardCellularInterface is derived from UARTCellularInterfae and provides hooks to
the target provided implementation of onbard_modem_api.h. An off-board modem, i.e, a modem on
a shield has to override the modem_init(), modem_power_up() etc as it cannot use
onboard_modem_api.h.
GCC have not been capable enough to catch some linker errors which arose when
ethernet support for LWIP was disabled. Checks have been added to make sure that
unrefrenced code is not linked in.
nsapi_ppp glue layer is made more transparent to public cellular API. Storage of IP
addresses is removed. PPP layer already stores the addresses, so we pass the pointer back
to the upper layers.
If PPP is not used, we provide dummy functions.
* state machine corrections
* adding various standard API methods
* Addition/revision/enhancement of the nsapi_ppp glue layer
* Turning off debug by default
Mainly reutilizing code from ublox C027 support lib.
As we are using external PDP context, i.e., an external IP stack,
we will pass username and password to underlying stack running PPP.
We only support CHAP as the authentication protocol.
In case of carrier lost, we would like to inform PPP data pump.
That involved setting up link status flag down semaphores.
mbed_lwip_bringup() and mbed_lwip_bringdown() had been Ethernet specific only.
We extend these routines to support PPP as well. Currently we support only one interface
at a time. However, future enhancement to multi interface support should be trivial.
Observed during investigation of
https://github.com/ARMmbed/mbed-os/issues/4246 - DNS queries sent
the entire buffer, not just the bit filled in.
Inefficient, especially for 6LoWPAN, and a security hole - the trailing
data could be previously-used heap.
Note, the registered callback is still disabled by a call to
socket_attach. This will avoid being called after the socket is closed
unless close is called from the attached callback, which is in irq
context.
As pointed out by kjbracey-arm, the previous behaviour was broken
for sockets that started out listening.
To allow a network stack to support both NSAPI and its own options, try to make
sure the NSAPI levels don't collide with level numbers likely to be used by
network stacks.
Distinguish between socket and stack options, and tighten up documentation. Add
IP MRU stack options as an example (implementation not immediately planned for
any stack, but could be useful).
A few new error codes are added to nsapi_error_t and
support for non-blocking socket connect is added.
Nanostack's connect call will be non-blocking.
Whereas LWIP connect call is currently blocking, and it could be changed now
to be non-blocking.
During open, the socket checked the internal stack variable,
assuming it would alway be null on a socket not connected to
the network. However, when a socket is closed, the stack variable
was not updated, causing the socket to incorrectly return a
parameter error if reopened.
The simple fix was to set the stack to null on close. A non-null
stack is a predicate for a non-null socket variable, so no additional
checks are needed in socket functions.
It's currently possible to generate a socket event when a non-blocking socket is closed:
1. _pending is set to 0 in https://github.com/ARMmbed/mbed-os/blob/master/features/netsocket/TCPSocket.cpp#L22
when the socket is created.
2. close() calls event() in https://github.com/ARMmbed/mbed-os/blob/master/features/netsocket/Socket.cpp#L66
3. event() increments _pending, and since _pending is 1 it will call _callback() in https://github.com/ARMmbed/mbed-os/blob/master/features/netsocket/TCPSocket.cpp#L167
However, if send() (for example) is called, this can happen:
- send() is called and sets _pending to 0.
- when the data is sent, event() is called, which sets _pending to 1 and calls _callback().
- if close() is called at this point, there won't be an event generated for close() anymore,
since _pending will be set to 2.
Same thing for recv. Also, same thing for TCPServer and UDPSocket.
This PR changes the initial value of _pending to 1 instead of 0, so that
events are never generated for close().