 Yes, thank you all for attending. I'll be presenting a new open source project called Iotivity Constraint. It's specifically targeted towards resource constrained hardware and software environments. During the course of the talk, I'll discuss a few design decisions that we have made. And while this project implements the open connectivity foundation standards, similar design philosophies should apply more generally to standards based software for the internet of things. So this is the outline of the talk. I'll start by briefly introducing OCF and the Iotivity Project, followed by a brief overview of the OCF core standard. I'll speak about the typical challenges of working in constrained environments, and further dive into the Iotivity Constraint's architecture. I'll then walk through a few code samples, application code samples, to give you an idea of the Iotivity Constraint's application APIs as they currently stand. And lastly, I'll provide a few guidelines on porting Iotivity Constraint to new environments. So the open connectivity foundation was set up in an attempt to solve the problem of fragmentation in machine to machine protocols and standards. It's an industry consortium with several member companies. It aims to collaboratively develop and publish open communication standards for the internet of things, covering a wide array of vertical use cases. In addition, it sponsors the Iotivity Project, which is an open source project, and serves as a reference implementation of these standards. So this talk is specifically about Iotivity Constraint, which is a new project under the Iotivity umbrella of projects. It, too, is a reference implementation of the OCF standards for resource constrained environments, which is also to say that it is lightweight. Its architecture enables it to be easily customized to various platform configurations. This is an important attribute, since given the variety of hardware and software options that vendors have to choose from, having a flexible architecture helps to capture a wider base of users and serve them. To that point, the users who would benefit most more from this project are embedded vendors or makers who would like to tweak their OCF applications and OS bundles at a fine-grained level. To sort of gain a better understanding of what it means to be constrained, I'll quote from RFC 7228, which presents a classification of constraint devices. Flash and RAM sizes are the key dimensions along which the authors observed a fairly clear clustering of commercially available chips and MCUs, resulting in the three classes. Class 0 devices are severely constrained in memory and processing capabilities. In the best case, they might be connected to the internet via a proxy or a gateway. Class 1 devices are less constrained than Class 0 devices, but with a limited code size, they might not be able to employ a full protocol stack to directly talk to other internet-connected nodes. However, they might be able to run protocol stacks that are more built for constrained environments, such as the constrained application protocol. But even with that, it might leave only a few limited resources available to applications. Class 2 devices are less constrained than Class 0 and Class 1 devices, but their resources can be better utilized by using lightweight and efficient software, leaving sufficient resources to develop more capable applications. So as you can see, these factors directly influence any design choices that we must make in software, based on the class of devices we'd like to target. For OCF specifically, we have the challenge of accommodating at a minimum the operating system, the network stack, the drivers, the OCF protocol, and the OCF application within the constraints. They might, however, be further considerations, such as software update, which might also need to be factored in. So the IATVT project has been around for a little less than two years now, and maybe some of you are familiar with it. It targets multifunction devices, such as PCs, smartphones, gateways, tablets. Such devices run a full feature at OS, like Linux, Android, Tizen, Windows. Whereas IATVT constraint targets resource constraint devices, and these devices are ones that might be battery powered and mostly wireless, such as door locks or environment sensing platforms. Such devices may be connected to a network that is itself constrained, such as low power and lossy networks. Such devices typically run a small OS, like Zephyr, Kentucky, RiotOS, FreeRTOS. However, both the implementations are protocol compatible. Over the next few slides, I'll just provide a brief overview of the OCF. Some key concepts that underlie the OCF core standard. The OCF protocol is based on the restful architectural style, where all things in the internet of things are modeled as resources. The crudin, which stands for create, read, update, delete, and notify, operations may be performed on these resources via the standard methods get, post, put, and delete. The things communicate with each other by exchanging resource representations. The schema of these representations is fully specified by OCF. The observe or notify operation, which is really a special case of the get method, and is used to subscribe to notifications from a resource when there's a change in its representation. Resources are defined with a common set of properties. Resource URI points to a specific physical object. It has a friendly name, a name property. Resources also have one or more types or interfaces. The type is sort of self-explanatory. It could be a light or a fan, and they have specific names designating those types. And also they might support one or more interfaces, where an interface defines the set of operations that are possible on the resource and the nature of their presentations. OCF provides a standard set of resource types and interfaces that applications might use. Resources also have policies associated with them, which specify if a resource is discoverable or observable. OCF also defines roles that are embodied in applications. The server role describes an application that hosts a set of resources and exposes them to the outside world. The client role describes an application that accesses resources hosted on a server. An application may incorporate both the client and server role at the same time. Such an application might run on a gateway or a proxy device, serving as an intermediary. So the OCF protocol is based on the constraint application protocol. It supports resource discovery with the aid of a fixed well-known resource. Endpoint discovery over IP is performed using multicast requests to an assigned address and port. Since co-app is usually transported over unreliable network transports, it has a simplified mechanism for establishing reliability, which uses a stop-and-wait retransmission model with an exponential back-off. Messages that want to utilize this function are marked confirmable, and expect an acknowledgment to return from the remote endpoint within a certain time frame, failing which they attempt a retransmission. OCF data payloads are encoded using the concise binary object representation, which is a compact binary format that is well suited for use over constrained environments. The OCF security model defines mechanisms for authentication and encryption over DTLS, and further rely upon access control lists to restrict access to resources. You may refer to the OCF security specification for more details on the security model. The OCF protocol is designed to work well over UDP and IP as the network transport, but there has been some prior work to adapt it to used Bluetooth low energy as an alternate network transport. There is an ongoing effort to refine and standardize this. So the OCF core specification lays out a set of well-known resources that serve specific functions. The OIC-RES resource is specifically for discovery and handles discovery requests. This is something I touched upon in the previous slide. It takes the, it accepts a resource type as a filter, which a client might specify if it wants to discover resources of that particular type. Device and platform are logical concepts defined by OCF, which, and their resources expose certain metadata, such as manufacturer operating system and firmware information as well as versioning information. The OIC-SEC resources serve as interfaces to the security implementation. And likewise, there are a few other well-known resources that always exist. You can, you may refer to the OCF core specification to gain a better understanding of those. I'll walk through a few request response sequences with a simple example. In this scenario, we have a smartphone which runs a client application, a light bulb, which runs a server application. The smartphone issues, in order to do resource discovery, the smartphone issues a multicast get request to the well-known OIC-RES resource. The light bulb, the server application running on the light bulb receives this and sends a unicast response back to the client with its information, which in this case mentions a resource a slash light with a specific resource type or supported interface and its policy is the fact that it's both discoverable and observable. The client that now wants to communicate with this resource sends a unicast get directly to the light bulb end point to that specific resource a slash light. The server response sends a unicast response with its current representation, which contains two properties, state and dim. The client issues a unicast put request to a slash light and its payload includes the representation that it wants to essentially put on the server side. This basically, the representation mentioned state equal to 1 and dim equal to 50. So this ends up turning on the light bulb and setting the brightness level to 50. On successfully completing this operation, the server sends a unicast response indicating the success status to the client. The client now issues a unicast observe request, which is really a get and the observe option set in the co-app header to a slash light. The server accepts the subscription, observer subscription and sends a unicast response back with its current representation, which remains the same. That is state equal to 1 and dim equal to 50. In this example, the light bulb happens to be connected to a physical switch, which someone has just turned off. So this has obviously led to a change in the representation of the server side. And so the server sends a notification back to the client, which had previously subscribed for notifications of such. And it includes its current representation, state equal to 0 and dim equal to 0. So this is roughly how clients and servers interact. So now I will speak about the typical challenges of working in constrained environments. These are a few hardware-induced constraints. I've already spoken about the fact that you tend to have lower RAM and flash capacity. Not only does this imply that we must run software that is lightweight, we should also understand that these constraints directly influence certain runtime parameters that have an impact on the constraint, the workload that an application can service. Some of these parameters might be, you know, maximum number of concurrent requests and maximum payload sizes. And this is something we need to factor into and be aware of. Well, while working with low-power CPUs that might potentially have a low clock cycle, we need to ensure that frequently used code parts are sort of straight and direct. We should also limit the number of copy operations. We should also ensure that there is no spinning that happens during periods of inactivity so that the CPU can be allowed to enter a more deeper sleep state. All of these considerations improve execution efficiency, which is something that's very essential if the device is battery-powered. And lastly, software should be designed such that you could easily incorporate only a specific subset of features that an application needs and not compile any more code than is necessary. These are some of the typical challenges posed by software infrastructures for constraint environments. First of all, the operating system itself is lightweight. It might lack an appropriate network stack or support for persistent storage, making the user rely upon third-party or proprietary libraries to fulfill those purposes. There's usually no dynamic memory allocation in these operating systems, which is something that we take for granted for the future OSs. We could easily allocate memory statically, but then considerable thought needs to put into the size of those allocations because they would have a direct impact on the performance of the application. There are a variety of OSs and other choices that developers have. So this leads to a considerable fragmentation in the APIs and also programming models tend to vary. There can also be a variation in the design of execution contexts amongst various OSs as well as their scheduling strategies. They might be either preemptive or non-preemptive. For example, Riot OS supports multi-threading, Contiki supports a form of cooperative multitasking, and Zephyr currently has a task and fiber model which serve different purposes. So basically the point I'm trying to convey is that it's very hard to design a piece of software for a particular environment and easily port it to another when we have to. So all of these points, in turn, led to the definition of some of these architectural goals that are fulfilled by Iotivity constraint. Firstly, we have a core framework that's essentially cross-platform. It's just pure C code. It encompasses much of the OCF resource model protocol memory management and its execution. It interacts with lower-level platform-specific functionality via a set of abstract interfaces. These interfaces are defined in generic terms, and elicit a specific contract from their implementations. The specific functionality is that these interfaces cover span, the connectivity, access to a system clock, pseudo-random number generation, and some form of persistent storage. And these are all features that the core framework just relies upon and needs to carry out its functions. As the core framework is the sole consumer of these interfaces, the scope of their definitions is very limited to its needs, and this enables it to be implemented on various environments with relative ease and allows rapid porting of Iotivity constraint and deployment on those environments. All memory is allocated statically in memory pools. And lastly, the design is modular and enables applications to exclude certain features cleanly without affecting the rest of the system. So this illustration sort of depicts the architecture that I just described. The gray box in the middle is the core framework, which is the cross-platform framework. It consumes the abstract interfaces. Concrete implementations of all of these interfaces constitute support, and we have a number of ports currently for Zephyr, RiotOS, Kentucky, and Linux. And finally you have an IOT application that sits and communicates with through APIs that are exposed by the core framework. So this box sort of illustrates the constituent blocks of the core framework, which is essentially like zooming into the gray box from the previous slide. To the right are blocks that handle the OCF resource model protocol and security flows, and they interact uniformly with various platform-specific functionalities on different environments via the abstract interfaces. The blocks to the left serve more horizontal functions and deal with managing memory pools as well as the execution. The framework executes in an event-driven fashion where the messages are passed between internal modules through the propagation of events. The framework maintains a queue of a fixed size to hold all outstanding events that are to be processed, and these events are processed by the receiving modules to completion in the order in which they were posted. An application essentially needs to then run an event loop in its main or background task to execute the framework. The code that implements the client and server roles are kept distinct so that an application can incorporate either of them or both. And lastly, the framework exposes a set of APIs for operating on and handling resources as well as working with OCF's data model. This illustration shows the internal workings of activity constraints event loop. An application continually calls the OC main pole function, and at the same time registers a set of callbacks with the framework. Every invocation of OC main pole processes all outstanding events at that time. That are to be processed. The connectivity module at the bottom right tends to wait for incoming messages over the network, and once such a message is received, the data buffers are passed as events to either the security or messaging modules depending on whether the incoming message was encrypted. The security module passes a decrypted co-op message to the messaging module. The messaging module decrypts the co-op message and passes the structure to the resource layer, which maps it to OCF resource model constructs, and then calls back into the application to either handle resource requests or responses. At the same time, an application can itself... If all of this happens in the context of the event loop, everything I just said. At the same time, an application can itself post events, like interrupt events, into the framework for handling. This might be used, for instance, in the case where you wanted to handle data that arises out of a hardware interrupt from a sensor. The event loop is designed such that the task that runs it can basically enter a particular idle mode when there is no activity. An application can, in addition, register a callback which can be invoked to signal the event loop when there is new work. The code on the slide sort of describes a pattern that applications can use, where the code block on the top runs in the application's main task. It creates a semaphore to use for signaling. It initializes a semaphore and then starts off the main loop, the event loop. The OC main poll function returns the absolute timestamp of the next schedule event if there is one, or it returns zero if there is none. The application can now wait on the semaphore either indefinitely or for a period of time. The signal event loop callback, which is being registered by the application, can be implemented to signal the semaphore. But the way all of this works underneath this, the framework invokes the signal event loop function when there is new work, since it is aware of any such activity, which can come in two forms. One is either if there was an incoming request for a response or if the application itself posted an interrupt event for processing. Once it invokes the signal event loop function, it would signal the semaphore and then the event loop could resume execution. So I will now go over a few application code samples, and the examples would illustrate the APIs as they currently stand. As I mentioned earlier, applications may incorporate OCF's client or server roles or both, and application is basically implemented over a set of callbacks. These are required by the framework and they sort of dictate the structure of the application. These are the set of callbacks that you would typically define. One is for initialization, for defining and registering OCF resources in a server application. Resource handlers for all supported methods of defined resources in a server application. An entry point for issuing requests in the client application. And response handlers for all issued requests in a client application. And in addition, there is a framework configuration file that lets you configure some of these various runtime parameters which you would need to make so that it meets the needs of the application that you're building. So this is done in a specific header file, config.h. I'll show you some of those parameters that I'll talk about them later on. So this is an example of the main task in an application where you set the initialization callback, the callback for signaling the event loop, and callback for registering resources in an OC handler T structure. You pass that structure over to OC main init, and following a successful initialization, you start executing the main loop. This is an example of the initialization callback where you typically set the representations for the platform and device resources, which are standard OCF resources. And you pass in some of the required metadata that you'd like to expose, like the manufacturer name, the device name, and some versioning information. You might also want to perform any hardware initializations over here. It's an appropriate place to do that. And in addition, it's a place where you can initialize the persistent storage hardware that you have on your platform. So for supporting... So the OCF... An Iotivity constraint requires some form of persistent storage to load and store credential and access control information. And the framework accesses persistent storage via the storage interface, which is one of the four abstract interfaces. OC Storage config is part of the storage interface, and takes a particular parameter, which might be some sort of a reference to some area of storage. The behavior of that function really depends on the implementation. In this specific case, where it's taken from the Linux sample, the parameter that it takes refers to a file system path. This is an example of the resource registration callback, where I'm defining a resource with URI a slash light of a resource type core.light. It's said to be discoverable and observable. It supports only the get method and sets the resource handler as get underscore light, which is a callback that we'd have to define. So here's an example of the light resource handler for the get method. If a resource handler supports queries, so basically an application can issue query parameters along with a request to a resource. And if a resource handler supports that, it can read those query parameters here by calling the OC get query value API. But basically, what the resource handler needs to do is return a representation of that resource, specifically for the get method. And as you can see here, the representation consists of an object with two properties, state and brightness level, and they are being set from the application. What you see here are basically a set of macros that are part of the IATVT constraints API to make it as an attempt to simplify the process of encoding representations, and we send a response. So here's an example of doing resource discovery on the client side. So at the top is the API to issue a discovery request for a particular resource type, OICR.light, and also passing in a handle to a callback function to handle the discovery response. The framework invokes the discovery response handler for every, separately for every discovered resource that match with the filter. So below is an example of the discovery response handler. Where you basically have to make a copy of the URI as well as the OC server handle T structure. That contains the information about the remote endpoint that actually hosts this resource. And these are the two pieces of information that a client would need to subsequently issue a request to that resource. Also, the discovery, the response handler can, has an opportunity to review all of the other resources that were just discovered, or by returning OC continued discovery, or can choose to just stop discovery if they are satisfied with what they're found. So here's an example of a client application issuing a get request to the resource that we just discovered. The server handle and URI would have already been populated in the discovery callback. And so you issue an OC do get request using the OC do get API to the URI and server. And you also pass in a query selecting the units that you'd like to use in your, that you'd like the resource representation to contain. And you also pass in a response handler for this request named get light. In this case, you would, this particular request is choosing to not use the co-apps reliability mechanism, which is the conformable request part, which I mentioned earlier. And so in order to do that, it's just mentioning low QoS as a parameter, which as a result sends a non-confirmable request that doesn't expect any acknowledgement. So here's an example of a response handler that's handling the response. The response payload would include the representation encoded in Seabor of that particular resource. And by the time this callback is invoked, the payload is already parsed out. And so this function gets handed in a structure which the application can just walk through to read all of the properties, which are part of the representation. So in the case of a conformable request, as I mentioned earlier, when a client issues a conformable request, it expects a response within a certain time window, failing which attempts a retransmission. But there might be instances where a server might not be able to return a representation within that time frame and yet receive the request correctly. So in order to prevent the client from needlessly retransmitting, the server can respond with an empty acknowledgement and at a later point send a separate response to that request. So this is basically how you do it with the APIs. You declare a separate response handle to track all incoming requests. In the resource handler for some resource, you would basically use the Indicate Separate Response call to add that request to the handle for tracking. And at a later point, whenever the response is ready, you would send the resource representation back to all of the endpoints that are requested for that representation in that period of time. The framework has the ability to set a callback to trigger after a certain period of time. This is done using the ocsetDelayedCallback function, where you specify a period in seconds. So in this instance, the function run after a second runs immediately. And inside of that function, the value it returns, which could be either done or continue determines whether the application wants to tear it on the callback or continue to trigger every one more time period ahead. And this mechanism can be used for scheduling like periodic requests, for instance. So lastly, for handling interrupts, applications have the ability to define a callback and signal it from an external context. That's a context that is external to the one that's running the event loop. For example, from an interrupt service routine. So the callback, once signaled, ends up running in the context of the event loop. So in this case, we can see an example of how you would define a callback and give it a name, register a callback during initialization, and subsequently signal the callback. And this you could use to again handle data from sensors or anything that's externally derived, an externally derived event to handle that. And it ends up getting synchronized and executing in the context of the event loop. So for instance, this could be used to send notifications of sensor data values whenever they get delivered to the application through the ISR. So the framework configuration is something that I spoke about earlier, and these need to be set at build time in a file, config.h. So these are some of the parameters that you configure in that file, like the number of application resources, number of request response buffers, like maximum payload sizes, memory pool sizes, and DTLS-related parameters. So lastly, these are the... I'll just go over the definitions of some of these abstract interfaces that you'd need to implement to port IATVT constraint to any new platform. So this is an example of the... This is the clock interface. In order to use it, you need to first define the resolution of time that IATVT constraint must use. IATVT constraint tracks time in terms of clock ticks, and of course a higher resolution provides for greater precision in timekeeping. Those are defined in the framework configuration, but the interface itself consists of these four functions which is for initializing the clock, getting the current time and clock ticks, getting the current time in seconds, and delaying the flow for a certain period of time. These need to be implemented using the target environments API. So for example, on Linux, I'd use clock get time to implement these functions. These are all the functions that are part of the connectivity interface, where you have functions for initialization where you might want to set up and configure your sockets. Shutdown for clearing resources, sending a buffer which basically sends a message to some remote endpoint, sending a multicast message, and getting the currently assigned ETLS port. These are all functions that the framework internally calls, and so they need to be implemented correctly on any target. The OC message T structure contains all the remote endpoint information, which could be the IP address of Bluetooth address as well as the data buffer. On the received side, incoming messages may be captured either via polling, or via a blocking weight from a separate thread. For example, you could do a select to block indefinitely on the site of socket file descriptors on Linux. But once the message is received, the port should construct an OC message T object and then the messages are injected into the framework via the OC network event call. However, the OC network event function needs to be synchronized with the execution of the event loop itself. And so in instances where it's called from a different thread, it would need, the connectivity implementation would need to even implement these functions using the target environment synchronization primitives to achieve that synchronization. On the other hand, if you're working in an environment like Kentucky where there is no preemption, since it uses cooperative multitasking, there is no need to implement these functions because there is no need to synchronize. This is the pseudo random number generation generator interface. An implementation might choose to employ some desired seeding strategy if necessary in the initialization. But the framework calls OC random value to obtain an unsigned integer whenever it needs a random number. And this is the persistent storage interface. I spoke a little bit about OC storage config, which is for initialization. How it's used entirely depends on the implementation. But OC storage read and write must most definitely implement access to some key value store. Since the framework internally calls these functions to read from keys and write to keys. So to conclude, the project is being actively developed. We have a few working ports for these environments. Riot OS, Zephyr, Kentucky and Linux. We're trying to work on filling up some feature gaps from the OCF standards point of view, some enhancements and our goal is to eventually pass all OCF certification tests to make it completely OCF certifiable. And also, we are still working on better documentation for the project, the code and the APIs. These are the pointers to the source code as well as the Iotivity mailing list where you could post questions. And we'd welcome any involvement or code contributions. That's any questions? What makes OCF more special than LWM2M? I'm not that familiar with LWM2M to be honest. But OCF is based on co-app, and so I guess if you know the difference between co-app and LWM2M, then that might... Well, OCF, I guess OCF tries to address sort of the vertical side as well because we have a lot of work groups that are focused on the needs of various vertical use cases. And so the... I think one of the contributions for OCF is the establishment of various data models that work well for various verticals. At least that's one of the things that we do over co-app. But yeah, I'm not sure about... if LWM2M does something similar or what. Right? So, as soon as we're done with the device, we would like to talk more and more about the network. And do you really have an idea of how much our job on the network is going forward? Right. So you're talking about off-loading functionality? Yeah. No. Yeah, no, I think it really depends on... Well, so I guess if you look at the way the event loop executes and the way the framework gently executes, it tries to behave well in the sense that it basically goes to sleep. It gives an application the opportunity to sleep. So the framework has all of those necessary hooks to enable an application to take advantage of those things to basically behave in a more energy efficient way. As for the question which you're asking, I guess it also depends upon how frequently you're receiving requests, right? Because that really has an impact on how often the device is executing and performing more work. So to some extent, the application can constrain the number of requests that it can receive by setting those parameters saying, hey, I don't want to accept more than one sort of request at a time. But I'm guessing the application itself who was designing this for a device might have to put more thought into how they'd like their device to behave in a thought. But the framework has those capabilities to enable applications to do whatever best they can. I'm just not sure if that's an OCF thing. I mean, it seems like... What you need to do is limit the interaction to the network if your device seems very powerful. The main one that you need to be aware of is going to be the multicasting because it'll depend on you. And to solve that, what you basically need is to register your device with a resource directory and then disengage from multicasting. So you can be still found, but you're not on multicasting. So just leave it for a bigger device to answer that question for you. And then it should be more or less okay. But the one is that we're trying to find the right architecture on the database that should be happened once. And in the case of that, you have to buy to change the place of all that information. It will really depend on what your use case is going to be, what your users are going to be doing, and how much you can spend but I think that the most important thing is actually to find out for multicast. Don't be on multicasting. This is what we're doing. But after that, it's only when it's directed to you and if your user is asking you to do something, your device has to be designed for the workflow. I think Tiago's point is a key point that you can actually have a resource directory that sits in between as a proxy to your really low-powered resource. So it goes to basically queue up requests and all of that. And the application can decide how it wants to behave based on who is building the device. Okay. No, not at the moment. But it shouldn't be particularly difficult. Just to contribute to that point. Yeah. We have a question for you. Just to bring it to your audience. Do you have them in the course that you're attaching on you? And then the follow-up question So I think to answer your first point, I think my new to something that is definitely of interest to us and something that I plan to personally look into. With regard to certification, I think that's sort of the goal, as I mentioned. I think the goal is to eventually be able to pass all certification tests. So the certification group in OCF has laid out a large test plan which covers a number of various cases and ensures that you're compliant with the spec, both the core specification as well as the security specification. And so, yes, I mean, I think the goal is to actually be certifiable so that somebody can take this and really productize it. Yes. Yes.