Skip to contentSkip to navigationSkip to topbar
Rate this page:
On this page

Microvisor Networking


(warning)

Warning

Microvisor Public Beta

Microvisor is in a pre-release phase and the information contained in this document is subject to change. Some features referenced below may not be fully available until Microvisor's General Availability (GA) release.

Microvisor owns all of the device's networking sub-systems which can be used to connect the device to the Internet. Microvisor makes these network sub-systems available to the application through the Microvisor System Calls to allow your code to transfer data to and from remote servers.

This guide will help you understand how this is achieved by walking you through a typical usage flow:

  • Establish a network connection.
  • Set up a data channel.
  • Send and receive data through the channel.
  • Close the channel.
  • End the network connection.

This guide focuses on establishing network connections and channels, and then tearing them down when they are no longer required: the top and bottom of the sequence listed above. The phase in the middle, that of using the channel to send and receive data, is covered in separate guides, one each for the supported protocols.

(warning)

Warning

Earlier versions of this guide made use of channel-oriented Microvisor System Calls that have since been deprecated. These calls are no longer referred to in this guide.


Using networking

using-networking page anchor

At a high level, your application asks Microvisor to provide it with a network connection. When it has done so, Microvisor passes the application a handle which uniquely identifies the connection. The application can use this handle to check the connection's status and to open two-way data pathways, called channels, that are hosted by the connection. The application might use a channel to request data from a cloud service and to read the response. When it has completed the interaction, the application closes the channel. If it no longer needs the network connection, it relinquishes its access.

Like the network connection, every channel is identified by its own handle. Each handle's value is a 32-bit unsigned integer that is unique for the lifetime of the resource to which it has been assigned.

Handles are used to specify all types of resource in application-Microvisor interactions. When you open a channel, you provide the handle of the network connection that will host it: you include the network connection handle in the channel configuration data. Microvisor will provide a channel handle in return: use this channel handle for all future work with the channel.

(warning)

Warning

Before using a handle, you should always check that it is not zero. Any handle with the value zero is invalid. All extant handles are zeroed when Microvisor boots, and specific handles are zeroed when the resource they refer to is relinquished or closed by the application through the appropriate system call. If you attempt to make use of an invalid handle, Microvisor will report it as an error.


When Microvisor starts up, it will attempt to establish a network connection. It will maintain this connection until your application takes ownership of the network state by requesting network connectivity. From this point, it is your application's responsibility to manage when the device is connected to the network and when it is not.

Microvisor will take advantage of the application-managed connection to check if application or system updates have been staged for download. If the application intentionally goes offline, or if it doesn't reconnect after an outage, Microvisor will autonomously connect when it needs to make one of its periodic check-ins with the Microvisor cloud. It will stay connected for as short a time as possible.

Microvisor will also connect if the application crashes. This puts ownership of network state back in the hands of Microvisor until your code once again makes a network request.

A special case is remote debugging. In this case, Microvisor maintains a connection for debugging even if the application disconnects.

The System Call mvGetNetworkReasons() provides a means for your application to determine the state of network ownership. It can be called at any time, even if your application hasn't yet requested access to the network. The call writes out a bitfield of flags that together indicate current networking status. For example, examining the bitfield after the application has closed the network connection might reveal that Microvisor nonetheless has a connection in place because a remote debugger is attached.

You can view all the flags that may be set in the bitfield in the mvGetNetworkReasons() documentation.

Application logging

application-logging page anchor

Microvisor's application logging system implicitly makes use of any available connection to relay posted messages to the Microvisor cloud, from when they will be streamed to any remote computer that's listening for them. This means that it's not necessary for your application to request network connectivity solely to have posted log messages relayed. However, if you do request network access for other reasons, and you close the connection, messages will not be relayed.

Log messages posted while the device is offline — intentionally or unintentionally — are buffered so long as their is sufficient space in the buffer for them. Buffered messages will be sent to the cloud as soon as connectivity is restored by the current owner.


Requesting network connectivity

requesting-network-connectivity page anchor

To request a network connection, you application calls mvRequestNetwork(). This has these parameters:

  • A pointer to a data structure which allows you to specify how Microvisor will notify your application about subsequent network operations.
  • A pointer to application-accessible memory into which Microvisor will write the network connection's handle.

Microvisor will now bring up the network connection, powering up the hardware and making a connection to the Internet if these are not already in place. Once this process is complete, Microvisor will signal network availability to the application by dispatching an MV_EVENTTYPE_NETWORKSTATUSCHANGED notification.

(information)

Info

For more information on when and how Microvisor issues notifications to the application, and how the application can register its interest in certain notifications, please see Microvisor Notifications.

With a network connection in place, the application is ready to open channels and use them to transfer data.

(information)

Info

Like all Microvisor system calls, mvRequestNetwork() immediately returns a status value indicating whether Microvisor is able to proceed with the request. Only continue if Microvisor returns the value MV_STATUS_OKAY.

You can check on the status of a network connection at any time by calling mvGetNetworkStatus() and passing both the handle of the network you're interested in and the address of memory into which Microvisor will write a connection status code which will be one of the following:

StatusDescription
MV_NETWORKSTATUS_DELIBERATELYOFFLINEThe device is not connected
MV_NETWORKSTATUS_CONNECTEDThe device is connected
MV_NETWORKSTATUS_CONNECTINGThe device is connecting to the Internet

First, you need to establish the notification center to which network notifications will be posted. This center will then be used to configure the network connection itself. The code also shows how to set up stores for the various types of handle that will be used, and for notifications.


_30
// Central store for Microvisor resource handles used in this code.
_30
struct {
_30
MvNotificationHandle notification;
_30
MvNetworkHandle network;
_30
MvChannelHandle channel;
_30
} net_handles = { 0, 0, 0 };
_30
_30
// Central store for notification records. Holds one record at
_30
// a time -- each record is 16 bytes in size.
_30
static volatile struct MvNotification net_notification_buffer[16];
_30
_30
// Clear the notification store
_30
memset((void *)net_notification_buffer, 0xff, sizeof(net_notification_buffer));
_30
_30
// Configure a notification center for network-centric notifications
_30
static struct MvNotificationSetup net_notification_config = {
_30
.irq = TIM1_BRK_IRQn,
_30
.buffer = (struct MvNotification *)net_notification_buffer,
_30
.buffer_size = sizeof(net_notification_buffer)
_30
};
_30
_30
// Ask Microvisor to establish the notification center
_30
// and confirm that it has accepted the request
_30
enum MvStatus status = mvSetupNotifications(&net_notification_config,
_30
&net_handles.notification);
_30
assert(status == MV_STATUS_OKAY);
_30
_30
// Start the notification IRQ
_30
NVIC_ClearPendingIRQ(TIM1_BRK_IRQn);
_30
NVIC_EnableIRQ(TIM1_BRK_IRQn);

Here is the code you would write to open a network connection:


_14
// Configure the network connection request
_14
struct MvRequestNetworkParams network_config = {
_14
.version = 1,
_14
.v1 = {
_14
.notification_handle = net_handles.notification,
_14
.notification_tag = USER_TAG_LOGGING_REQUEST_NETWORK,
_14
}
_14
};
_14
_14
// Ask Microvisor to establish the network connection
_14
// and confirm that it has accepted the request
_14
enum MvStatus status = mvRequestNetwork(&network_config,
_14
&net_handles.network);
_14
assert(status == MV_STATUS_OKAY);

However, because the connection is established asynchronously, it's important to check network status before proceeding to open the channel — which will fail if the connection is not yet ready:


_18
// The network connection is established by Microvisor asynchronously,
_18
// so we wait for it to come up before opening the data channel -- which
_18
// would fail otherwise
_18
enum MvNetworkStatus net_status;
_18
while (1) {
_18
// Request the status of the network connection, identified by its handle.
_18
// If we're good to continue, break out of the loop...
_18
if (mvGetNetworkStatus(net_handles.network, &net_status) == MV_STATUS_OKAY &&
_18
net_status == MV_NETWORKSTATUS_CONNECTED) {
_18
break;
_18
}
_18
_18
// ... or wait a short period before retrying
_18
for (volatile unsigned i = 0; i < 50000; ++i) {
_18
// No op
_18
__asm("nop");
_18
}
_18
}

Recall that Microvisor system calls return immediately with a value — status in the code above — that indicates whether the request was accepted or rejected, not whether the request itself succeeded or failed.

General connection state checks

general-connection-state-checks page anchor

A call to mvGetNetworkStatus() can be used at any time to determine the state of the device's connection. This code assumes your network connection's handle is stored in a variable called network_handle.


_10
// Check connection state
_10
bool is_connected = false;
_10
if (net_handles.network != 0) {
_10
enum MvNetworkStatus net_state = MV_NETWORKSTATUS_DELIBERATELYOFFLINE;
_10
uint32_t status = mvGetNetworkStatus(net_handles.network, &net_state);
_10
if (status == MV_STATUS_OKAY) {
_10
is_connected = (net_state == MV_NETWORKSTATUS_CONNECTED);
_10
}
_10
}


To open a channel, call mvOpenChannel(). This function takes a data structure that's used to configure the channel, and a pointer to memory where Microvisor will write the channel's handle.

The configuration data comprises:

  • Pointers to the channel's send and receive buffers created by the application.
  • The sizes of those buffers.
  • The channel type.
  • The handle of the network connection that will host the channel.

The network connection that is hosting the channel must be connected to the Internet or the attempt to open the channel will fail. If connectivity is subsequently lost, any open channels on the network will be closed automatically, and your application will receive an EVENT_NETWORK_STATUS_CHANGED notification. This should trigger a call to mvGetNetworkStatus().

The channel type value tells Microvisor how the channel is to be used: the protocol it should use to send and receive information. At this time, only HTTPS, MQTT, and Configuration - specifed by the constants MV_CHANNELTYPE_HTTP, MV_CHANNELTYPE_MQTT, and MV_CHANNELTYPE_CONFIGFETCH, respectively — are supported, but we may add support for other protocols in due course.

The channel configuration structure includes an endpoint property and the related endpoint_len. This is no longer used, but you will need to provide the data: set the length to zero, and pass in a pointer to a dummy variable.

Send and receive buffers

send-and-receive-buffers page anchor

The application is responsible for allocating its own channel send and receive buffers. However, once Microvisor has opened a channel, it isn't possible to change the sizes or addresses of the channel's buffers. If you need to do so, you must close the channel and open a new one.

Each buffer is treated by Microvisor as circular. It will maintain a pointer and move it forward as data is written and read. When the pointer reaches the end of the buffer, it continues from at the start of the buffer once more. As data leaves the send buffer, space is made for further data to be sent. Microvisor keeps track of the available space for you.

Buffers must be sized in multiples of 512 bytes and their addresses aligned to 512-byte boundaries.

Having already requested a network connection and ensured that it is up before proceeding, we can now open the channel:

Set up the channel's send and receive buffers with appropriate sizes and alignment:


_10
// Set up the HTTP channel's multi-use send and receive buffers
_10
static volatile uint8_t http_channel_rx_buffer[RX_BUFFER_SIZE_B] __attribute__((aligned(512)));
_10
static volatile uint8_t http_channel_tx_buffer[TX_BUFFER_SIZE_B] __attribute__((aligned(512)));

Now add those buffers to the channel definition:


_17
struct MvOpenChannelParams channel_config = {
_17
.version = 1,
_17
.v1 = {
_17
.notification_handle = http_handles.notification,
_17
.notification_tag = USER_TAG_HTTP_OPEN_CHANNEL,
_17
.network_handle = http_handles.network,
_17
.receive_buffer = (uint8_t*)http_channel_rx_buffer,
_17
.receive_buffer_len = sizeof(http_channel_rx_buffer),
_17
.send_buffer = (uint8_t*)http_channel_tx_buffer,
_17
.send_buffer_len = sizeof(http_channel_tx_buffer),
_17
.channel_type = MV_CHANNELTYPE_HTTP,
_17
.endpoint = {
_17
.data = (uint8_t*)"",
_17
.length = 0
_17
}
_17
}
_17
};

Finally, request the channel be opened:


_10
// Ask Microvisor to open the channel
_10
// and confirm that it has accepted the request
_10
enum MvStatus status = mvOpenChannel(&channel_config, &net_handles.channel);
_10
if (status == MV_STATUS_OKAY) {
_10
server_log("Channel handle: %lu", (uint32_t)net_handles.channel);
_10
} else {
_10
server_error("Channel opening failed. Status: %i", status);
_10
}

The functions server_log() and server_error() are functions which take a format string and zero or more value arguments, render the string, and issue it via mvServerLog(). You can view both functions' code in the HTTP demo repo(link takes you to an external page).

(information)

Info

To learn how to use the HTTP channel you have just established, please see How to Issue HTTP Requests under Microvisor .


When you have finished with a channel, call mvClosechannel() to release it. It will zero the channel handle to prevent the use of that handle again — doing so will cause Microvisor to issue an error.

Closing a channel is straightforward, but it's prudent to check that the closure request was successful. Your application might need to follow a different path if the response from mvCloseChannel() is not MV_STATUS_OKAY.


_10
// If we have a valid channel handle -- ie. it is non-zero --
_10
// then ask Microvisor to close it and confirm acceptance of
_10
// the closure request.
_10
if (net_handles.channel != 0) {
_10
enum MvStatusstatus = mvCloseChannel(&net_handles.channel);
_10
assert(status == MV_STATUS_OKAY);
_10
}
_10
_10
// Confirm the channel handle has been invalidated by Microvisor
_10
assert(net_handles.channel == 0);

Unexpected channel closures

unexpected-channel-closures page anchor

Devices can lose connectivity for a variety of reasons: they are in an area with marginal cellular coverage, or the local network to which they are connected has lost its Internet backhaul. Whatever the reason for the loss of connectivity, it will cause Microvisor to post an MV_EVENTTYPE_CHANNELNOTCONNECTED notification to every open channel. However, Microvisor does not close the channels. This is so that your application can read any data still in their receive buffers, though no new data will be added to them.

You can call mvReadchannel() and mvReadchannelComplete() to get data that was received before the loss of connectivity, and then mvClosechannel() to terminate the channel.

However, you cannot call mvWritechannel(). No data can be sent because there's no connection, so Microvisor will issue an error if you try to do so.


Close the network connection

close-the-network-connection page anchor

Any time that you have a network connection, you can relinquish your application's access to it by calling mvReleaseNetwork(). It has a single parameter: the network connection handle.

Releasing the network connection will cause it to be closed — but only if there are no other handles that reference it, and Microvisor is not making use of it to check for OS and application updates. If you release a network connection that is host to one or more open channels, those channels will each receive an MV_EVENTTYPE_CHANNELNOTCONNECTED notification as described above.

Closing the network is straightforward, but don't forget to remove the notification center assigned to the network if you no longer need it.


_19
// If we have a valid network handle, then ask Microvisor to
_19
// close the connection and confirm acceptance of the request.
_19
if (net_handles.network != 0) {
_19
status = mvReleaseNetwork(&net_handles.network);
_19
assert(status == MV_STATUS_OKAY);
_19
}
_19
_19
// Confirm the network handle has been invalidated by Microvisor
_19
assert(net_handles.network == 0);
_19
_19
// If we have a valid notification center handle, then ask Microvisor
_19
// to tear down the center and confirm acceptance of the request.
_19
if (net_handles.notification != 0) {
_19
status = mvCloseNotifications(&net_handles.notification);
_19
assert(status == MV_STATUS_OKAY);
_19
}
_19
_19
// Confirm the notification center handle has been invalidated
_19
assert(net_handles.notification == 0);

(information)

Info

Microvisor Help and Support

We welcome all inquiries you may have about Microvisor and its implementation, and any support questions that arise once you've begun developing with Microvisor. Please submit your queries via a KORE Wireless ticket: log in to the Kore console(link takes you to an external page) and click the Contact Support button in the left-hand navbar.


Rate this page: