blob: 8d403ca9c94e109f7b5a6d10b988aee0dbef5248 [file] [log] [blame]
{"config":{"lang":["en"],"min_search_length":3,"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"","text":"Apache Mynewt is a real-time, modular operating system for connected IoT devices that need to operate for long periods of time under power, memory, and storage constraints. The first connectivity stack offered is BLE 4.2.","title":"Home"},{"location":"about/","text":"Roadmap Some upcoming features: Full IP support Low power support with ability for drivers to turn on/off low power settings automatically Sensor API, see discussion thread Support for MIPS architecture Support for additional boards The detailed roadmap is tracked on JIRA for Mynewt . Feature Request The WISHLIST at the top of the roadmap on JIRA for Mynewt features all the new ideas awaiting discussion and review. Once the community decides to go ahead with a request, it is scheduled into a release. Generally, effort is made to schedule a requested feature into a particular version no later than 6 weeks prior to the planned release date. If you have suggestions for a new feature, use case, or implementation improvements, file a JIRA ticket with Issue Type set to \"Wish\". Introduce it in the dev@ mailing list with a link to the JIRA ticket. This assumes you have signed up for an account on JIRA and submitted a request to the dev@ mailing list for your JIRA username to be added to the Apache Mynewt (MYNEWT) project. FAQ Questions? Click here","title":"About"},{"location":"about/#roadmap","text":"Some upcoming features: Full IP support Low power support with ability for drivers to turn on/off low power settings automatically Sensor API, see discussion thread Support for MIPS architecture Support for additional boards The detailed roadmap is tracked on JIRA for Mynewt .","title":"Roadmap"},{"location":"about/#feature-request","text":"The WISHLIST at the top of the roadmap on JIRA for Mynewt features all the new ideas awaiting discussion and review. Once the community decides to go ahead with a request, it is scheduled into a release. Generally, effort is made to schedule a requested feature into a particular version no later than 6 weeks prior to the planned release date. If you have suggestions for a new feature, use case, or implementation improvements, file a JIRA ticket with Issue Type set to \"Wish\". Introduce it in the dev@ mailing list with a link to the JIRA ticket. This assumes you have signed up for an account on JIRA and submitted a request to the dev@ mailing list for your JIRA username to be added to the Apache Mynewt (MYNEWT) project.","title":"Feature Request"},{"location":"about/#faq","text":"Questions? Click here","title":"FAQ"},{"location":"community/","text":"Mailing Lists We welcome you to join our mailing lists and get in touch with us! To complete your subscription you have to confirm it by replying to the response sent to you when you email your subscription request!","title":"Community"},{"location":"community/#mailing-lists","text":"We welcome you to join our mailing lists and get in touch with us! To complete your subscription you have to confirm it by replying to the response sent to you when you email your subscription request!","title":"Mailing Lists"},{"location":"documentation/","text":"Documentation Organization The technical literature for Apache Mynewt is organized into three manuals. The first describes the Real Time Operating System (RTOS), its features and capabilities, and how to get it running on your target device. The second one demonstrates how to use the build and packaging tool, Newt , to easily choose firmware modules for your target and compose them into a working executable. The third manual shows how the device management tool, Newtmgr , can communicate with a remote device running Mynewt OS and monitor, configure, and upgrade it. For you to learn and get some hands-on experience, each manual includes one or more tutorials. We encourage that you try them, and do send us your feedback.","title":"Documentation"},{"location":"documentation/#documentation-organization","text":"The technical literature for Apache Mynewt is organized into three manuals. The first describes the Real Time Operating System (RTOS), its features and capabilities, and how to get it running on your target device. The second one demonstrates how to use the build and packaging tool, Newt , to easily choose firmware modules for your target and compose them into a working executable. The third manual shows how the device management tool, Newtmgr , can communicate with a remote device running Mynewt OS and monitor, configure, and upgrade it. For you to learn and get some hands-on experience, each manual includes one or more tutorials. We encourage that you try them, and do send us your feedback.","title":"Documentation Organization"},{"location":"download/","text":"Latest Apache Mynewt OS Release Release Version: Mynewt 0.9.0-incubating Release Date: June 6, 2016 Release Notes Fresh install If you are brand new to Mynewt, go to Quick Start . The Newt tool will automatically download the latest release. If you have already installed the Newt tool but not started any project yet, go to Create Your First Project . The Newt tool will automatically download the latest release. Upgrade If you have already installed the Newt tool and started a project that installed a previous version of Apache Mynewt, upgrade using Newt tool: $ newt upgrade Code in development While the use of one of the official releases listed above is generally recommended, you may be interested in seeing work in progress. The most recent code resides in the develop branch of the Mynewt git repository. You may view or fork the repositories for Mynewt OS and Newt Tool from the Apache mirror on github.com. Apache Mynewt OS mirror on github.com Apache Newt Tool mirror on github.com Alternatively, you can clone the desired branch using git: $ git clone git://github.com/apache/incubator-mynewt-core.git -b develop $ git clone git://github.com/apache/incubator-mynewt-newt.git -b develop A relatively stable version of code in progress can be found in the master branch of the Mynewt git repository. You may access the code for Mynewt OS and Newt Tool from the 'master` branch of the Apache mirror on github.com or clone it using git: $ git clone git://github.com/apache/incubator-mynewt-core.git $ git clone git://github.com/apache/incubator-mynewt-newt.git For general information on using Git at Apache, go to https://git-wip-us.apache.org. Release Archives Mynewt 0.8.0-incubating, Release Notes Mynewt 0.8.0-b2-incubating, Release Notes","title":"Download"},{"location":"download/#latest-apache-mynewt-os-release","text":"Release Version: Mynewt 0.9.0-incubating Release Date: June 6, 2016 Release Notes","title":"Latest Apache Mynewt OS Release"},{"location":"download/#fresh-install","text":"If you are brand new to Mynewt, go to Quick Start . The Newt tool will automatically download the latest release. If you have already installed the Newt tool but not started any project yet, go to Create Your First Project . The Newt tool will automatically download the latest release.","title":"Fresh install"},{"location":"download/#upgrade","text":"If you have already installed the Newt tool and started a project that installed a previous version of Apache Mynewt, upgrade using Newt tool: $ newt upgrade","title":"Upgrade"},{"location":"download/#code-in-development","text":"While the use of one of the official releases listed above is generally recommended, you may be interested in seeing work in progress. The most recent code resides in the develop branch of the Mynewt git repository. You may view or fork the repositories for Mynewt OS and Newt Tool from the Apache mirror on github.com. Apache Mynewt OS mirror on github.com Apache Newt Tool mirror on github.com Alternatively, you can clone the desired branch using git: $ git clone git://github.com/apache/incubator-mynewt-core.git -b develop $ git clone git://github.com/apache/incubator-mynewt-newt.git -b develop A relatively stable version of code in progress can be found in the master branch of the Mynewt git repository. You may access the code for Mynewt OS and Newt Tool from the 'master` branch of the Apache mirror on github.com or clone it using git: $ git clone git://github.com/apache/incubator-mynewt-core.git $ git clone git://github.com/apache/incubator-mynewt-newt.git For general information on using Git at Apache, go to https://git-wip-us.apache.org.","title":"Code in development"},{"location":"download/#release-archives","text":"Mynewt 0.8.0-incubating, Release Notes Mynewt 0.8.0-b2-incubating, Release Notes","title":"Release Archives"},{"location":"events/","text":"Events Please take a look at our upcoming events! We hope to see you there.","title":"Events"},{"location":"events/#events","text":"Please take a look at our upcoming events! We hope to see you there.","title":"Events"},{"location":"known_issues/","text":"Known Issues Here is a list of known issues and workarounds: newt install returns the following error: ReadDesc: No matching branch for apache-mynewt-core repo No matching branch for apache-mynewt-core repo The apache-mynewt-core Git repository location has changed due to Mynewt's graduation from an incubator project to an Apache top level project. The HTTP redirect to the new location may fail for some users. Workaround: Edit the project.yml file and change the line repo: incubator-mynewt-core as shown in the following example to repo: mynewt-core : repository.apache-mynewt-core: type: github vers: 1-latest user: apache repo: incubator-mynewt-core","title":"Known Issues"},{"location":"known_issues/#known-issues","text":"Here is a list of known issues and workarounds: newt install returns the following error: ReadDesc: No matching branch for apache-mynewt-core repo No matching branch for apache-mynewt-core repo The apache-mynewt-core Git repository location has changed due to Mynewt's graduation from an incubator project to an Apache top level project. The HTTP redirect to the new location may fail for some users. Workaround: Edit the project.yml file and change the line repo: incubator-mynewt-core as shown in the following example to repo: mynewt-core : repository.apache-mynewt-core: type: github vers: 1-latest user: apache repo: incubator-mynewt-core","title":"Known Issues"},{"location":"quick-start/","text":"Get set Apache Mynewt currently offers two ways to quickly get set up, each appealing to different personal preferences and levels of familiarity with embedded systems. Option 1: All-in-one docker container that bundles Newt tool, developer toolchains and libraries. For this option, go to Docker instructions Option 2: Step-by-step instructions to install the Newt tool, developer toolchains and libraries natively on your computer. For this option, go to Native Setup Go! Start a new project as explained under Create Your First Project . The core Mynewt OS is automatically downloaded as part of the project installation. When you Create Your First Project you define a simulated target and run Project Blinky, the Hello World equivalent in the embedded world. If you have one of the supported boards , you can make real LEDs blink in Project Blinky . Simply choose the appropriate tutorial for the board and proceed. And More... Explore the Tutorials section for other interesting projects or simply to learn more about Mynewt's capabilities and get familiar with its use.","title":"Quick Start"},{"location":"quick-start/#get-set","text":"Apache Mynewt currently offers two ways to quickly get set up, each appealing to different personal preferences and levels of familiarity with embedded systems. Option 1: All-in-one docker container that bundles Newt tool, developer toolchains and libraries. For this option, go to Docker instructions Option 2: Step-by-step instructions to install the Newt tool, developer toolchains and libraries natively on your computer. For this option, go to Native Setup","title":"Get set"},{"location":"quick-start/#go","text":"Start a new project as explained under Create Your First Project . The core Mynewt OS is automatically downloaded as part of the project installation. When you Create Your First Project you define a simulated target and run Project Blinky, the Hello World equivalent in the embedded world. If you have one of the supported boards , you can make real LEDs blink in Project Blinky . Simply choose the appropriate tutorial for the board and proceed.","title":"Go!"},{"location":"quick-start/#and-more","text":"Explore the Tutorials section for other interesting projects or simply to learn more about Mynewt's capabilities and get familiar with its use.","title":"And More..."},{"location":"faq/answers/","text":"How do I submit a bug? If you do not have a JIRA account sign up for an account on JIRA . Submit a request to the @dev mailing list for your JIRA username to be added to the Apache Mynewt (MYNEWT) project. You can view the issues on JIRA for the MYNEWT project without an account but you need to log in for reporting a bug. Log in. Choose the \"MYNEWT\" project. Click on the \"Create\" button to create a ticket. Choose \"Bug\" as the Issue Type. Fill in the bug description, how it is triggered, and other details. How do I request a feature? If you do not have a JIRA account sign up for an account on JIRA . Submit a request to the @dev mailing list for your JIRA username to be added to the Apache Mynewt (MYNEWT) project. You can view the issues on JIRA for the MYNEWT project without an account but you need to log in for reporting a bug. Log in. Choose the \"MYNEWT\" project. Click on the \"Create\" button to create a ticket. Choose \"Wish\" as the Issue Type. Fill in the feature description, benefits, and any other implementation details. Note in the description whether you want to work on it yourself. If you are not a committer and you wish to work on it, someone who is on the committer list will have to review your request and assign it to you. You will have to refer to this JIRA ticket in your pull request. I am not on the committer list. How do I submit a patch? You submit your proposed changes for your peers with committer status to review and merge. The \"develop\" branch on Mynewt's repository contains the most recent changes made by the community of developers. Contributions from you need to go into this branch. The essential steps to setting up your project space for working with the latest code from \"develop\" and make pull requests into \"develop\" to get your code added are the following: Step 1: Create a fork of the entire Mynewt repository on github.com. Step 2: Setup repository on your laptop to use code in \u201cdevelop\u201d branch. You then create a new branch \u201cmybranch\u201d using \u201cgit checkout \u2013b\u201d. You also add a remote handle named \u201cfork\u201d that points to the github fork you created in Step 1. $ newt new devproject $ cd devproject $ vi project.yml # change version to 0-dev for repository.apache-mynewt-core $ newt install $ cd repos/apache-mynewt-core $ git status On branch develop Your branch is up-to-date with 'origin/develop'. nothing to commit, working directory clean $ git checkout \u2013b mybranch $ git remote -v origin https://github.com/apache/incubator-mynewt-core.git (fetch) origin https://github.com/apache/incubator-mynewt-core.git (push) $ git remote add fork https://github.com/<user>/incubator-mynewt-core $ git remote -v origin https://github.com/apache/incubator-mynewt-core.git (fetch) origin https://github.com/apache/incubator-mynewt-core.git (push) fork https://github.com/<user>/incubator-mynewt-core (fetch) fork https://github.com/<user>/incubator-mynewt-core (push) Step 3: Check you are in \u201cmybranch\u201d. Write code. Stage and commit your changes (example shows adding all). $ git checkout mybranch $ git add . $ git commit \u2013m \u201cyour message about your code changes\u201d Step 4: Always pull the latest from develop on Apache mirror to \u201cmybranch\u201d before pushing any changes to remotes. If you see merge conflicts, resolve them first. $ git pull --rebase origin develop Step 5: Push your changes to \u201cmybranch\u201d branch on your github fork. If \u201cmybranch\u201d does not exist yet on your github fork, the command automa;cally creates it. $ git push fork mybranch \ufffcStep 6: Generate a pull request from \u201cmybranch\u201d in your fork to \u201cdevelop\u201d in Mynewt using the \"New pull request\" button on github.com. I would like to make some edits to the documentation. What do I do? You submit your proposed changes for your peers with committer status to review and merge. Go to the documentation mirror on github.com. Navigate to the file you wish to edit on github.com. All the technical documentation is in Markdown files under the /docs directory. Click on the pencil icon (\"Edit the file in your fork of this project\") and start making changes. Click the green \"Propose file change\" button. You will be directed to the page where you can start a pull request from the branch that was created for you. The branch is gets an automatic name patch-# where # is a number. Click on the green \"Compare & pull request\" to open the pull request. In the comment for the pull request, include a description of the changes you have made and why. Github will automatically notify everyone on the commits@mynewt.incubator.apache.org mailing list about the newly opened pull requests. You can open a pull request even if you don't think the code is ready for merging but want some discussion on the matter. Upon receiving notification, one or more committers will review your work, ask for edits or clarifications, and merge when your proposed changes are ready. If you want to withdraw the pull request simply go to your fork https://github.com/<your github username>/incubator-mynewt-site and click on \"branches\". You should see your branch under \"Your branches\". Click on the delete icon. I would like to make some edits to the documentation but want to use an editor on my own laptop. What do I do? You submit your proposed changes for your peers with committer status to review and merge. Go to the documentation mirror on github.com. You need to create your own fork of the repo in github.com by clicking on the \"Fork\" button on the top right. Clone the forked repository into your laptop (using git clone from a terminal or using the download buttons on the github page)and create a local branch for the edits and switching to it (using git checkout -b <new-branchname> or GitHub Desktop). Make your changes using the editor of your choice. Push that branch to your fork on github. Then submit a pull request from that branch on your github fork. The review and merge process is the same as other pull requests described for earlier questions.","title":"FAQ"},{"location":"faq/answers/#how-do-i-submit-a-bug","text":"If you do not have a JIRA account sign up for an account on JIRA . Submit a request to the @dev mailing list for your JIRA username to be added to the Apache Mynewt (MYNEWT) project. You can view the issues on JIRA for the MYNEWT project without an account but you need to log in for reporting a bug. Log in. Choose the \"MYNEWT\" project. Click on the \"Create\" button to create a ticket. Choose \"Bug\" as the Issue Type. Fill in the bug description, how it is triggered, and other details.","title":"How do I submit a bug?"},{"location":"faq/answers/#how-do-i-request-a-feature","text":"If you do not have a JIRA account sign up for an account on JIRA . Submit a request to the @dev mailing list for your JIRA username to be added to the Apache Mynewt (MYNEWT) project. You can view the issues on JIRA for the MYNEWT project without an account but you need to log in for reporting a bug. Log in. Choose the \"MYNEWT\" project. Click on the \"Create\" button to create a ticket. Choose \"Wish\" as the Issue Type. Fill in the feature description, benefits, and any other implementation details. Note in the description whether you want to work on it yourself. If you are not a committer and you wish to work on it, someone who is on the committer list will have to review your request and assign it to you. You will have to refer to this JIRA ticket in your pull request.","title":"How do I request a feature?"},{"location":"faq/answers/#i-am-not-on-the-committer-list-how-do-i-submit-a-patch","text":"You submit your proposed changes for your peers with committer status to review and merge. The \"develop\" branch on Mynewt's repository contains the most recent changes made by the community of developers. Contributions from you need to go into this branch. The essential steps to setting up your project space for working with the latest code from \"develop\" and make pull requests into \"develop\" to get your code added are the following: Step 1: Create a fork of the entire Mynewt repository on github.com. Step 2: Setup repository on your laptop to use code in \u201cdevelop\u201d branch. You then create a new branch \u201cmybranch\u201d using \u201cgit checkout \u2013b\u201d. You also add a remote handle named \u201cfork\u201d that points to the github fork you created in Step 1. $ newt new devproject $ cd devproject $ vi project.yml # change version to 0-dev for repository.apache-mynewt-core $ newt install $ cd repos/apache-mynewt-core $ git status On branch develop Your branch is up-to-date with 'origin/develop'. nothing to commit, working directory clean $ git checkout \u2013b mybranch $ git remote -v origin https://github.com/apache/incubator-mynewt-core.git (fetch) origin https://github.com/apache/incubator-mynewt-core.git (push) $ git remote add fork https://github.com/<user>/incubator-mynewt-core $ git remote -v origin https://github.com/apache/incubator-mynewt-core.git (fetch) origin https://github.com/apache/incubator-mynewt-core.git (push) fork https://github.com/<user>/incubator-mynewt-core (fetch) fork https://github.com/<user>/incubator-mynewt-core (push) Step 3: Check you are in \u201cmybranch\u201d. Write code. Stage and commit your changes (example shows adding all). $ git checkout mybranch $ git add . $ git commit \u2013m \u201cyour message about your code changes\u201d Step 4: Always pull the latest from develop on Apache mirror to \u201cmybranch\u201d before pushing any changes to remotes. If you see merge conflicts, resolve them first. $ git pull --rebase origin develop Step 5: Push your changes to \u201cmybranch\u201d branch on your github fork. If \u201cmybranch\u201d does not exist yet on your github fork, the command automa;cally creates it. $ git push fork mybranch \ufffcStep 6: Generate a pull request from \u201cmybranch\u201d in your fork to \u201cdevelop\u201d in Mynewt using the \"New pull request\" button on github.com.","title":"I am not on the committer list. How do I submit a patch?"},{"location":"faq/answers/#i-would-like-to-make-some-edits-to-the-documentation-what-do-i-do","text":"You submit your proposed changes for your peers with committer status to review and merge. Go to the documentation mirror on github.com. Navigate to the file you wish to edit on github.com. All the technical documentation is in Markdown files under the /docs directory. Click on the pencil icon (\"Edit the file in your fork of this project\") and start making changes. Click the green \"Propose file change\" button. You will be directed to the page where you can start a pull request from the branch that was created for you. The branch is gets an automatic name patch-# where # is a number. Click on the green \"Compare & pull request\" to open the pull request. In the comment for the pull request, include a description of the changes you have made and why. Github will automatically notify everyone on the commits@mynewt.incubator.apache.org mailing list about the newly opened pull requests. You can open a pull request even if you don't think the code is ready for merging but want some discussion on the matter. Upon receiving notification, one or more committers will review your work, ask for edits or clarifications, and merge when your proposed changes are ready. If you want to withdraw the pull request simply go to your fork https://github.com/<your github username>/incubator-mynewt-site and click on \"branches\". You should see your branch under \"Your branches\". Click on the delete icon.","title":"I would like to make some edits to the documentation. What do I do?"},{"location":"faq/answers/#i-would-like-to-make-some-edits-to-the-documentation-but-want-to-use-an-editor-on-my-own-laptop-what-do-i-do","text":"You submit your proposed changes for your peers with committer status to review and merge. Go to the documentation mirror on github.com. You need to create your own fork of the repo in github.com by clicking on the \"Fork\" button on the top right. Clone the forked repository into your laptop (using git clone from a terminal or using the download buttons on the github page)and create a local branch for the edits and switching to it (using git checkout -b <new-branchname> or GitHub Desktop). Make your changes using the editor of your choice. Push that branch to your fork on github. Then submit a pull request from that branch on your github fork. The review and merge process is the same as other pull requests described for earlier questions.","title":"I would like to make some edits to the documentation but want to use an editor on my own laptop. What do I do?"},{"location":"faq/how_to_edit_docs/","text":"How to Edit Docs Objective Learn the process of editing docs by adding some content to a test document. Markdown, MkDocs, Mou The Mynewt documentation you see on the Apache incubator website is a bunch of HTML files generated using MkDocs which is a simple static site generation tool geared towards building project documentation. You can read about it at http://www.mkdocs.org . Documentation source files are written in Markdown, and configured with a single YAML configuration file. Markdown is a lightweight markup language with plain text formatting syntax designed so that it can be converted to HTML and many other formats using a tool (which in our case is MkDocs). The HTML pages are generated periodically after changes have been reviewed and accepted into the master branch. Access to the Apache repo Get an account on Apache. You do not need a committer account to view the website or clone the repository but you need it to push changes to it. If you are not a committer, you may follow the proposed non-committer workflow to share your work. The direct link to the proposed workflow is https://git-wip-us.apache.org/docs/workflow.html . You will find the steps described in more detail later in this tutorial. Editing an existing page Create a fork on the github mirror . Then create a new branch to work on your documentation and move to that branch. $ git checkout -b <your-branch-name> Make changes directly on github.com. Generate a pull request. Alternatively, you can edit locally on your machine, push the branch (or the changes in the branch) to your fork on github.com, and then generate a pull request. Adding a new page If you create a new file somewhere in the docs subdirectory to add a new page, you have to add a line in the mkdocs.yml file at the correct level. For example, if you add a new module named \"Wi-Fi\" by creating a new file named wifi.md in the network directory, you have to insert the following line under Networking User Guide in the mkdocs.yml file (at the same level as the docs directory). In this example, a link will show up in the navigation bar on the left under \"Networking User Guide\" titled \"Wi-Fi\" and take the user to the contents of the 'wifi.md' file when the link is clicked. ** Note: The change will show up on this Mynewt site only after your pull request is merged in and the updated site is generated.** - 'Wi-Fi': 'wifi.md' Local preview of HTML files You have the option to install MkDocs and do a local conversion yourself to preview the pages using the built-in webserver that comes with MkDocs. In order to install MkDocs you'll need Python installed on your system, as well as the Python package manager, pip. You can check if you have them already (usually you will). $ python --version Python 2.7.2 $ pip --version pip 1.5.2 $ pip install mkdocs You will then run the built-in webserver from the root of the documentation directory using the command mkdocs serve . The root directory for documentation is incubator-mynewt-site or the directory with the mkdocs.yml file. $ ls docs images mkdocs.yml $ mkdocs serve Then go to http://127.0.0.1:8000 to preview your pages and see how they will look on the website. Remember that the Myself website itself will not be updated. For more information on MkDocs go to http://www.mkdocs.org .","title":"Edit Docs"},{"location":"faq/how_to_edit_docs/#how-to-edit-docs","text":"","title":"How to Edit Docs"},{"location":"faq/how_to_edit_docs/#objective","text":"Learn the process of editing docs by adding some content to a test document.","title":"Objective"},{"location":"faq/how_to_edit_docs/#markdown-mkdocs-mou","text":"The Mynewt documentation you see on the Apache incubator website is a bunch of HTML files generated using MkDocs which is a simple static site generation tool geared towards building project documentation. You can read about it at http://www.mkdocs.org . Documentation source files are written in Markdown, and configured with a single YAML configuration file. Markdown is a lightweight markup language with plain text formatting syntax designed so that it can be converted to HTML and many other formats using a tool (which in our case is MkDocs). The HTML pages are generated periodically after changes have been reviewed and accepted into the master branch.","title":"Markdown, MkDocs, Mou"},{"location":"faq/how_to_edit_docs/#access-to-the-apache-repo","text":"Get an account on Apache. You do not need a committer account to view the website or clone the repository but you need it to push changes to it. If you are not a committer, you may follow the proposed non-committer workflow to share your work. The direct link to the proposed workflow is https://git-wip-us.apache.org/docs/workflow.html . You will find the steps described in more detail later in this tutorial.","title":"Access to the Apache repo"},{"location":"faq/how_to_edit_docs/#editing-an-existing-page","text":"Create a fork on the github mirror . Then create a new branch to work on your documentation and move to that branch. $ git checkout -b <your-branch-name> Make changes directly on github.com. Generate a pull request. Alternatively, you can edit locally on your machine, push the branch (or the changes in the branch) to your fork on github.com, and then generate a pull request.","title":"Editing an existing page"},{"location":"faq/how_to_edit_docs/#adding-a-new-page","text":"If you create a new file somewhere in the docs subdirectory to add a new page, you have to add a line in the mkdocs.yml file at the correct level. For example, if you add a new module named \"Wi-Fi\" by creating a new file named wifi.md in the network directory, you have to insert the following line under Networking User Guide in the mkdocs.yml file (at the same level as the docs directory). In this example, a link will show up in the navigation bar on the left under \"Networking User Guide\" titled \"Wi-Fi\" and take the user to the contents of the 'wifi.md' file when the link is clicked. ** Note: The change will show up on this Mynewt site only after your pull request is merged in and the updated site is generated.** - 'Wi-Fi': 'wifi.md'","title":"Adding a new page"},{"location":"faq/how_to_edit_docs/#local-preview-of-html-files","text":"You have the option to install MkDocs and do a local conversion yourself to preview the pages using the built-in webserver that comes with MkDocs. In order to install MkDocs you'll need Python installed on your system, as well as the Python package manager, pip. You can check if you have them already (usually you will). $ python --version Python 2.7.2 $ pip --version pip 1.5.2 $ pip install mkdocs You will then run the built-in webserver from the root of the documentation directory using the command mkdocs serve . The root directory for documentation is incubator-mynewt-site or the directory with the mkdocs.yml file. $ ls docs images mkdocs.yml $ mkdocs serve Then go to http://127.0.0.1:8000 to preview your pages and see how they will look on the website. Remember that the Myself website itself will not be updated. For more information on MkDocs go to http://www.mkdocs.org .","title":"Local preview of HTML files"},{"location":"network/ble/ble_intro/","text":"BLE Introduction Apache Mynewt offers the world's first fully open-source Bluetooth Low Energy (BLE) or Bluetooth Smart stack. It is called NimBLE. BLE technology operates in the unlicensed industrial, scientific and medical (ISM) band at 2.4 to 2.485 GHz which is available in most countries. It uses a spread spectrum, frequency hopping, full-duplex signal. BLE FHSS employs 40 2-MHz-wide channels to ensure greater reliability over longer distances. It also features 0-dBm (1 mW) power output and a typical maximum range of 50 meters. Note that BLE is not compatible with standard Bluetooth. Features NimBLE complies with Bluetooth Core Specification 4.2 which introduces several new features that make it an ideal wireless technology for the Internet of Things (IoT). LE Privacy 1.2 for frequent changes to the device address to make it difficult to track for outsiders Roadmap LE Secure Connections featuring FIPS-compliant algorithms. Roadmap LE Data Length Extension for higher throughput Available now Enables users to assign an Internet Protocol (IP) address (complaint with the IPv6 or 6LoWPAN standard) to a Bluetooth device through Internet Protocol Support Profile (IPSP) Roadmap NimBLE supports features from older specifications including, Support multiple roles (master(central)/slave(peripheral), server/client) simultaneously Support simultaneous advertising and scanning Support being slave to multiple masters simultaneously (subject to memory and scheduling constraints) Low Duty Cycle Directed Advertising Connection parameters request procedure LE Ping 32 bits UUID L2CAP Connection Oriented Channels Components A Bluetooth low energy stack (NimBLE included) consists of two components with several subcomponents: Controller Physical Layer : adaptive frequency-hopping Gaussian Frequency Shift Keying (GFSK) radio using 40 RF channels (0-39), with 2 MHz spacing. Link Layer : with one of five states (Standby, Advertising, Scanning, Initiating, Connection states) active at any time Host Logical Link Control and Adaptation Protocol (L2CAP) : provides logical channels, named L2CAP channels, which are multiplexed over one or more logical links to provide packet segmentation and reassembly, flow control, error control, streaming, QoS etc. Security Manager (SM) : uses Security Manager Protocol (SMP) for pairing and transport specific key distribution for securing radio communication Attribute protocol (ATT) : allows a device ( Server ) to expose certain pieces of data, known as Attributes , to another device ( Client ) Generic Attribute Profile (GATT) : a framework for using the ATT protocol to exchange attributes encapsulated as Characteristics or Services Generic Access Profile (GAP) : a base profile which all Bluetooth devices implement, which in the case of LE, defines the Physical Layer, Link Layer, L2CAP, Security Manager, Attribute Protocol and Generic Attribute Profile. Host Controller Interface (HCI) : the interface between the host and controller either through software API or by a hardware interface such as SPI, UART or USB. Subsequent chapters in this manual will go into the details of the implementation of each component, APIs available, and things to consider while designing a NimBLE app. Example NimBLE projects Mynewt comes with two built-in projects that allow users to play with NimBLE, try the tutorials out with, and see how to use available services. bletiny : A simple shell application which provides a basic interface to the host-side of the BLE stack. bleprph : A basic peripheral device with no user interface. It advertises automatically on startup, and resumes advertising whenever a connection is terminated. It supports a maximum of one connection.","title":"NimBLE Introduction"},{"location":"network/ble/ble_intro/#ble-introduction","text":"Apache Mynewt offers the world's first fully open-source Bluetooth Low Energy (BLE) or Bluetooth Smart stack. It is called NimBLE. BLE technology operates in the unlicensed industrial, scientific and medical (ISM) band at 2.4 to 2.485 GHz which is available in most countries. It uses a spread spectrum, frequency hopping, full-duplex signal. BLE FHSS employs 40 2-MHz-wide channels to ensure greater reliability over longer distances. It also features 0-dBm (1 mW) power output and a typical maximum range of 50 meters. Note that BLE is not compatible with standard Bluetooth.","title":"BLE Introduction"},{"location":"network/ble/ble_intro/#features","text":"NimBLE complies with Bluetooth Core Specification 4.2 which introduces several new features that make it an ideal wireless technology for the Internet of Things (IoT). LE Privacy 1.2 for frequent changes to the device address to make it difficult to track for outsiders Roadmap LE Secure Connections featuring FIPS-compliant algorithms. Roadmap LE Data Length Extension for higher throughput Available now Enables users to assign an Internet Protocol (IP) address (complaint with the IPv6 or 6LoWPAN standard) to a Bluetooth device through Internet Protocol Support Profile (IPSP) Roadmap NimBLE supports features from older specifications including, Support multiple roles (master(central)/slave(peripheral), server/client) simultaneously Support simultaneous advertising and scanning Support being slave to multiple masters simultaneously (subject to memory and scheduling constraints) Low Duty Cycle Directed Advertising Connection parameters request procedure LE Ping 32 bits UUID L2CAP Connection Oriented Channels","title":"Features"},{"location":"network/ble/ble_intro/#components","text":"A Bluetooth low energy stack (NimBLE included) consists of two components with several subcomponents: Controller Physical Layer : adaptive frequency-hopping Gaussian Frequency Shift Keying (GFSK) radio using 40 RF channels (0-39), with 2 MHz spacing. Link Layer : with one of five states (Standby, Advertising, Scanning, Initiating, Connection states) active at any time Host Logical Link Control and Adaptation Protocol (L2CAP) : provides logical channels, named L2CAP channels, which are multiplexed over one or more logical links to provide packet segmentation and reassembly, flow control, error control, streaming, QoS etc. Security Manager (SM) : uses Security Manager Protocol (SMP) for pairing and transport specific key distribution for securing radio communication Attribute protocol (ATT) : allows a device ( Server ) to expose certain pieces of data, known as Attributes , to another device ( Client ) Generic Attribute Profile (GATT) : a framework for using the ATT protocol to exchange attributes encapsulated as Characteristics or Services Generic Access Profile (GAP) : a base profile which all Bluetooth devices implement, which in the case of LE, defines the Physical Layer, Link Layer, L2CAP, Security Manager, Attribute Protocol and Generic Attribute Profile. Host Controller Interface (HCI) : the interface between the host and controller either through software API or by a hardware interface such as SPI, UART or USB. Subsequent chapters in this manual will go into the details of the implementation of each component, APIs available, and things to consider while designing a NimBLE app.","title":"Components"},{"location":"network/ble/ble_intro/#example-nimble-projects","text":"Mynewt comes with two built-in projects that allow users to play with NimBLE, try the tutorials out with, and see how to use available services. bletiny : A simple shell application which provides a basic interface to the host-side of the BLE stack. bleprph : A basic peripheral device with no user interface. It advertises automatically on startup, and resumes advertising whenever a connection is terminated. It supports a maximum of one connection.","title":"Example NimBLE projects"},{"location":"network/ble/ble_sec/","text":"BLE Security The Bluetooth Low Energy security model includes five distinct security concepts as listed below. For detailed specifications, see BLUETOOTH SPECIFICATION Version 4.2 [Vol 1, Part A]. Pairing : The process for creating one or more shared secret keys. In LE a single link key is generated by combining contributions from each device into a link key used during pairing. Bonding : The act of storing the keys created during pairing for use in subsequent connections in order to form a trusted device pair. Bonding is currently a roadmap item for Apache Mynewt. Device authentication : Verification that the two devices have the same keys (verify device identity) Encryption : Keeps message confidential. Encryption in Bluetooth LE uses AES-CCM cryptography and is performed in the Controller . Message integrity : Protects against message forgeries. Bluetooth LE uses four association models depending on the I/O capabilities of the devices. Apache Mynewt has first implemented support for \"Just Works\" only. Just Works : designed for scenarios where at least one of the devices does not have a display capable of displaying a six digit number nor does it have a keyboard capable of entering six decimal digits. Numeric Comparison : designed for scenarios where both devices are capable of displaying a six digit number and both are capable of having the user enter \"yes\" or \"no\". A good example of this model is the cell phone / PC scenario. Out of Band : designed for scenarios where an Out of Band mechanism is used to both discover the devices as well as to exchange or transfer cryptographic numbers used in the pairing process. Passkey Entry : designed for the scenario where one device has input capability but does not have the capability to display six digits and the other device has output capabilities. A good example of this model is the PC and keyboard scenario. Key Generation Key generation for all purposes in Bluetooth LE is performed by the Host on each LE device independent of any other LE device. Privacy Feature Bluetooth LE supports an optional feature during connection mode and connection procedures that reduces the ability to track a LE device over a period of time by changing the Bluetooth device address on a frequent basis. Privacy support is currently a roadmap item for Apache Mynewt. There are two variants of the privacy feature. In the first variant, private addresses are resolved and generated by the Host . In the second variant, private addresses are resolved and generated by the Controller without involving the Host after the Host provides the Controller device identity information. The Host may provide the Controller with a complete resolving list or a subset of the resolving list. Device filtering becomes possible in the second variant when address resolution is performed in the Controller because the peer\u2019s device identity address can be resolved prior to checking whether it is in the white list. Note : When address resolution is performed exclusively in the Host, a device may experience increased power consumption because device filtering must be disabled. For more details on the privacy feature, refer to BLUETOOTH SPECIFICATION Version 4.2 [Vol 3, Part C] (Published 02 December 2014), Page 592.","title":"NimBLE Security"},{"location":"network/ble/ble_sec/#ble-security","text":"The Bluetooth Low Energy security model includes five distinct security concepts as listed below. For detailed specifications, see BLUETOOTH SPECIFICATION Version 4.2 [Vol 1, Part A]. Pairing : The process for creating one or more shared secret keys. In LE a single link key is generated by combining contributions from each device into a link key used during pairing. Bonding : The act of storing the keys created during pairing for use in subsequent connections in order to form a trusted device pair. Bonding is currently a roadmap item for Apache Mynewt. Device authentication : Verification that the two devices have the same keys (verify device identity) Encryption : Keeps message confidential. Encryption in Bluetooth LE uses AES-CCM cryptography and is performed in the Controller . Message integrity : Protects against message forgeries. Bluetooth LE uses four association models depending on the I/O capabilities of the devices. Apache Mynewt has first implemented support for \"Just Works\" only. Just Works : designed for scenarios where at least one of the devices does not have a display capable of displaying a six digit number nor does it have a keyboard capable of entering six decimal digits. Numeric Comparison : designed for scenarios where both devices are capable of displaying a six digit number and both are capable of having the user enter \"yes\" or \"no\". A good example of this model is the cell phone / PC scenario. Out of Band : designed for scenarios where an Out of Band mechanism is used to both discover the devices as well as to exchange or transfer cryptographic numbers used in the pairing process. Passkey Entry : designed for the scenario where one device has input capability but does not have the capability to display six digits and the other device has output capabilities. A good example of this model is the PC and keyboard scenario.","title":"BLE Security"},{"location":"network/ble/ble_sec/#key-generation","text":"Key generation for all purposes in Bluetooth LE is performed by the Host on each LE device independent of any other LE device.","title":"Key Generation"},{"location":"network/ble/ble_sec/#privacy-feature","text":"Bluetooth LE supports an optional feature during connection mode and connection procedures that reduces the ability to track a LE device over a period of time by changing the Bluetooth device address on a frequent basis. Privacy support is currently a roadmap item for Apache Mynewt. There are two variants of the privacy feature. In the first variant, private addresses are resolved and generated by the Host . In the second variant, private addresses are resolved and generated by the Controller without involving the Host after the Host provides the Controller device identity information. The Host may provide the Controller with a complete resolving list or a subset of the resolving list. Device filtering becomes possible in the second variant when address resolution is performed in the Controller because the peer\u2019s device identity address can be resolved prior to checking whether it is in the white list. Note : When address resolution is performed exclusively in the Host, a device may experience increased power consumption because device filtering must be disabled. For more details on the privacy feature, refer to BLUETOOTH SPECIFICATION Version 4.2 [Vol 3, Part C] (Published 02 December 2014), Page 592.","title":"Privacy Feature"},{"location":"network/ble/bletiny_api/","text":"API for bletiny app \"bletiny\" is one of the sample applications that come with Mynewt. It is a simple shell application which provides a basic interface to the host-side of the BLE stack. \"bletiny\" includes all the possible roles (Central/Peripheral) and they may be run simultaneously. You can run bletiny on a board and issue commands that make it behave as a central or a peripheral with different peers. Highlighted below are some of the ways you can use the API to establish connections and discover services and characteristics from peer devices. For descriptions of the full API, go to the next sections on GAP in bletiny and GATT in bletiny . Set device public address. Currently the device public address is hardcoded to 0a:0b:0c:0d:0e:0f in bletiny app but you can change it by going into its source code and initializing it to the desired value as described in the section on how to initialize device addr . Initiate a direct connection to a device In this case, your board is acting as a central and initiating a connection with another BLE device. The example assumes you know the address of the peer, either by scanning for available peers or because you have set up the peer yourself. b conn addr_type=public addr=d4:f5:13:53:d2:43 [ts=118609ssb, mod=64 level=2] connection complete; status=0 handle=1 peer_addr_type=0 peer_addr=0x43:0xd2:0x53:0x13:0xf5:0xd4 conn_itvl=40 conn_latency=0 supervision_timeout=256 The handle=1 in the output indicates that it is connection-1. Configure advertisements to include device name In this case, your board is acting as a peripheral. b set adv_data name=<your-device-name> Begin sending undirected general advertisements In this case, your board is acting as a peripheral. b adv conn=und disc=gen Show established connections. b show conn Discover and display peer's services. This is how you discover and then display the services of the peer you established earlier across connection-1. b disc svc conn=1 b show chr [ts=132425ssb, mod=64 level=2] CONNECTION: handle=1 addr=d4:f5:13:53:d2:43 [ts=132428ssb, mod=64 level=2] start=1 end=5 uuid=0x1800 [ts=132433ssb, mod=64 level=2] start=6 end=16 uuid=0x1808 [ts=132437ssb, mod=64 level=2] start=17 end=31 uuid=0x180a [ts=132441ssb, mod=64 level=2] start=32 end=65535 uuid=00000000-0000-1000-1000000000000000 Discover characteristics for each service on peer The following examples show how to find the characteristics for each service available on the peer device across connection-1. The start and end values depend on the specific services discovered using the previous command b show chr . Continuing with the example above, you can discover the characteristics of the first service and display it using the following commands. b disc chr conn=1 start=1 end=5 b show chr [ts=163063ssb, mod=64 level=2] CONNECTION: handle=1 addr=d4:f5:13:53:d2:43 [ts=163067ssb, mod=64 level=2] start=1 end=5 uuid=0x1800 [ts=163071ssb, mod=64 level=2] def_handle=2 val_handle=3 properties=0x02 uuid=0x2a00 [ts=163078ssb, mod=64 level=2] def_handle=4 val_handle=5 properties=0x02 uuid=0x2a01 [ts=163085ssb, mod=64 level=2] start=6 end=16 uuid=0x1808 [ts=163089ssb, mod=64 level=2] start=17 end=31 uuid=0x180a [ts=163094ssb, mod=64 level=2] start=32 end=65535 uuid=00000000-0000-1000-1000000000000000 You can next discover characteristics for the second service and display. b disc chr conn=1 start=6 end=16 b show chr [ts=180631ssb, mod=64 level=2] CONNECTION: handle=1 addr=d4:f5:13:53:d2:43 [ts=180634ssb, mod=64 level=2] start=1 end=5 uuid=0x1800 [ts=180639ssb, mod=64 level=2] def_handle=2 val_handle=3 properties=0x02 uuid=0x2a00 [ts=180646ssb, mod=64 level=2] def_handle=4 val_handle=5 properties=0x02 uuid=0x2a01 [ts=180653ssb, mod=64 level=2] start=6 end=16 uuid=0x1808 [ts=180657ssb, mod=64 level=2] def_handle=7 val_handle=8 properties=0x10 uuid=0x2a18 [ts=180664ssb, mod=64 level=2] def_handle=10 val_handle=11 properties=0x02 uuid=0x2a51 [ts=180672ssb, mod=64 level=2] def_handle=12 val_handle=13 properties=0x28 uuid=0x2a52 [ts=180679ssb, mod=64 level=2] def_handle=15 val_handle=16 properties=0x02 uuid=0x2a08 [ts=180686ssb, mod=64 level=2] start=17 end=31 uuid=0x180a [ts=180691ssb, mod=64 level=2] start=32 end=65535 uuid=00000000-0000-1000-1000000000000000 Discover descriptors for each characteristic on peer Just as before, the start and end values depend on the specific characteristics discovered. b disc dsc conn=1 start=1 end=5 b disc dsc conn=1 start=6 end=16 b disc dsc conn=1 start=17 end=31 Read an attribute belonging to the peer b read conn=1 attr=18 attr=21 Write to an attribute belonging to the peer b write conn=1 attr=3 value=0x01:0x02:0x03 Perform a passive scan This is how you tell your board to listen to all advertisements around it. The duration is specified in ms. b scan dur=1000 disc=gen type=passive filt=no_wl","title":"toc"},{"location":"network/ble/bletiny_api/#api-for-bletiny-app","text":"\"bletiny\" is one of the sample applications that come with Mynewt. It is a simple shell application which provides a basic interface to the host-side of the BLE stack. \"bletiny\" includes all the possible roles (Central/Peripheral) and they may be run simultaneously. You can run bletiny on a board and issue commands that make it behave as a central or a peripheral with different peers. Highlighted below are some of the ways you can use the API to establish connections and discover services and characteristics from peer devices. For descriptions of the full API, go to the next sections on GAP in bletiny and GATT in bletiny .","title":"API for bletiny app"},{"location":"network/ble/bletiny_api/#set-device-public-address","text":"Currently the device public address is hardcoded to 0a:0b:0c:0d:0e:0f in bletiny app but you can change it by going into its source code and initializing it to the desired value as described in the section on how to initialize device addr .","title":"Set device public address."},{"location":"network/ble/bletiny_api/#initiate-a-direct-connection-to-a-device","text":"In this case, your board is acting as a central and initiating a connection with another BLE device. The example assumes you know the address of the peer, either by scanning for available peers or because you have set up the peer yourself. b conn addr_type=public addr=d4:f5:13:53:d2:43 [ts=118609ssb, mod=64 level=2] connection complete; status=0 handle=1 peer_addr_type=0 peer_addr=0x43:0xd2:0x53:0x13:0xf5:0xd4 conn_itvl=40 conn_latency=0 supervision_timeout=256 The handle=1 in the output indicates that it is connection-1.","title":"Initiate a direct connection to a device"},{"location":"network/ble/bletiny_api/#configure-advertisements-to-include-device-name","text":"In this case, your board is acting as a peripheral. b set adv_data name=<your-device-name>","title":"Configure advertisements to include device name"},{"location":"network/ble/bletiny_api/#begin-sending-undirected-general-advertisements","text":"In this case, your board is acting as a peripheral. b adv conn=und disc=gen","title":"Begin sending undirected general advertisements"},{"location":"network/ble/bletiny_api/#show-established-connections","text":"b show conn","title":"Show established connections."},{"location":"network/ble/bletiny_api/#discover-and-display-peers-services","text":"This is how you discover and then display the services of the peer you established earlier across connection-1. b disc svc conn=1 b show chr [ts=132425ssb, mod=64 level=2] CONNECTION: handle=1 addr=d4:f5:13:53:d2:43 [ts=132428ssb, mod=64 level=2] start=1 end=5 uuid=0x1800 [ts=132433ssb, mod=64 level=2] start=6 end=16 uuid=0x1808 [ts=132437ssb, mod=64 level=2] start=17 end=31 uuid=0x180a [ts=132441ssb, mod=64 level=2] start=32 end=65535 uuid=00000000-0000-1000-1000000000000000","title":"Discover and display peer's services."},{"location":"network/ble/bletiny_api/#discover-characteristics-for-each-service-on-peer","text":"The following examples show how to find the characteristics for each service available on the peer device across connection-1. The start and end values depend on the specific services discovered using the previous command b show chr . Continuing with the example above, you can discover the characteristics of the first service and display it using the following commands. b disc chr conn=1 start=1 end=5 b show chr [ts=163063ssb, mod=64 level=2] CONNECTION: handle=1 addr=d4:f5:13:53:d2:43 [ts=163067ssb, mod=64 level=2] start=1 end=5 uuid=0x1800 [ts=163071ssb, mod=64 level=2] def_handle=2 val_handle=3 properties=0x02 uuid=0x2a00 [ts=163078ssb, mod=64 level=2] def_handle=4 val_handle=5 properties=0x02 uuid=0x2a01 [ts=163085ssb, mod=64 level=2] start=6 end=16 uuid=0x1808 [ts=163089ssb, mod=64 level=2] start=17 end=31 uuid=0x180a [ts=163094ssb, mod=64 level=2] start=32 end=65535 uuid=00000000-0000-1000-1000000000000000 You can next discover characteristics for the second service and display. b disc chr conn=1 start=6 end=16 b show chr [ts=180631ssb, mod=64 level=2] CONNECTION: handle=1 addr=d4:f5:13:53:d2:43 [ts=180634ssb, mod=64 level=2] start=1 end=5 uuid=0x1800 [ts=180639ssb, mod=64 level=2] def_handle=2 val_handle=3 properties=0x02 uuid=0x2a00 [ts=180646ssb, mod=64 level=2] def_handle=4 val_handle=5 properties=0x02 uuid=0x2a01 [ts=180653ssb, mod=64 level=2] start=6 end=16 uuid=0x1808 [ts=180657ssb, mod=64 level=2] def_handle=7 val_handle=8 properties=0x10 uuid=0x2a18 [ts=180664ssb, mod=64 level=2] def_handle=10 val_handle=11 properties=0x02 uuid=0x2a51 [ts=180672ssb, mod=64 level=2] def_handle=12 val_handle=13 properties=0x28 uuid=0x2a52 [ts=180679ssb, mod=64 level=2] def_handle=15 val_handle=16 properties=0x02 uuid=0x2a08 [ts=180686ssb, mod=64 level=2] start=17 end=31 uuid=0x180a [ts=180691ssb, mod=64 level=2] start=32 end=65535 uuid=00000000-0000-1000-1000000000000000","title":"Discover characteristics for each service on peer"},{"location":"network/ble/bletiny_api/#discover-descriptors-for-each-characteristic-on-peer","text":"Just as before, the start and end values depend on the specific characteristics discovered. b disc dsc conn=1 start=1 end=5 b disc dsc conn=1 start=6 end=16 b disc dsc conn=1 start=17 end=31","title":"Discover descriptors for each characteristic on peer"},{"location":"network/ble/bletiny_api/#read-an-attribute-belonging-to-the-peer","text":"b read conn=1 attr=18 attr=21","title":"Read an attribute belonging to the peer"},{"location":"network/ble/bletiny_api/#write-to-an-attribute-belonging-to-the-peer","text":"b write conn=1 attr=3 value=0x01:0x02:0x03","title":"Write to an attribute belonging to the peer"},{"location":"network/ble/bletiny_api/#perform-a-passive-scan","text":"This is how you tell your board to listen to all advertisements around it. The duration is specified in ms. b scan dur=1000 disc=gen type=passive filt=no_wl","title":"Perform a passive scan"},{"location":"network/ble/nimble_setup/","text":"Set up a NimBLE application This tutorial explains how to set up an application using the NimBLE stack. The end result will be a framework that you can use to create your own BLE application using the nimble stack. This tutorial assumes that you have already installed the newt tool and are familiar with its concepts. Create the application directory You start by creating a project space for your own application work using the Newt tool ( my_proj1 in this example) and installing all the additional apps and libraries available by adding the repo apache-mynewt-core . See the tutorial on adding a repo for more on working with repos. ~/dev$ newt new my_proj1 Downloading project skeleton from apache/incubator-mynewt-blinky... Installing skeleton in my_proj1... Project my_proj1 successfully created. ~/dev$ tree my_proj1 my_proj1 \u251c\u2500\u2500 DISCLAIMER \u251c\u2500\u2500 LICENSE \u251c\u2500\u2500 NOTICE \u251c\u2500\u2500 README.md \u251c\u2500\u2500 apps \u2502 \u2514\u2500\u2500 blinky \u2502 \u251c\u2500\u2500 pkg.yml \u2502 \u2514\u2500\u2500 src \u2502 \u2514\u2500\u2500 main.c \u251c\u2500\u2500 project.yml \u2514\u2500\u2500 targets \u251c\u2500\u2500 my_blinky_sim \u2502 \u251c\u2500\u2500 pkg.yml \u2502 \u2514\u2500\u2500 target.yml \u2514\u2500\u2500 unittest \u251c\u2500\u2500 pkg.yml \u2514\u2500\u2500 target.yml 6 directories, 11 files ~/dev$ cd my_proj1 ~/dev/my_proj1$ newt install apache-mynewt-core ~/dev/my_proj1$ tree . \u251c\u2500\u2500 DISCLAIMER \u251c\u2500\u2500 LICENSE \u251c\u2500\u2500 NOTICE \u251c\u2500\u2500 README.md \u251c\u2500\u2500 apps \u2502 \u2514\u2500\u2500 blinky \u2502 \u251c\u2500\u2500 pkg.yml \u2502 \u2514\u2500\u2500 src \u2502 \u2514\u2500\u2500 main.c \u251c\u2500\u2500 project.state \u251c\u2500\u2500 project.yml \u251c\u2500\u2500 repos \u2502 \u2514\u2500\u2500 apache-mynewt-core \u2502 \u251c\u2500\u2500 DISCLAIMER \u2502 \u251c\u2500\u2500 LICENSE \u2502 \u251c\u2500\u2500 NOTICE \u2502 \u251c\u2500\u2500 README.md \u2502 \u251c\u2500\u2500 RELEASE_NOTES.md \u2502 \u251c\u2500\u2500 apps \u2502 \u2502 \u251c\u2500\u2500 bleprph \u2502 \u2502 \u2502 \u2514\u2500\u2500 src \u2502 \u2502 \u2502 \u251c\u2500\u2500 bleprph.h \u2502 \u2502 \u2502 \u251c\u2500\u2500 gatt_svr.c \u2502 \u2502 \u2502 \u2514\u2500\u2500 main.c \u2502 \u2502 \u251c\u2500\u2500 bletest \u2502 \u2502 \u2502 \u251c\u2500\u2500 pkg.yml \u2502 \u2502 \u2502 \u2514\u2500\u2500 src \u2502 \u2502 \u2502 \u2514\u2500\u2500 main.c \u2502 \u2502 \u251c\u2500\u2500 bletiny \u2502 \u2502 \u2502 \u251c\u2500\u2500 pkg.yml \u2502 \u2502 \u2502 \u2514\u2500\u2500 src \u2502 \u2502 \u2502 \u251c\u2500\u2500 bletiny_priv.h \u2502 \u2502 \u2502 \u251c\u2500\u2500 cmd.c \u2502 \u2502 \u2502 \u251c\u2500\u2500 main.c \u2502 \u2502 \u2502 \u251c\u2500\u2500 parse.c \u2502 \u2502 \u2502 \u2514\u2500\u2500 periph.c <snip> 232 directories, 846 files It's time to build your own app using one or more of the example apps available in the repo apache-mynewt-core . ~/dev/my_proj1$ ls repos/apache-mynewt-core/apps bleprph bletiny boot luatest test bletest blinky ffs2native slinky At the very least your app must contain a main() function and a pkg.yml file. Use the following steps to create minimal ... 1. Create the app directory structure. ~/dev/my_proj1$ mkdir -p apps/ble_app/src 2. Paste the following contents into apps/ble_app/pkg.yml . pkg.name: apps/ble_app pkg.type: app pkg.deps: - \"@apache-mynewt-core/libs/baselibc\" - \"@apache-mynewt-core/libs/console/full\" - \"@apache-mynewt-core/libs/os\" - \"@apache-mynewt-core/net/nimble/controller\" - \"@apache-mynewt-core/net/nimble/host\" 3. Paste the following contents into apps/ble_app/src/main.c . #include <assert.h> #include \"os/os.h\" int main ( void ) { /* Initialize OS */ os_init (); /* Start the OS */ os_start (); /* os_start should never return. If it does, this should be an error */ assert ( 0 ); } In this main() all we are doing is initializing the Mynewt OS and starting it. Create the target Now you have to create the target that you will use to build your application. We will call this target \"ble_tgt\". Type the newt target create ble_tgt command. You should get this: ~/dev/my_proj1$ newt target create ble_tgt Target targets/ble_tgt successfully created What this command just did was to create a directory called ble_tgt in the targets directory of your project. Two files are created in that directory: pkg.yml and target.yml. The target is not yet complete though! We need to set some target variables for this project. Currently, the nimble stack has been ported to the Nordic nrf5x chipsets; specifically the nrf51 and nrf52. This application will use the nrf52 but we will also show the setup for the nrf51 in case your project uses that chip. Here is the command you will need to set up your target for the nrf52: ~/dev/my_proj1$ newt target set ble_tgt \\ app=apps/ble_app \\ bsp=@apache-mynewt-core/hw/bsp/nrf52pdk \\ build_profile=optimized Target targets/ble_tgt successfully set target.app to apps/ble_app Target targets/ble_tgt successfully set target.bsp to @apache-mynewt-core/hw/bsp/nrf52pdk Target targets/ble_tgt successfully set target.build_profile to optimized Here is the command you will need to set up your target for the nrf51: ~/dev/my_proj1$ newt target set ble_tgt \\ app=apps/ble_app \\ bsp=@apache-mynewt-core/hw/bsp/nrf51dk \\ build_profile=optimized Target targets/ble_tgt successfully set target.app to apps/ble_app Target targets/ble_tgt successfully set target.bsp to @apache-mynewt-core/hw/bsp/nrf51dk Target targets/ble_tgt successfully set target.build_profile to optimized Nimble stack initialization There are certain stack initialization steps that are required for a BLE application to be up and running. If you are running a canned example (e.g. bletiny), these steps are already done for you. When you are writing your own app, you may want to assign different initial values or initialize additional packages that you may have added to your project or written yourself. Details of the initialization step requirements are covered in Initialize Stack step. Building the application Now that we have created the application and the target we can build it and test it out. The command you need to run is the newt build command with the target we created ( ble_tgt ). The output will show the files being compiled and linked. You should see this when all is done (except for the ... of course): ~/dev/my_proj1$ newt build ble_tgt ... Archiving os.a Compiling cons_fmt.c Compiling cons_tty.c Archiving full.a Linking ble_app.elf App successfully built: /Users/wes/dev/my_proj1/bin/ble_tgt/apps/ble_app/ble_app.elf Conclusion You now have a fully functional BLE app (never mind the fact that it doesn't actually do anything yet!). With all the necessary infrastructure in place, you can now start turning this into a real application. Additional tutorials with focus on adding application-layer functionality to your Nimble application will be coming soon. In the meantime, you might get some inspiration from apache-mynewt-core's example Nimble apps. These apps can be found at the below locations, relative to your project's base directory: repos/apache-mynewt-core/apps/bleprph repos/apache-mynewt-core/apps/bletiny","title":"Set up application"},{"location":"network/ble/nimble_setup/#set-up-a-nimble-application","text":"This tutorial explains how to set up an application using the NimBLE stack. The end result will be a framework that you can use to create your own BLE application using the nimble stack. This tutorial assumes that you have already installed the newt tool and are familiar with its concepts.","title":"Set up a NimBLE application"},{"location":"network/ble/nimble_setup/#create-the-application-directory","text":"You start by creating a project space for your own application work using the Newt tool ( my_proj1 in this example) and installing all the additional apps and libraries available by adding the repo apache-mynewt-core . See the tutorial on adding a repo for more on working with repos. ~/dev$ newt new my_proj1 Downloading project skeleton from apache/incubator-mynewt-blinky... Installing skeleton in my_proj1... Project my_proj1 successfully created. ~/dev$ tree my_proj1 my_proj1 \u251c\u2500\u2500 DISCLAIMER \u251c\u2500\u2500 LICENSE \u251c\u2500\u2500 NOTICE \u251c\u2500\u2500 README.md \u251c\u2500\u2500 apps \u2502 \u2514\u2500\u2500 blinky \u2502 \u251c\u2500\u2500 pkg.yml \u2502 \u2514\u2500\u2500 src \u2502 \u2514\u2500\u2500 main.c \u251c\u2500\u2500 project.yml \u2514\u2500\u2500 targets \u251c\u2500\u2500 my_blinky_sim \u2502 \u251c\u2500\u2500 pkg.yml \u2502 \u2514\u2500\u2500 target.yml \u2514\u2500\u2500 unittest \u251c\u2500\u2500 pkg.yml \u2514\u2500\u2500 target.yml 6 directories, 11 files ~/dev$ cd my_proj1 ~/dev/my_proj1$ newt install apache-mynewt-core ~/dev/my_proj1$ tree . \u251c\u2500\u2500 DISCLAIMER \u251c\u2500\u2500 LICENSE \u251c\u2500\u2500 NOTICE \u251c\u2500\u2500 README.md \u251c\u2500\u2500 apps \u2502 \u2514\u2500\u2500 blinky \u2502 \u251c\u2500\u2500 pkg.yml \u2502 \u2514\u2500\u2500 src \u2502 \u2514\u2500\u2500 main.c \u251c\u2500\u2500 project.state \u251c\u2500\u2500 project.yml \u251c\u2500\u2500 repos \u2502 \u2514\u2500\u2500 apache-mynewt-core \u2502 \u251c\u2500\u2500 DISCLAIMER \u2502 \u251c\u2500\u2500 LICENSE \u2502 \u251c\u2500\u2500 NOTICE \u2502 \u251c\u2500\u2500 README.md \u2502 \u251c\u2500\u2500 RELEASE_NOTES.md \u2502 \u251c\u2500\u2500 apps \u2502 \u2502 \u251c\u2500\u2500 bleprph \u2502 \u2502 \u2502 \u2514\u2500\u2500 src \u2502 \u2502 \u2502 \u251c\u2500\u2500 bleprph.h \u2502 \u2502 \u2502 \u251c\u2500\u2500 gatt_svr.c \u2502 \u2502 \u2502 \u2514\u2500\u2500 main.c \u2502 \u2502 \u251c\u2500\u2500 bletest \u2502 \u2502 \u2502 \u251c\u2500\u2500 pkg.yml \u2502 \u2502 \u2502 \u2514\u2500\u2500 src \u2502 \u2502 \u2502 \u2514\u2500\u2500 main.c \u2502 \u2502 \u251c\u2500\u2500 bletiny \u2502 \u2502 \u2502 \u251c\u2500\u2500 pkg.yml \u2502 \u2502 \u2502 \u2514\u2500\u2500 src \u2502 \u2502 \u2502 \u251c\u2500\u2500 bletiny_priv.h \u2502 \u2502 \u2502 \u251c\u2500\u2500 cmd.c \u2502 \u2502 \u2502 \u251c\u2500\u2500 main.c \u2502 \u2502 \u2502 \u251c\u2500\u2500 parse.c \u2502 \u2502 \u2502 \u2514\u2500\u2500 periph.c <snip> 232 directories, 846 files It's time to build your own app using one or more of the example apps available in the repo apache-mynewt-core . ~/dev/my_proj1$ ls repos/apache-mynewt-core/apps bleprph bletiny boot luatest test bletest blinky ffs2native slinky At the very least your app must contain a main() function and a pkg.yml file. Use the following steps to create minimal ... 1. Create the app directory structure. ~/dev/my_proj1$ mkdir -p apps/ble_app/src 2. Paste the following contents into apps/ble_app/pkg.yml . pkg.name: apps/ble_app pkg.type: app pkg.deps: - \"@apache-mynewt-core/libs/baselibc\" - \"@apache-mynewt-core/libs/console/full\" - \"@apache-mynewt-core/libs/os\" - \"@apache-mynewt-core/net/nimble/controller\" - \"@apache-mynewt-core/net/nimble/host\" 3. Paste the following contents into apps/ble_app/src/main.c . #include <assert.h> #include \"os/os.h\" int main ( void ) { /* Initialize OS */ os_init (); /* Start the OS */ os_start (); /* os_start should never return. If it does, this should be an error */ assert ( 0 ); } In this main() all we are doing is initializing the Mynewt OS and starting it.","title":"Create the application directory"},{"location":"network/ble/nimble_setup/#create-the-target","text":"Now you have to create the target that you will use to build your application. We will call this target \"ble_tgt\". Type the newt target create ble_tgt command. You should get this: ~/dev/my_proj1$ newt target create ble_tgt Target targets/ble_tgt successfully created What this command just did was to create a directory called ble_tgt in the targets directory of your project. Two files are created in that directory: pkg.yml and target.yml. The target is not yet complete though! We need to set some target variables for this project. Currently, the nimble stack has been ported to the Nordic nrf5x chipsets; specifically the nrf51 and nrf52. This application will use the nrf52 but we will also show the setup for the nrf51 in case your project uses that chip. Here is the command you will need to set up your target for the nrf52: ~/dev/my_proj1$ newt target set ble_tgt \\ app=apps/ble_app \\ bsp=@apache-mynewt-core/hw/bsp/nrf52pdk \\ build_profile=optimized Target targets/ble_tgt successfully set target.app to apps/ble_app Target targets/ble_tgt successfully set target.bsp to @apache-mynewt-core/hw/bsp/nrf52pdk Target targets/ble_tgt successfully set target.build_profile to optimized Here is the command you will need to set up your target for the nrf51: ~/dev/my_proj1$ newt target set ble_tgt \\ app=apps/ble_app \\ bsp=@apache-mynewt-core/hw/bsp/nrf51dk \\ build_profile=optimized Target targets/ble_tgt successfully set target.app to apps/ble_app Target targets/ble_tgt successfully set target.bsp to @apache-mynewt-core/hw/bsp/nrf51dk Target targets/ble_tgt successfully set target.build_profile to optimized","title":"Create the target"},{"location":"network/ble/nimble_setup/#nimble-stack-initialization","text":"There are certain stack initialization steps that are required for a BLE application to be up and running. If you are running a canned example (e.g. bletiny), these steps are already done for you. When you are writing your own app, you may want to assign different initial values or initialize additional packages that you may have added to your project or written yourself. Details of the initialization step requirements are covered in Initialize Stack step.","title":"Nimble stack initialization"},{"location":"network/ble/nimble_setup/#building-the-application","text":"Now that we have created the application and the target we can build it and test it out. The command you need to run is the newt build command with the target we created ( ble_tgt ). The output will show the files being compiled and linked. You should see this when all is done (except for the ... of course): ~/dev/my_proj1$ newt build ble_tgt ... Archiving os.a Compiling cons_fmt.c Compiling cons_tty.c Archiving full.a Linking ble_app.elf App successfully built: /Users/wes/dev/my_proj1/bin/ble_tgt/apps/ble_app/ble_app.elf","title":"Building the application"},{"location":"network/ble/nimble_setup/#conclusion","text":"You now have a fully functional BLE app (never mind the fact that it doesn't actually do anything yet!). With all the necessary infrastructure in place, you can now start turning this into a real application. Additional tutorials with focus on adding application-layer functionality to your Nimble application will be coming soon. In the meantime, you might get some inspiration from apache-mynewt-core's example Nimble apps. These apps can be found at the below locations, relative to your project's base directory: repos/apache-mynewt-core/apps/bleprph repos/apache-mynewt-core/apps/bletiny","title":"Conclusion"},{"location":"network/ble/bletiny/bletiny_GAP/","text":"GAP API for bletiny Generic Access Profile (GAP) defines the generic procedures related to discovery of Bluetooth devices (idle mode procedures) and link management aspects of connecting to Bluetooth devices (connecting mode procedures). It also defines procedures related to use of different security levels. Several different modes and procedures may be performed simultaneously over an LE physical transport. The following modes and procedures are defined for use over an LE physical transport: Broadcast mode and observation procedure These allow two devices to communicate in a unidirectional connectionless manner using the advertising events. Discovery modes and procedures All devices shall be in either non-discoverable mode or one of the discoverable modes. A device in the discoverable mode shall be in either the general discoverable mode or the limited discoverable mode. A device in non-discoverable mode will not be discovered by any device that is performing either the general discovery procedure or the limited discovery procedure. Connection modes and procedures allow a device to establish a connection to another device. allow updating of parameters of the connection allow termination of the connection Bonding modes and procedures Bonding allows two connected devices to exchange and store security and identity information to create a trusted relationship. Bonding can occur only between two devices in bondable mode. Usage API Item No. Modes and Procedures nimBLE command 1 Broadcast Mode b adv conn=non disc=x Observation Procedure b scan dur=x disc=x type=x filt=x 2 Non-Discoverable mode b adv conn=x disc=non Limited Discoverable mode b adv conn=x disc=ltd General Discoverable mode b adv conn=x disc=gen Limited Discovery procedure b scan dur=x disc=ltd type=active filt=no_wl General Discovery procedure b scan dur=x disc=gen type=active filt=no_wl Name Discovery procedure UNSUPPORTED 3 Non-connectable mode b adv conn=non disc=x Directed connectable mode b adv conn=dir disc=x addr_type=x addr=x Undirected connectable mode b adv conn=und disc=x Auto connection establishment procedure b wl addr_type=x addr=x Auto connection establishment procedure b conn addr_type=wl General connection establishment procedure AVAILABLE SOON Selective connection establishment procedure AVAILABLE SOON Direct connection establishment procedure b conn addr_type=x addr=x [params] Connection parameter update procedure b update conn=x <params> Terminate connection procedure b term conn=x 4 Non-Bondable mode AVAILABLE SOON Bondable mode AVAILABLE SOON Bonding procedure AVAILABLE SOON Connection Parameters The Connection parameter definitions can be found in Section 7.8.12 of the BLUETOOTH SPECIFICATION Version 4.2 [Vol 2, Part E]. Name Description nimBLE parameter Minimum connection interval Defines minimum allowed connection interval itvl_min Maximum connection interval Defines maximum allowed connection interval itvl_max Conn_Latency Defines the maximum allowed connection latency latency Supervision_Timeout Link supervision timeout for the connection. timeout LE_Scan_Interval Recommendation from the Host on how long the Controller should scan scan_itvl LE_Scan_Window Recommendation from the Host on how frequently the Controller should scan scan_window Minimum_CE_Length Informative parameter providing the Controller with the expected minimum length of the connection event min_ce_len Maximum_CE_Length Informative parameter providing the Controller with the expected maximum length of the connection event max_ce_len Advertisement data fields","title":"GAP in bletiny"},{"location":"network/ble/bletiny/bletiny_GAP/#gap-api-for-bletiny","text":"Generic Access Profile (GAP) defines the generic procedures related to discovery of Bluetooth devices (idle mode procedures) and link management aspects of connecting to Bluetooth devices (connecting mode procedures). It also defines procedures related to use of different security levels. Several different modes and procedures may be performed simultaneously over an LE physical transport. The following modes and procedures are defined for use over an LE physical transport: Broadcast mode and observation procedure These allow two devices to communicate in a unidirectional connectionless manner using the advertising events. Discovery modes and procedures All devices shall be in either non-discoverable mode or one of the discoverable modes. A device in the discoverable mode shall be in either the general discoverable mode or the limited discoverable mode. A device in non-discoverable mode will not be discovered by any device that is performing either the general discovery procedure or the limited discovery procedure. Connection modes and procedures allow a device to establish a connection to another device. allow updating of parameters of the connection allow termination of the connection Bonding modes and procedures Bonding allows two connected devices to exchange and store security and identity information to create a trusted relationship. Bonding can occur only between two devices in bondable mode.","title":"GAP API for bletiny"},{"location":"network/ble/bletiny/bletiny_GAP/#usage-api","text":"Item No. Modes and Procedures nimBLE command 1 Broadcast Mode b adv conn=non disc=x Observation Procedure b scan dur=x disc=x type=x filt=x 2 Non-Discoverable mode b adv conn=x disc=non Limited Discoverable mode b adv conn=x disc=ltd General Discoverable mode b adv conn=x disc=gen Limited Discovery procedure b scan dur=x disc=ltd type=active filt=no_wl General Discovery procedure b scan dur=x disc=gen type=active filt=no_wl Name Discovery procedure UNSUPPORTED 3 Non-connectable mode b adv conn=non disc=x Directed connectable mode b adv conn=dir disc=x addr_type=x addr=x Undirected connectable mode b adv conn=und disc=x Auto connection establishment procedure b wl addr_type=x addr=x Auto connection establishment procedure b conn addr_type=wl General connection establishment procedure AVAILABLE SOON Selective connection establishment procedure AVAILABLE SOON Direct connection establishment procedure b conn addr_type=x addr=x [params] Connection parameter update procedure b update conn=x <params> Terminate connection procedure b term conn=x 4 Non-Bondable mode AVAILABLE SOON Bondable mode AVAILABLE SOON Bonding procedure AVAILABLE SOON","title":"Usage API"},{"location":"network/ble/bletiny/bletiny_GAP/#connection-parameters","text":"The Connection parameter definitions can be found in Section 7.8.12 of the BLUETOOTH SPECIFICATION Version 4.2 [Vol 2, Part E]. Name Description nimBLE parameter Minimum connection interval Defines minimum allowed connection interval itvl_min Maximum connection interval Defines maximum allowed connection interval itvl_max Conn_Latency Defines the maximum allowed connection latency latency Supervision_Timeout Link supervision timeout for the connection. timeout LE_Scan_Interval Recommendation from the Host on how long the Controller should scan scan_itvl LE_Scan_Window Recommendation from the Host on how frequently the Controller should scan scan_window Minimum_CE_Length Informative parameter providing the Controller with the expected minimum length of the connection event min_ce_len Maximum_CE_Length Informative parameter providing the Controller with the expected maximum length of the connection event max_ce_len","title":"Connection Parameters"},{"location":"network/ble/bletiny/bletiny_GAP/#advertisement-data-fields","text":"","title":"Advertisement data fields"},{"location":"network/ble/bletiny/bletiny_GATT/","text":"GATT feature API for bletiny GATT(GENERIC ATTRIBUTE PROFILE) describes a service framework using the Attribute Protocol for discovering services, and for reading and writing characteristic values on a peer device. There are 11 features defined in the GATT Profile, and each of the features is mapped to procedures and sub-procedures: Item No. Feature Sub-Procedure nimBLE command 1 Server Configuration Exchange MTU b mtu 2 Primary Service Discovery Discover All Primary Services b disc svc conn=x Discover Primary Services By Service UUID b disc svc conn=x uuid=x 3 Relationship Discovery Find Included Services b find inc_svcs conn=x start=x end=x 4 Characteristic Discovery Discover All Characteristic of a Service b disc chr conn=x start=x end=x Discover Characteristic by UUID b disc chr conn=x start=x end=x uuid=x 5 Characteristic Descriptor Discovery Discover All Characteristic Descriptors b disc dsc conn=x start=x end=x 6 Reading a Characteristic Value Read Characteristic Value b read conn=x attr=x Read Using Characteristic UUID b read conn=x start=x end=x uuid=x Read Long Characteristic Values b read conn=x attr=x long=1 Read Multiple Characteristic Values b read conn=x attr=x attr=y attr=z 7 Writing a Characteristic Value Write Without Response b write conn=x value=0xXX:0xXX no_rsp=1 Signed Write Without Response NOT SUPPORTED Write Characteristic Value b write conn=x attr=x value=0xXX:0xXX Write Long Characteristic Values b write conn=x attr=x value=0xXX:0xXX long=1 Characteristic Value Reliable Writes b write conn=x attr=x value=0xXX:0xXX attr=y value=0xYY:0xYY 8 Notification of a Characteristic Value Notifications Write CLIENT CONFIGURATION characteristic 9 Indication of a Characteristic Value Indications Write CLIENT CONFIGURATION characteristic 10 Reading a Characteristic Descriptor Read Characteristic Descriptors b read conn=x attr=x Read Long Characteristic Descriptors b read conn=x attr=x long=1 11 Writing a Characteristic Descriptor Write Characteristic Descriptors b write conn=x value=0xXX:0xXX Write Long Characteristic Descriptors b write conn=x value=0xXX:0xXX long=1 Using nimBLE commands Assuming you have discovered and established a BLE connection with at least one peer device (as explained earlier in API for bletiny app , you can find out what characteristics and services are available over these connections. Here is a recap. b show conn To show discovered services b show svc To show discovered characteristics b show chr To show connection RSSI b show rssi conn=x","title":"GATT in bletiny"},{"location":"network/ble/bletiny/bletiny_GATT/#gatt-feature-api-for-bletiny","text":"GATT(GENERIC ATTRIBUTE PROFILE) describes a service framework using the Attribute Protocol for discovering services, and for reading and writing characteristic values on a peer device. There are 11 features defined in the GATT Profile, and each of the features is mapped to procedures and sub-procedures: Item No. Feature Sub-Procedure nimBLE command 1 Server Configuration Exchange MTU b mtu 2 Primary Service Discovery Discover All Primary Services b disc svc conn=x Discover Primary Services By Service UUID b disc svc conn=x uuid=x 3 Relationship Discovery Find Included Services b find inc_svcs conn=x start=x end=x 4 Characteristic Discovery Discover All Characteristic of a Service b disc chr conn=x start=x end=x Discover Characteristic by UUID b disc chr conn=x start=x end=x uuid=x 5 Characteristic Descriptor Discovery Discover All Characteristic Descriptors b disc dsc conn=x start=x end=x 6 Reading a Characteristic Value Read Characteristic Value b read conn=x attr=x Read Using Characteristic UUID b read conn=x start=x end=x uuid=x Read Long Characteristic Values b read conn=x attr=x long=1 Read Multiple Characteristic Values b read conn=x attr=x attr=y attr=z 7 Writing a Characteristic Value Write Without Response b write conn=x value=0xXX:0xXX no_rsp=1 Signed Write Without Response NOT SUPPORTED Write Characteristic Value b write conn=x attr=x value=0xXX:0xXX Write Long Characteristic Values b write conn=x attr=x value=0xXX:0xXX long=1 Characteristic Value Reliable Writes b write conn=x attr=x value=0xXX:0xXX attr=y value=0xYY:0xYY 8 Notification of a Characteristic Value Notifications Write CLIENT CONFIGURATION characteristic 9 Indication of a Characteristic Value Indications Write CLIENT CONFIGURATION characteristic 10 Reading a Characteristic Descriptor Read Characteristic Descriptors b read conn=x attr=x Read Long Characteristic Descriptors b read conn=x attr=x long=1 11 Writing a Characteristic Descriptor Write Characteristic Descriptors b write conn=x value=0xXX:0xXX Write Long Characteristic Descriptors b write conn=x value=0xXX:0xXX long=1","title":"GATT feature API for bletiny"},{"location":"network/ble/bletiny/bletiny_GATT/#using-nimble-commands","text":"Assuming you have discovered and established a BLE connection with at least one peer device (as explained earlier in API for bletiny app , you can find out what characteristics and services are available over these connections. Here is a recap. b show conn To show discovered services b show svc To show discovered characteristics b show chr To show connection RSSI b show rssi conn=x","title":"Using nimBLE commands"},{"location":"network/ble/bletiny/bletiny_advdata/","text":"Advertisement Data Fields This part defines the advertisement data fields used in the bletiny app. For a complete list of all data types and formats used for Extended Inquiry Response (EIR), Advertising Data (AD), and OOB data blocks, refer to the Supplement to the Bluetooth Core Specification, CSSv6, available for download here . Name Definition Details uuids16 16-bit Bluetooth Service UUIDs Indicates the Service UUID list is incomplete i.e. more 16-bit Service UUIDs available. 16 bit UUIDs shall only be used if they are assigned by the Bluetooth SIG. uuids16_is_complete 16-bit Bluetooth Service UUIDs Indicates the Service UUID list is complete. 16 bit UUIDs shall only be used if they are assigned by the Bluetooth SIG. uuids32 32-bit Bluetooth Service UUIDs Indicates the Service UUID list is incomplete i.e. more 32-bit Service UUIDs available. 32 bit UUIDs shall only be used if they are assigned by the Bluetooth SIG. uuids32_is_complete 32-bit Bluetooth Service UUIDs Indicates the Service UUID list is complete. 32 bit UUIDs shall only be used if they are assigned by the Bluetooth SIG. uuids128 Global 128-bit Service UUIDs More 128-bit Service UUIDs available. uuids128_is_complete Global 128-bit Service UUIDs Complete list of 128-bit Service UUIDs tx_pwr_lvl TX Power Level Indicates the transmitted power level of the packet containing the data type. The TX Power Level data type may be used to calculate path loss on a received packet using the following equation: pathloss = Tx Power Level \u2013 RSSI where \u201cRSSI\u201d is the received signal strength, in dBm, of the packet received. device_class Class of device Size: 3 octets slave_itvl_range Slave Connection Interval Range Contains the Peripheral\u2019s preferred connection interval range, for all logical connections. Size: 4 Octets . The first 2 octets defines the minimum value for the connection interval in the following manner: connIntervalmin = Conn_Interval_Min * 1.25 ms Conn_Interval_Min range: 0x0006 to 0x0C80 Value of 0xFFFF indicates no specific minimum. The other 2 octets defines the maximum value for the connection interval in the following manner: connIntervalmax = Conn_Interval_Max * 1.25 ms Conn_Interval_Max range: 0x0006 to 0x0C80 Conn_Interval_Max shall be equal to or greater than the Conn_Interval_Min. Value of 0xFFFF indicates no specific maximum. svc_data_uuid16 Service Data - 16 bit UUID Size: 2 or more octets The first 2 octets contain the 16 bit Service UUID followed by additional service data public_tgt_addr Public Target Address Defines the address of one or more intended recipients of an advertisement when one or more devices were bonded using a public address. This data type shall exist only once. It may be sent in either the Advertising or Scan Response data, but not both. appearance Appearance Defines the external appearance of the device. The Appearance data type shall exist only once. It may be sent in either the Advertising or Scan Response data, but not both. adv_itvl Advertising Interval Contains the advInterval value as defined in the Core specification, Volume 6, Part B, Section 4.4.2.2. le_addr LE Bluetooth Device Address Defines the device address of the local device and the address type on the LE transport. le_role LE Role Defines the LE role capabilities of the device. 0x00 Only Peripheral Role supported 0x01 Only Central Role supported 0x02 Peripheral and Central Role supported, Peripheral Role preferred for connection establishment 0x03 Peripheral and Central Role supported, Central Role preferred for connection establishment 0x04 \u2013 0xFF Reserved for future use svc_data_uuid32 Service Data - 32 bit UUID Size: 4 or more octets The first 4 octets contain the 32 bit Service UUID followed by additional service data svc_data_uuid128 Service Data - 128 bit UUID Size: 16 or more octets The first 16 octets contain the 128 bit Service UUID followed by additional service data uri Uniform Resource Identifier (URI) Scheme name string and URI as a UTF-8 string mfg_data Manufacturer Specific data Size: 2 or more octets The first 2 octets contain the Company Identifier Code followed by additional manufacturer specific data","title":"Advertisement Data Fields"},{"location":"network/ble/bletiny/bletiny_advdata/#advertisement-data-fields","text":"This part defines the advertisement data fields used in the bletiny app. For a complete list of all data types and formats used for Extended Inquiry Response (EIR), Advertising Data (AD), and OOB data blocks, refer to the Supplement to the Bluetooth Core Specification, CSSv6, available for download here . Name Definition Details uuids16 16-bit Bluetooth Service UUIDs Indicates the Service UUID list is incomplete i.e. more 16-bit Service UUIDs available. 16 bit UUIDs shall only be used if they are assigned by the Bluetooth SIG. uuids16_is_complete 16-bit Bluetooth Service UUIDs Indicates the Service UUID list is complete. 16 bit UUIDs shall only be used if they are assigned by the Bluetooth SIG. uuids32 32-bit Bluetooth Service UUIDs Indicates the Service UUID list is incomplete i.e. more 32-bit Service UUIDs available. 32 bit UUIDs shall only be used if they are assigned by the Bluetooth SIG. uuids32_is_complete 32-bit Bluetooth Service UUIDs Indicates the Service UUID list is complete. 32 bit UUIDs shall only be used if they are assigned by the Bluetooth SIG. uuids128 Global 128-bit Service UUIDs More 128-bit Service UUIDs available. uuids128_is_complete Global 128-bit Service UUIDs Complete list of 128-bit Service UUIDs tx_pwr_lvl TX Power Level Indicates the transmitted power level of the packet containing the data type. The TX Power Level data type may be used to calculate path loss on a received packet using the following equation: pathloss = Tx Power Level \u2013 RSSI where \u201cRSSI\u201d is the received signal strength, in dBm, of the packet received. device_class Class of device Size: 3 octets slave_itvl_range Slave Connection Interval Range Contains the Peripheral\u2019s preferred connection interval range, for all logical connections. Size: 4 Octets . The first 2 octets defines the minimum value for the connection interval in the following manner: connIntervalmin = Conn_Interval_Min * 1.25 ms Conn_Interval_Min range: 0x0006 to 0x0C80 Value of 0xFFFF indicates no specific minimum. The other 2 octets defines the maximum value for the connection interval in the following manner: connIntervalmax = Conn_Interval_Max * 1.25 ms Conn_Interval_Max range: 0x0006 to 0x0C80 Conn_Interval_Max shall be equal to or greater than the Conn_Interval_Min. Value of 0xFFFF indicates no specific maximum. svc_data_uuid16 Service Data - 16 bit UUID Size: 2 or more octets The first 2 octets contain the 16 bit Service UUID followed by additional service data public_tgt_addr Public Target Address Defines the address of one or more intended recipients of an advertisement when one or more devices were bonded using a public address. This data type shall exist only once. It may be sent in either the Advertising or Scan Response data, but not both. appearance Appearance Defines the external appearance of the device. The Appearance data type shall exist only once. It may be sent in either the Advertising or Scan Response data, but not both. adv_itvl Advertising Interval Contains the advInterval value as defined in the Core specification, Volume 6, Part B, Section 4.4.2.2. le_addr LE Bluetooth Device Address Defines the device address of the local device and the address type on the LE transport. le_role LE Role Defines the LE role capabilities of the device. 0x00 Only Peripheral Role supported 0x01 Only Central Role supported 0x02 Peripheral and Central Role supported, Peripheral Role preferred for connection establishment 0x03 Peripheral and Central Role supported, Central Role preferred for connection establishment 0x04 \u2013 0xFF Reserved for future use svc_data_uuid32 Service Data - 32 bit UUID Size: 4 or more octets The first 4 octets contain the 32 bit Service UUID followed by additional service data svc_data_uuid128 Service Data - 128 bit UUID Size: 16 or more octets The first 16 octets contain the 128 bit Service UUID followed by additional service data uri Uniform Resource Identifier (URI) Scheme name string and URI as a UTF-8 string mfg_data Manufacturer Specific data Size: 2 or more octets The first 2 octets contain the Company Identifier Code followed by additional manufacturer specific data","title":"Advertisement Data Fields"},{"location":"network/ble/ini_stack/ble_add_cpu/","text":"Add cputime The NimBLE stack requires \"cputime\". This is provided by the Mynewt HAL of the same name. The cputime HAL provides a high resolution timer that is used by the nimble stack (as the BLE specification requires a fairly high resolution timer and has fairly tight timing requirements). The cputime HAL allows the user to specify the timer resolution as different applications may require a different resolution. While the Nimble stack does not require a specific timer resolution per se, a resolution that is too large may affect performance and power efficiency. A suggested clock rate for HAL cputime for the nimble stack is 1 MHz, or 1 microsecond per cputime tick. This provides enough resolution for most needs while providing the Nimble stack enough resolution to implement the BLE specification. Add the initialization of cputime to your application: #include \"hal/hal_cputime.h\" int main ( void ) { int rc ; /* Initialize OS */ os_init (); /* Set cputime to count at 1 usec increments */ rc = cputime_init ( 1000000 ); assert ( rc == 0 ); /* Start the OS */ os_start (); /* os start should never return. If it does, this should be an error */ assert ( 0 ); }","title":"Add cputime"},{"location":"network/ble/ini_stack/ble_add_cpu/#add-cputime","text":"The NimBLE stack requires \"cputime\". This is provided by the Mynewt HAL of the same name. The cputime HAL provides a high resolution timer that is used by the nimble stack (as the BLE specification requires a fairly high resolution timer and has fairly tight timing requirements). The cputime HAL allows the user to specify the timer resolution as different applications may require a different resolution. While the Nimble stack does not require a specific timer resolution per se, a resolution that is too large may affect performance and power efficiency. A suggested clock rate for HAL cputime for the nimble stack is 1 MHz, or 1 microsecond per cputime tick. This provides enough resolution for most needs while providing the Nimble stack enough resolution to implement the BLE specification. Add the initialization of cputime to your application: #include \"hal/hal_cputime.h\" int main ( void ) { int rc ; /* Initialize OS */ os_init (); /* Set cputime to count at 1 usec increments */ rc = cputime_init ( 1000000 ); assert ( rc == 0 ); /* Start the OS */ os_start (); /* os start should never return. If it does, this should be an error */ assert ( 0 ); }","title":"Add cputime"},{"location":"network/ble/ini_stack/ble_consolepkg/","text":"Initializing the console package The console is also required by the Nimble stack. The console is currently used for log output so it needs to be initialized. For this example, we are not going to use a console receive callback. All this means is that input from the console will not be accepted by default; the developer will have to install their own handler or use one provided by another package (the shell, for example). Just like statistics, the console is initialized by calling the console initialization function console_init() . #include \"console/console.h\" int main ( void ) { int rc ; /* Initialize OS */ os_init (); /* Set cputime to count at 1 usec increments */ rc = cputime_init ( 1000000 ); assert ( rc == 0 ); /* Create memory pool for Nimble packets and register with Msys */ rc = os_mempool_init ( &g_mbuf_mempool , MBUF_NUM_MBUFS , MBUF_MEMBLOCK_SIZE , &g_mbuf_buffer [ 0 ], \"mbuf_pool\" ); assert ( rc == 0 ); rc = os_mbuf_pool_init ( &g_mbuf_pool , &g_mbuf_mempool , MBUF_MEMBLOCK_SIZE , MBUF_NUM_MBUFS ); assert ( rc == 0 ); rc = os_msys_register ( &g_mbuf_pool ); assert ( rc == 0 ); /* Initialize our device address */ g_dev_addr [ 0 ] = 0x33 ; g_dev_addr [ 1 ] = 0x22 ; g_dev_addr [ 2 ] = 0x11 ; g_dev_addr [ 3 ] = 0xcc ; g_dev_addr [ 4 ] = 0xbb ; g_dev_addr [ 5 ] = 0x0a ; /* Initialize the statistics package */ rc = stats_module_init (); assert ( rc == 0 ); /* Init the console */ rc = console_init ( NULL ); assert ( rc == 0 ); /* Start the OS */ os_start (); /* os start should never return. If it does, this should be an error */ assert ( 0 ); }","title":"Initialize console pkg"},{"location":"network/ble/ini_stack/ble_consolepkg/#initializing-the-console-package","text":"The console is also required by the Nimble stack. The console is currently used for log output so it needs to be initialized. For this example, we are not going to use a console receive callback. All this means is that input from the console will not be accepted by default; the developer will have to install their own handler or use one provided by another package (the shell, for example). Just like statistics, the console is initialized by calling the console initialization function console_init() . #include \"console/console.h\" int main ( void ) { int rc ; /* Initialize OS */ os_init (); /* Set cputime to count at 1 usec increments */ rc = cputime_init ( 1000000 ); assert ( rc == 0 ); /* Create memory pool for Nimble packets and register with Msys */ rc = os_mempool_init ( &g_mbuf_mempool , MBUF_NUM_MBUFS , MBUF_MEMBLOCK_SIZE , &g_mbuf_buffer [ 0 ], \"mbuf_pool\" ); assert ( rc == 0 ); rc = os_mbuf_pool_init ( &g_mbuf_pool , &g_mbuf_mempool , MBUF_MEMBLOCK_SIZE , MBUF_NUM_MBUFS ); assert ( rc == 0 ); rc = os_msys_register ( &g_mbuf_pool ); assert ( rc == 0 ); /* Initialize our device address */ g_dev_addr [ 0 ] = 0x33 ; g_dev_addr [ 1 ] = 0x22 ; g_dev_addr [ 2 ] = 0x11 ; g_dev_addr [ 3 ] = 0xcc ; g_dev_addr [ 4 ] = 0xbb ; g_dev_addr [ 5 ] = 0x0a ; /* Initialize the statistics package */ rc = stats_module_init (); assert ( rc == 0 ); /* Init the console */ rc = console_init ( NULL ); assert ( rc == 0 ); /* Start the OS */ os_start (); /* os start should never return. If it does, this should be an error */ assert ( 0 ); }","title":"Initializing the console package"},{"location":"network/ble/ini_stack/ble_controller_ini/","text":"Initialize the NimBLE controller The NimBLE controller is initialized via a call to ble_ll_init() . This function is declared as follows: int ble_ll_init ( uint8_t ll_task_prio , uint8_t num_acl_pkts , uint16_t acl_pkt_size ) This function's parameters are documented below. Parameter Description prio The priority of the NimBLE controller task. A lower number corresponds to higher priority. num_acl_pkts The maximum number of outstanding data packets that the controller will accept from the host. acl_pkt_size The maximum data packet size that the controller will accept from the host. prio : If you are not familiar with multitasking, preemptive operating systems we highly encourage you to read the Core OS section of Mynewt OS manual. It is up to the application developer to decide the priority of tasks in the system. Note that the lower the priority number the higher the priority in the OS. For example, if a task is running at priority 5 and a task at priority 3 wants to run, the task at priority 5 gets preempted as the other task is a higher proiority. In the example shown below, the LL task is configured to have the highest priority (priority 0). We recommend making the BLE LL task the highest priority task in your application as it has fairly rigorous timing requirements and allowing other tasks to preempt the LL task could cause undesirable behavior. Note that we do not force this to be the case as an application may require a task to be even higher priority than the LL task. Just be warned: a task higher in priority than the LL task should not perform actions that take too long; even a few milliseconds could cause undesirable behavior. num_acl_pkts and acl_pkt_size : These two parameters are used to limit the amount of data the host tries to send through the controller. NimBLE uses the msys facility for allocating data packets, so the product of these arguments must not be larger than the total amount of memory allocated for msys. The below example uses some values that are reasonable for most uses. #include \"controller/ble_ll.h\" int main ( void ) { int rc ; struct ble_hs_cfg cfg ; /* Initialize OS */ os_init (); /* Set cputime to count at 1 usec increments */ rc = cputime_init ( 1000000 ); assert ( rc == 0 ); /* Create memory pool for NimBLE packets and register with Msys */ rc = os_mempool_init ( &g_mbuf_mempool , MBUF_NUM_MBUFS , MBUF_MEMBLOCK_SIZE , &g_mbuf_buffer [ 0 ], \"mbuf_pool\" ); assert ( rc == 0 ); rc = os_mbuf_pool_init ( &g_mbuf_pool , &g_mbuf_mempool , MBUF_MEMBLOCK_SIZE , MBUF_NUM_MBUFS ); assert ( rc == 0 ); rc = os_msys_register ( &g_mbuf_pool ); assert ( rc == 0 ); /* Initialize our device address */ g_dev_addr [ 0 ] = 0x33 ; g_dev_addr [ 1 ] = 0x22 ; g_dev_addr [ 2 ] = 0x11 ; g_dev_addr [ 3 ] = 0xcc ; g_dev_addr [ 4 ] = 0xbb ; g_dev_addr [ 5 ] = 0x0a ; /* Initialize the statistics package */ rc = stats_module_init (); assert ( rc == 0 ); /* Initialize the BLE LL */ rc = ble_ll_init ( 0 , 7 , 260 ); assert ( rc == 0 ); /* Start the OS */ os_start (); /* os start should never return. If it does, this should be an error */ assert ( 0 ); }","title":"Initialize controller"},{"location":"network/ble/ini_stack/ble_controller_ini/#initialize-the-nimble-controller","text":"The NimBLE controller is initialized via a call to ble_ll_init() . This function is declared as follows: int ble_ll_init ( uint8_t ll_task_prio , uint8_t num_acl_pkts , uint16_t acl_pkt_size ) This function's parameters are documented below. Parameter Description prio The priority of the NimBLE controller task. A lower number corresponds to higher priority. num_acl_pkts The maximum number of outstanding data packets that the controller will accept from the host. acl_pkt_size The maximum data packet size that the controller will accept from the host. prio : If you are not familiar with multitasking, preemptive operating systems we highly encourage you to read the Core OS section of Mynewt OS manual. It is up to the application developer to decide the priority of tasks in the system. Note that the lower the priority number the higher the priority in the OS. For example, if a task is running at priority 5 and a task at priority 3 wants to run, the task at priority 5 gets preempted as the other task is a higher proiority. In the example shown below, the LL task is configured to have the highest priority (priority 0). We recommend making the BLE LL task the highest priority task in your application as it has fairly rigorous timing requirements and allowing other tasks to preempt the LL task could cause undesirable behavior. Note that we do not force this to be the case as an application may require a task to be even higher priority than the LL task. Just be warned: a task higher in priority than the LL task should not perform actions that take too long; even a few milliseconds could cause undesirable behavior. num_acl_pkts and acl_pkt_size : These two parameters are used to limit the amount of data the host tries to send through the controller. NimBLE uses the msys facility for allocating data packets, so the product of these arguments must not be larger than the total amount of memory allocated for msys. The below example uses some values that are reasonable for most uses. #include \"controller/ble_ll.h\" int main ( void ) { int rc ; struct ble_hs_cfg cfg ; /* Initialize OS */ os_init (); /* Set cputime to count at 1 usec increments */ rc = cputime_init ( 1000000 ); assert ( rc == 0 ); /* Create memory pool for NimBLE packets and register with Msys */ rc = os_mempool_init ( &g_mbuf_mempool , MBUF_NUM_MBUFS , MBUF_MEMBLOCK_SIZE , &g_mbuf_buffer [ 0 ], \"mbuf_pool\" ); assert ( rc == 0 ); rc = os_mbuf_pool_init ( &g_mbuf_pool , &g_mbuf_mempool , MBUF_MEMBLOCK_SIZE , MBUF_NUM_MBUFS ); assert ( rc == 0 ); rc = os_msys_register ( &g_mbuf_pool ); assert ( rc == 0 ); /* Initialize our device address */ g_dev_addr [ 0 ] = 0x33 ; g_dev_addr [ 1 ] = 0x22 ; g_dev_addr [ 2 ] = 0x11 ; g_dev_addr [ 3 ] = 0xcc ; g_dev_addr [ 4 ] = 0xbb ; g_dev_addr [ 5 ] = 0x0a ; /* Initialize the statistics package */ rc = stats_module_init (); assert ( rc == 0 ); /* Initialize the BLE LL */ rc = ble_ll_init ( 0 , 7 , 260 ); assert ( rc == 0 ); /* Start the OS */ os_start (); /* os start should never return. If it does, this should be an error */ assert ( 0 ); }","title":"Initialize the NimBLE controller"},{"location":"network/ble/ini_stack/ble_devadd/","text":"Initialize the Device Address The BLE specification requires that devices have an address (called a device address). This address can be either a public device address or a random device address. The current Nimble stack implementation requires that these addresses be defined somewhere in the application; they are not defined within the Nimble stack itself. This was done so that the entire application could have access to these addresses. We expect that we will move these addresses into the Nimble stack in a future release. The two variables that must be defined are named g_dev_addr (public device address) and g_random_addr (static random address). The device address must be initialized prior to initializing the Nimble stack. The random address does not have to be initialized ahead of time as it is possible to set the random address in the Nimble controller when it is running. In this example, we only initialize the device address. The company OUI in this example is 0a:bb:cc; the unique portion is 11:22:33 for a device address equal to 0a:bb:cc:11:22:33. Note that we store the address in little endian order as BLE expects the OUI to be in the most significant bytes. /* Our global device address (public) */ uint8_t g_dev_addr [ BLE_DEV_ADDR_LEN ]; /* Our random address (static) */ uint8_t g_random_addr [ BLE_DEV_ADDR_LEN ]; int main ( void ) { int rc ; /* Initialize OS */ os_init (); /* Set cputime to count at 1 usec increments */ rc = cputime_init ( 1000000 ); assert ( rc == 0 ); /* Create memory pool for Nimble packets and register with Msys */ rc = os_mempool_init ( &g_mbuf_mempool , MBUF_NUM_MBUFS , MBUF_MEMBLOCK_SIZE , &g_mbuf_buffer [ 0 ], \"mbuf_pool\" ); assert ( rc == 0 ); rc = os_mbuf_pool_init ( &g_mbuf_pool , &g_mbuf_mempool , MBUF_MEMBLOCK_SIZE , MBUF_NUM_MBUFS ); assert ( rc == 0 ); rc = os_msys_register ( &g_mbuf_pool ); assert ( rc == 0 ); /* Initialize our device address */ g_dev_addr [ 0 ] = 0x33 ; g_dev_addr [ 1 ] = 0x22 ; g_dev_addr [ 2 ] = 0x11 ; g_dev_addr [ 3 ] = 0xcc ; g_dev_addr [ 4 ] = 0xbb ; g_dev_addr [ 5 ] = 0x0a ; /* Start the OS */ os_start (); /* os start should never return. If it does, this should be an error */ assert ( 0 ); }","title":"Initialize device addr"},{"location":"network/ble/ini_stack/ble_devadd/#initialize-the-device-address","text":"The BLE specification requires that devices have an address (called a device address). This address can be either a public device address or a random device address. The current Nimble stack implementation requires that these addresses be defined somewhere in the application; they are not defined within the Nimble stack itself. This was done so that the entire application could have access to these addresses. We expect that we will move these addresses into the Nimble stack in a future release. The two variables that must be defined are named g_dev_addr (public device address) and g_random_addr (static random address). The device address must be initialized prior to initializing the Nimble stack. The random address does not have to be initialized ahead of time as it is possible to set the random address in the Nimble controller when it is running. In this example, we only initialize the device address. The company OUI in this example is 0a:bb:cc; the unique portion is 11:22:33 for a device address equal to 0a:bb:cc:11:22:33. Note that we store the address in little endian order as BLE expects the OUI to be in the most significant bytes. /* Our global device address (public) */ uint8_t g_dev_addr [ BLE_DEV_ADDR_LEN ]; /* Our random address (static) */ uint8_t g_random_addr [ BLE_DEV_ADDR_LEN ]; int main ( void ) { int rc ; /* Initialize OS */ os_init (); /* Set cputime to count at 1 usec increments */ rc = cputime_init ( 1000000 ); assert ( rc == 0 ); /* Create memory pool for Nimble packets and register with Msys */ rc = os_mempool_init ( &g_mbuf_mempool , MBUF_NUM_MBUFS , MBUF_MEMBLOCK_SIZE , &g_mbuf_buffer [ 0 ], \"mbuf_pool\" ); assert ( rc == 0 ); rc = os_mbuf_pool_init ( &g_mbuf_pool , &g_mbuf_mempool , MBUF_MEMBLOCK_SIZE , MBUF_NUM_MBUFS ); assert ( rc == 0 ); rc = os_msys_register ( &g_mbuf_pool ); assert ( rc == 0 ); /* Initialize our device address */ g_dev_addr [ 0 ] = 0x33 ; g_dev_addr [ 1 ] = 0x22 ; g_dev_addr [ 2 ] = 0x11 ; g_dev_addr [ 3 ] = 0xcc ; g_dev_addr [ 4 ] = 0xbb ; g_dev_addr [ 5 ] = 0x0a ; /* Start the OS */ os_start (); /* os start should never return. If it does, this should be an error */ assert ( 0 ); }","title":"Initialize the Device Address"},{"location":"network/ble/ini_stack/ble_host_ini/","text":"Initialize the NimBLE host The Nimble host is initialized via a call to ble_hs_init() . This function is declared as follows: int ble_hs_init ( struct os_eventq *parent_evq , struct ble_hs_cfg *cfg ) The parameters are documented below. Parameter Description parent_evq The OS event queue that the host should use to schedule host-related operations. cfg A pointer to the desired host configuration, or NULL if you want to use the default settings. parent_evq : This is the event queue associated with the host parent task . cfg : As mentioned above, passing a cfg value of NULL will initialize the Nimble host with the default configuration. This is convenient while familiarizing yourself with the Nimble stack, but ultimately you will probably want to use a custom configuration. For more information on configuring the host, see the Nimble Configuration Guide (TBD). Continuing with our running example, we now add Nimble host initialization to the main() function. This application uses the default host configuration, so it specifies NULL as the second argument to ble_hs_init() . #include \"host/ble_hs.h\" int main ( void ) { int rc ; /* Initialize OS */ os_init (); /* Set cputime to count at 1 usec increments */ rc = cputime_init ( 1000000 ); assert ( rc == 0 ); /* Create memory pool for Nimble packets and register with Msys */ rc = os_mempool_init ( &g_mbuf_mempool , MBUF_NUM_MBUFS , MBUF_MEMBLOCK_SIZE , &g_mbuf_buffer [ 0 ], \"mbuf_pool\" ); assert ( rc == 0 ); rc = os_mbuf_pool_init ( &g_mbuf_pool , &g_mbuf_mempool , MBUF_MEMBLOCK_SIZE , MBUF_NUM_MBUFS ); assert ( rc == 0 ); rc = os_msys_register ( &g_mbuf_pool ); assert ( rc == 0 ); /* Initialize our device address */ g_dev_addr [ 0 ] = 0x33 ; g_dev_addr [ 1 ] = 0x22 ; g_dev_addr [ 2 ] = 0x11 ; g_dev_addr [ 3 ] = 0xcc ; g_dev_addr [ 4 ] = 0xbb ; g_dev_addr [ 5 ] = 0x0a ; /* Initialize the statistics package */ rc = stats_module_init (); assert ( rc == 0 ); /* Initialize the BLE LL */ rc = ble_ll_init ( 0 , 7 , 260 ); assert ( rc == 0 ); /* Initialize the application task. */ os_eventq_init ( &app_evq ); os_task_init ( &app_task , \"app\" , app_task_handler , NULL , 1 , OS_WAIT_FOREVER , app_stack , APP_STACK_SIZE ); /* Initialize the BLE host. */ rc = ble_hs_init ( &app_evq , NULL ); assert ( rc == 0 ); /* Start the OS */ os_start (); /* os start should never return. If it does, this should be an error */ assert ( 0 ); }","title":"Initialize host"},{"location":"network/ble/ini_stack/ble_host_ini/#initialize-the-nimble-host","text":"The Nimble host is initialized via a call to ble_hs_init() . This function is declared as follows: int ble_hs_init ( struct os_eventq *parent_evq , struct ble_hs_cfg *cfg ) The parameters are documented below. Parameter Description parent_evq The OS event queue that the host should use to schedule host-related operations. cfg A pointer to the desired host configuration, or NULL if you want to use the default settings. parent_evq : This is the event queue associated with the host parent task . cfg : As mentioned above, passing a cfg value of NULL will initialize the Nimble host with the default configuration. This is convenient while familiarizing yourself with the Nimble stack, but ultimately you will probably want to use a custom configuration. For more information on configuring the host, see the Nimble Configuration Guide (TBD). Continuing with our running example, we now add Nimble host initialization to the main() function. This application uses the default host configuration, so it specifies NULL as the second argument to ble_hs_init() . #include \"host/ble_hs.h\" int main ( void ) { int rc ; /* Initialize OS */ os_init (); /* Set cputime to count at 1 usec increments */ rc = cputime_init ( 1000000 ); assert ( rc == 0 ); /* Create memory pool for Nimble packets and register with Msys */ rc = os_mempool_init ( &g_mbuf_mempool , MBUF_NUM_MBUFS , MBUF_MEMBLOCK_SIZE , &g_mbuf_buffer [ 0 ], \"mbuf_pool\" ); assert ( rc == 0 ); rc = os_mbuf_pool_init ( &g_mbuf_pool , &g_mbuf_mempool , MBUF_MEMBLOCK_SIZE , MBUF_NUM_MBUFS ); assert ( rc == 0 ); rc = os_msys_register ( &g_mbuf_pool ); assert ( rc == 0 ); /* Initialize our device address */ g_dev_addr [ 0 ] = 0x33 ; g_dev_addr [ 1 ] = 0x22 ; g_dev_addr [ 2 ] = 0x11 ; g_dev_addr [ 3 ] = 0xcc ; g_dev_addr [ 4 ] = 0xbb ; g_dev_addr [ 5 ] = 0x0a ; /* Initialize the statistics package */ rc = stats_module_init (); assert ( rc == 0 ); /* Initialize the BLE LL */ rc = ble_ll_init ( 0 , 7 , 260 ); assert ( rc == 0 ); /* Initialize the application task. */ os_eventq_init ( &app_evq ); os_task_init ( &app_task , \"app\" , app_task_handler , NULL , 1 , OS_WAIT_FOREVER , app_stack , APP_STACK_SIZE ); /* Initialize the BLE host. */ rc = ble_hs_init ( &app_evq , NULL ); assert ( rc == 0 ); /* Start the OS */ os_start (); /* os start should never return. If it does, this should be an error */ assert ( 0 ); }","title":"Initialize the NimBLE host"},{"location":"network/ble/ini_stack/ble_ini_intro/","text":"Nimble stack initialization We are now going to explain how to set up your application to initialize the nimble stack and to get the basic stack, and its required modules, initialized and up and running. Note that the code shown here is an example of what is required for nimble stack operation; it is not intended to dictate to the developer exactly how to organize and set up your code. For example, the code sample shows modification of main.c in the application /src folder. The developer has the flexibility to organize the code as they see fit so this code does not need to reside in /src/main.c or in the main() function itself. The only possible issue is the order of some of the initializations. Where this order is important it is indicated in the sections covering stack initialization. A note about the code samples: the main() function in each code sample builds upon the previous example. However, code outside of main() shows only what we add for each step. The last code sample shows the entire main.c that we created. Let's start with a very basic main() function (shown below). This main() function is identical to the minimal version used in the Set up application introductory page. In this main() all we are doing is initializing the Mynewt OS and starting it. #include <assert.h> #include \"os/os.h\" int main ( void ) { /* Initialize OS */ os_init (); /* Start the OS */ os_start (); /* os start should never return. If it does, this should be an error */ assert ( 0 ); } The Nimble stack requires a number of packages to be initialized prior to being started. We are going to add these one by one to the application and describe each.","title":"toc"},{"location":"network/ble/ini_stack/ble_ini_intro/#nimble-stack-initialization","text":"We are now going to explain how to set up your application to initialize the nimble stack and to get the basic stack, and its required modules, initialized and up and running. Note that the code shown here is an example of what is required for nimble stack operation; it is not intended to dictate to the developer exactly how to organize and set up your code. For example, the code sample shows modification of main.c in the application /src folder. The developer has the flexibility to organize the code as they see fit so this code does not need to reside in /src/main.c or in the main() function itself. The only possible issue is the order of some of the initializations. Where this order is important it is indicated in the sections covering stack initialization. A note about the code samples: the main() function in each code sample builds upon the previous example. However, code outside of main() shows only what we add for each step. The last code sample shows the entire main.c that we created. Let's start with a very basic main() function (shown below). This main() function is identical to the minimal version used in the Set up application introductory page. In this main() all we are doing is initializing the Mynewt OS and starting it. #include <assert.h> #include \"os/os.h\" int main ( void ) { /* Initialize OS */ os_init (); /* Start the OS */ os_start (); /* os start should never return. If it does, this should be an error */ assert ( 0 ); } The Nimble stack requires a number of packages to be initialized prior to being started. We are going to add these one by one to the application and describe each.","title":"Nimble stack initialization"},{"location":"network/ble/ini_stack/ble_mempool/","text":"Create the System Memory Buffer Pool The Nimble stack allocates packet buffers (called mbufs) from the system memory buffer pool (msys). The system memory buffer pool and mbufs are described in the OS manual; we suggest reading that section in order to become familiar with mbufs if you are not already familiar with them. Note that the application itself (the unique application code that you are writing) does not need to use mbufs and none of the BLE host API exposed to the application developer uses them. However, the Nimble stack does require the existence of the system memory pool. Creating the memory pool and registering it with the system memory buffer pool can be a bit tricky the first time. However, using the template provided below it should be much easier. The header file /net/nimble/include/nimble/ble.h, which should be included in main.c, contains some MBUF macros that you will need to create the memory pool used by msys. The macro BLE_MBUF_PAYLOAD_SIZE defines the maximum amount of user payload, plus overhead, that a link layer BLE PDU can contain. The macro BLE_MBUF_MEMBLOCK_OVERHEAD is the amount of overhead required by the Nimble stack in each memory block used by the mbuf pool. The macro MBUF_NUM_MBUFS defines the number of mbufs in the mbuf pool and is defined locally. The user must determine, based on application requirements and platform memory size, how many mbufs are required. For example, if your application expects to have many simultaneous connections you may want to increase the size of the mbuf pool. In the example below, we assume you are only using a small number of active connections (2 to 3). A note about the size of the mbufs and BLE_MBUF_PAYLOAD_SIZE . Msys allows for multiple mbuf pools of various size. Currently, the Nimble stack requires that msys has an mbuf pool registered that can accommodate the maximum size BLE LL PDU. Thus, we only show the creation of one mbuf pool of maximum size mbufs which gets registered to the system mbuf memory pool. We plan on modifying the Nimble stack so that smaller mbufs can be used (to conserve memory) but at this point in time you cannot modify BLE_MBUF_PAYLOAD_SIZE . Furthermore, you cannot add a mbuf pool of smaller size elements to the msys pool as the msys code might then allocate a mbuf that is too small for the nimble stack. /* Create a mbuf pool of BLE mbufs */ #define MBUF_NUM_MBUFS (8) #define MBUF_BUF_SIZE OS_ALIGN(BLE_MBUF_PAYLOAD_SIZE, 4) #define MBUF_MEMBLOCK_SIZE (MBUF_BUF_SIZE + BLE_MBUF_MEMBLOCK_OVERHEAD) #define MBUF_MEMPOOL_SIZE OS_MEMPOOL_SIZE(MBUF_NUM_MBUFS, MBUF_MEMBLOCK_SIZE) struct os_mbuf_pool g_mbuf_pool ; struct os_mempool g_mbuf_mempool ; os_membuf_t g_mbuf_buffer [ MBUF_MEMPOOL_SIZE ]; int main ( void ) { int rc ; /* Initialize OS */ os_init (); /* Set cputime to count at 1 usec increments */ rc = cputime_init ( 1000000 ); assert ( rc == 0 ); /* Create memory pool for Nimble packets and register with Msys */ rc = os_mempool_init ( &g_mbuf_mempool , MBUF_NUM_MBUFS , MBUF_MEMBLOCK_SIZE , &g_mbuf_buffer [ 0 ], \"mbuf_pool\" ); assert ( rc == 0 ); rc = os_mbuf_pool_init ( &g_mbuf_pool , &g_mbuf_mempool , MBUF_MEMBLOCK_SIZE , MBUF_NUM_MBUFS ); assert ( rc == 0 ); rc = os_msys_register ( &g_mbuf_pool ); assert ( rc == 0 ); /* Start the OS */ os_start (); /* os start should never return. If it does, this should be an error */ assert ( 0 ); }","title":"Create mem pool"},{"location":"network/ble/ini_stack/ble_mempool/#create-the-system-memory-buffer-pool","text":"The Nimble stack allocates packet buffers (called mbufs) from the system memory buffer pool (msys). The system memory buffer pool and mbufs are described in the OS manual; we suggest reading that section in order to become familiar with mbufs if you are not already familiar with them. Note that the application itself (the unique application code that you are writing) does not need to use mbufs and none of the BLE host API exposed to the application developer uses them. However, the Nimble stack does require the existence of the system memory pool. Creating the memory pool and registering it with the system memory buffer pool can be a bit tricky the first time. However, using the template provided below it should be much easier. The header file /net/nimble/include/nimble/ble.h, which should be included in main.c, contains some MBUF macros that you will need to create the memory pool used by msys. The macro BLE_MBUF_PAYLOAD_SIZE defines the maximum amount of user payload, plus overhead, that a link layer BLE PDU can contain. The macro BLE_MBUF_MEMBLOCK_OVERHEAD is the amount of overhead required by the Nimble stack in each memory block used by the mbuf pool. The macro MBUF_NUM_MBUFS defines the number of mbufs in the mbuf pool and is defined locally. The user must determine, based on application requirements and platform memory size, how many mbufs are required. For example, if your application expects to have many simultaneous connections you may want to increase the size of the mbuf pool. In the example below, we assume you are only using a small number of active connections (2 to 3). A note about the size of the mbufs and BLE_MBUF_PAYLOAD_SIZE . Msys allows for multiple mbuf pools of various size. Currently, the Nimble stack requires that msys has an mbuf pool registered that can accommodate the maximum size BLE LL PDU. Thus, we only show the creation of one mbuf pool of maximum size mbufs which gets registered to the system mbuf memory pool. We plan on modifying the Nimble stack so that smaller mbufs can be used (to conserve memory) but at this point in time you cannot modify BLE_MBUF_PAYLOAD_SIZE . Furthermore, you cannot add a mbuf pool of smaller size elements to the msys pool as the msys code might then allocate a mbuf that is too small for the nimble stack. /* Create a mbuf pool of BLE mbufs */ #define MBUF_NUM_MBUFS (8) #define MBUF_BUF_SIZE OS_ALIGN(BLE_MBUF_PAYLOAD_SIZE, 4) #define MBUF_MEMBLOCK_SIZE (MBUF_BUF_SIZE + BLE_MBUF_MEMBLOCK_OVERHEAD) #define MBUF_MEMPOOL_SIZE OS_MEMPOOL_SIZE(MBUF_NUM_MBUFS, MBUF_MEMBLOCK_SIZE) struct os_mbuf_pool g_mbuf_pool ; struct os_mempool g_mbuf_mempool ; os_membuf_t g_mbuf_buffer [ MBUF_MEMPOOL_SIZE ]; int main ( void ) { int rc ; /* Initialize OS */ os_init (); /* Set cputime to count at 1 usec increments */ rc = cputime_init ( 1000000 ); assert ( rc == 0 ); /* Create memory pool for Nimble packets and register with Msys */ rc = os_mempool_init ( &g_mbuf_mempool , MBUF_NUM_MBUFS , MBUF_MEMBLOCK_SIZE , &g_mbuf_buffer [ 0 ], \"mbuf_pool\" ); assert ( rc == 0 ); rc = os_mbuf_pool_init ( &g_mbuf_pool , &g_mbuf_mempool , MBUF_MEMBLOCK_SIZE , MBUF_NUM_MBUFS ); assert ( rc == 0 ); rc = os_msys_register ( &g_mbuf_pool ); assert ( rc == 0 ); /* Start the OS */ os_start (); /* os start should never return. If it does, this should be an error */ assert ( 0 ); }","title":"Create the System Memory Buffer Pool"},{"location":"network/ble/ini_stack/ble_parent_ini/","text":"Create the host parent task The NimBLE stack requires an application task to function. One application task in particular is designated as the host parent task . In addition to application-specific work, the host parent task does work for NimBLE by processing events generated by the host. The process of creating an OS task is described in the Add Task tutorial . Priority: It is up to you which priority to use for the host parent task. Unlike the controller, the host does not have any strict timing requirements, so the priority should be based on the application's needs. In the below example, we use a priority of 1 . Stack size: The host parent task's stack needs to be sufficiently large to handle BLE operations. This depends on the set of BLE features your application uses, and on the specifics application callbacks that the stack is configured to use. A safe value is to use here is 300 words ; that is the value used in the below example. The parent task must do two things: Call ble_hs_start() before starting its task loop. Handle OS_EVENT_T_TIMER events within its task loop. The ble_hs_start() function is declared as follows: int ble_hs_start ( void ) The ble_hs_start() function causes the host to send a sequence of HCI commands to the controller. This sequence of commands is necessary for the host and controller to remain in sync. We add an application task to our example below. #include \"os/os.h\" /** Application task. */ static struct os_task app_task ; /** Application task event queue. */ static struct os_eventq app_evq ; /** Application task stack. */ #define APP_STACK_SIZE (OS_STACK_ALIGN(300)) static os_stack_t app_stack [ APP_STACK_SIZE ]; /** * Application task. */ static void app_task_handler ( void *arg ) { struct os_callout_func *cf ; struct os_event *ev ; int rc ; rc = ble_hs_start (); assert ( rc == 0 ); while ( 1 ) { ev = os_eventq_get ( &app_evq ); switch ( ev->ev_type ) { case OS_EVENT_T_TIMER : cf = ( struct os_callout_func * ) ev ; assert ( cf->cf_func ); cf->cf_func ( cf->cf_arg ); break ; default : assert ( 0 ); break ; } } } int main ( void ) { int rc ; /* Initialize OS */ os_init (); /* Set cputime to count at 1 usec increments */ rc = cputime_init ( 1000000 ); assert ( rc == 0 ); /* Create memory pool for Nimble packets and register with Msys */ rc = os_mempool_init ( &g_mbuf_mempool , MBUF_NUM_MBUFS , MBUF_MEMBLOCK_SIZE , &g_mbuf_buffer [ 0 ], \"mbuf_pool\" ); assert ( rc == 0 ); rc = os_mbuf_pool_init ( &g_mbuf_pool , &g_mbuf_mempool , MBUF_MEMBLOCK_SIZE , MBUF_NUM_MBUFS ); assert ( rc == 0 ); rc = os_msys_register ( &g_mbuf_pool ); assert ( rc == 0 ); /* Initialize our device address */ g_dev_addr [ 0 ] = 0x33 ; g_dev_addr [ 1 ] = 0x22 ; g_dev_addr [ 2 ] = 0x11 ; g_dev_addr [ 3 ] = 0xcc ; g_dev_addr [ 4 ] = 0xbb ; g_dev_addr [ 5 ] = 0x0a ; /* Initialize the statistics package */ rc = stats_module_init (); assert ( rc == 0 ); /* Initialize the BLE LL */ rc = ble_ll_init ( 0 , 7 , 260 ); assert ( rc == 0 ); /* Initialize the application task. */ os_eventq_init ( &app_evq ); os_task_init ( &app_task , \"app\" , app_task_handler , NULL , 1 , OS_WAIT_FOREVER , app_stack , APP_STACK_SIZE ); /* Start the OS */ os_start (); /* os start should never return. If it does, this should be an error */ assert ( 0 ); }","title":"Initialize parent task"},{"location":"network/ble/ini_stack/ble_parent_ini/#create-the-host-parent-task","text":"The NimBLE stack requires an application task to function. One application task in particular is designated as the host parent task . In addition to application-specific work, the host parent task does work for NimBLE by processing events generated by the host. The process of creating an OS task is described in the Add Task tutorial . Priority: It is up to you which priority to use for the host parent task. Unlike the controller, the host does not have any strict timing requirements, so the priority should be based on the application's needs. In the below example, we use a priority of 1 . Stack size: The host parent task's stack needs to be sufficiently large to handle BLE operations. This depends on the set of BLE features your application uses, and on the specifics application callbacks that the stack is configured to use. A safe value is to use here is 300 words ; that is the value used in the below example. The parent task must do two things: Call ble_hs_start() before starting its task loop. Handle OS_EVENT_T_TIMER events within its task loop. The ble_hs_start() function is declared as follows: int ble_hs_start ( void ) The ble_hs_start() function causes the host to send a sequence of HCI commands to the controller. This sequence of commands is necessary for the host and controller to remain in sync. We add an application task to our example below. #include \"os/os.h\" /** Application task. */ static struct os_task app_task ; /** Application task event queue. */ static struct os_eventq app_evq ; /** Application task stack. */ #define APP_STACK_SIZE (OS_STACK_ALIGN(300)) static os_stack_t app_stack [ APP_STACK_SIZE ]; /** * Application task. */ static void app_task_handler ( void *arg ) { struct os_callout_func *cf ; struct os_event *ev ; int rc ; rc = ble_hs_start (); assert ( rc == 0 ); while ( 1 ) { ev = os_eventq_get ( &app_evq ); switch ( ev->ev_type ) { case OS_EVENT_T_TIMER : cf = ( struct os_callout_func * ) ev ; assert ( cf->cf_func ); cf->cf_func ( cf->cf_arg ); break ; default : assert ( 0 ); break ; } } } int main ( void ) { int rc ; /* Initialize OS */ os_init (); /* Set cputime to count at 1 usec increments */ rc = cputime_init ( 1000000 ); assert ( rc == 0 ); /* Create memory pool for Nimble packets and register with Msys */ rc = os_mempool_init ( &g_mbuf_mempool , MBUF_NUM_MBUFS , MBUF_MEMBLOCK_SIZE , &g_mbuf_buffer [ 0 ], \"mbuf_pool\" ); assert ( rc == 0 ); rc = os_mbuf_pool_init ( &g_mbuf_pool , &g_mbuf_mempool , MBUF_MEMBLOCK_SIZE , MBUF_NUM_MBUFS ); assert ( rc == 0 ); rc = os_msys_register ( &g_mbuf_pool ); assert ( rc == 0 ); /* Initialize our device address */ g_dev_addr [ 0 ] = 0x33 ; g_dev_addr [ 1 ] = 0x22 ; g_dev_addr [ 2 ] = 0x11 ; g_dev_addr [ 3 ] = 0xcc ; g_dev_addr [ 4 ] = 0xbb ; g_dev_addr [ 5 ] = 0x0a ; /* Initialize the statistics package */ rc = stats_module_init (); assert ( rc == 0 ); /* Initialize the BLE LL */ rc = ble_ll_init ( 0 , 7 , 260 ); assert ( rc == 0 ); /* Initialize the application task. */ os_eventq_init ( &app_evq ); os_task_init ( &app_task , \"app\" , app_task_handler , NULL , 1 , OS_WAIT_FOREVER , app_stack , APP_STACK_SIZE ); /* Start the OS */ os_start (); /* os start should never return. If it does, this should be an error */ assert ( 0 ); }","title":"Create the host parent task"},{"location":"network/ble/ini_stack/ble_statpkg/","text":"Initialize the statistics package The NimBLE stack uses the statistics package and this must be initialized prior to initializing the Nimble stack. Initializing the statistics package is quite simple; all you need to do is call the initialization function stats_module_init() . #include \"stats/stats.h\" int main ( void ) { int rc ; /* Initialize OS */ os_init (); /* Set cputime to count at 1 usec increments */ rc = cputime_init ( 1000000 ); assert ( rc == 0 ); /* Create memory pool for Nimble packets and register with Msys */ rc = os_mempool_init ( &g_mbuf_mempool , MBUF_NUM_MBUFS , MBUF_MEMBLOCK_SIZE , &g_mbuf_buffer [ 0 ], \"mbuf_pool\" ); assert ( rc == 0 ); rc = os_mbuf_pool_init ( &g_mbuf_pool , &g_mbuf_mempool , MBUF_MEMBLOCK_SIZE , MBUF_NUM_MBUFS ); assert ( rc == 0 ); rc = os_msys_register ( &g_mbuf_pool ); assert ( rc == 0 ); /* Initialize our device address */ g_dev_addr [ 0 ] = 0x33 ; g_dev_addr [ 1 ] = 0x22 ; g_dev_addr [ 2 ] = 0x11 ; g_dev_addr [ 3 ] = 0xcc ; g_dev_addr [ 4 ] = 0xbb ; g_dev_addr [ 5 ] = 0x0a ; /* Initialize the statistics package */ rc = stats_module_init (); assert ( rc == 0 ); /* Start the OS */ os_start (); /* os start should never return. If it does, this should be an error */ assert ( 0 ); }","title":"Initialize stats pkg"},{"location":"network/ble/ini_stack/ble_statpkg/#initialize-the-statistics-package","text":"The NimBLE stack uses the statistics package and this must be initialized prior to initializing the Nimble stack. Initializing the statistics package is quite simple; all you need to do is call the initialization function stats_module_init() . #include \"stats/stats.h\" int main ( void ) { int rc ; /* Initialize OS */ os_init (); /* Set cputime to count at 1 usec increments */ rc = cputime_init ( 1000000 ); assert ( rc == 0 ); /* Create memory pool for Nimble packets and register with Msys */ rc = os_mempool_init ( &g_mbuf_mempool , MBUF_NUM_MBUFS , MBUF_MEMBLOCK_SIZE , &g_mbuf_buffer [ 0 ], \"mbuf_pool\" ); assert ( rc == 0 ); rc = os_mbuf_pool_init ( &g_mbuf_pool , &g_mbuf_mempool , MBUF_MEMBLOCK_SIZE , MBUF_NUM_MBUFS ); assert ( rc == 0 ); rc = os_msys_register ( &g_mbuf_pool ); assert ( rc == 0 ); /* Initialize our device address */ g_dev_addr [ 0 ] = 0x33 ; g_dev_addr [ 1 ] = 0x22 ; g_dev_addr [ 2 ] = 0x11 ; g_dev_addr [ 3 ] = 0xcc ; g_dev_addr [ 4 ] = 0xbb ; g_dev_addr [ 5 ] = 0x0a ; /* Initialize the statistics package */ rc = stats_module_init (); assert ( rc == 0 ); /* Start the OS */ os_start (); /* os start should never return. If it does, this should be an error */ assert ( 0 ); }","title":"Initialize the statistics package"},{"location":"news/article1/","text":"","title":"Article1"},{"location":"newt/newt_intro/","text":"Newt Tool Introduction Newt is a smart build and package management system for embedded contexts. It is a single tool that accomplishes both the following goals: source package management build, debug and install. Rationale In order for the Mynewt operating system to work well for constrained environments across the many different types of microcontroller applications (from doorbells to medical devices to power grids), a system is needed that lets you select which packages to install and which packages to build. The build systems for embedded devices are often fairly complicated and not well served for this purpose. For example, autoconf is designed for detecting system compatibility issues but not well suited when it comes to tasks like: Building for multiple targets Deciding what to build in and what not to build in Managing dependencies between components Fortunately, solutions addressing these very issues can be found in source package management systems in higher level languages such as Javascript (Node), Go, PHP and Ruby. We decided to fuse their source management systems with a make system built for embedded systems and create Newt. Build System A good build system must allow the user to take a few common steps while developing embedded applications: Generate full flash images Download debug images to a target board using a debugger Conditionally compile libraries & code based upon build settings Newt can read a directory tree, build a dependency tree, and emit the right build artifacts. An example newt source tree is in incubator-mynewt-blinky/develop: $ tree -L 3 . \u251c\u2500\u2500 DISCLAIMER \u251c\u2500\u2500 LICENSE \u251c\u2500\u2500 NOTICE \u251c\u2500\u2500 README.md \u251c\u2500\u2500 apps \u2502 \u2514\u2500\u2500 blinky \u2502 \u251c\u2500\u2500 pkg.yml \u2502 \u2514\u2500\u2500 src \u251c\u2500\u2500 project.yml \u2514\u2500\u2500 targets \u251c\u2500\u2500 my_blinky_sim \u2502 \u251c\u2500\u2500 pkg.yml \u2502 \u2514\u2500\u2500 target.yml \u2514\u2500\u2500 unittest \u251c\u2500\u2500 pkg.yml \u2514\u2500\u2500 target.yml 6 directories, 10 files When Newt sees a directory tree that contains a \"project.yml\" file, it is smart enough to recognize it as the base directory of a project, and automatically builds a package tree. It also recognizes two important package directories in the package tree - \"apps\" and \"targets\". More on these directories in Newt Theory of Ops . When Newt is told to build a project, it recursively resolves all package dependencies and generates artifacts that are placed in the bin/ directory at the top-level of the project. The artifact directory is prefixed by the target name being built - my_blinky_sim for example: $ tree bin bin \u2514\u2500\u2500 my_blinky_sim \u251c\u2500\u2500 apps \u2502 \u2514\u2500\u2500 blinky \u2502 \u251c\u2500\u2500 blinky.a \u2502 \u251c\u2500\u2500 blinky.a.cmd \u2502 \u251c\u2500\u2500 blinky.elf \u2502 \u251c\u2500\u2500 blinky.elf.cmd \u2502 \u251c\u2500\u2500 blinky.elf.dSYM \u2502 \u2502 \u2514\u2500\u2500 Contents \u2502 \u2502 \u251c\u2500\u2500 Info.plist \u2502 \u2502 \u2514\u2500\u2500 Resources \u2502 \u2502 \u2514\u2500\u2500 DWARF \u2502 \u2502 \u2514\u2500\u2500 blinky.elf \u2502 \u251c\u2500\u2500 blinky.elf.lst \u2502 \u251c\u2500\u2500 main.d \u2502 \u251c\u2500\u2500 main.o \u2502 \u2514\u2500\u2500 main.o.cmd \u251c\u2500\u2500 hw \u2502 \u251c\u2500\u2500 bsp \u2502 \u2502 \u2514\u2500\u2500 native \u2502 \u2502 \u251c\u2500\u2500 hal_bsp.d \u2502 \u2502 \u251c\u2500\u2500 hal_bsp.o \u2502 \u2502 \u251c\u2500\u2500 hal_bsp.o.cmd <snip> More operations using Newt Once a target has been built, Newt allows additional operations on the target. download : Download built target to board debug : Open debugger session to target size : Get size of target components create-image : Add image header to the binary image For more details on how Newt works, go to Newt - Theory of Operations . Source Management and Repositories The other major element of the Newt tool is the ability to create reusable source distributions from a collection of code. A project can be a reusable container of source code. In other words, projects can be versioned and redistributed, not packages. A project bundles together packages that are typically needed to work together in a product e.g. RTOS core, filesystem APIs, and networking stack. A project that has been made redistributable is known as a repository . Repositories can be added to your local project by adding them into your project.yml file. Here is an example of the blinky project's yml file which relies on apache-mynewt-core: $ more project.yml <snip> project.repositories: - apache-mynewt-core # Use github's distribution mechanism for core ASF libraries. # This provides mirroring automatically for us. # repository.apache-mynewt-core: type: github vers: 0-latest user: apache repo: incubator-mynewt-core When you specify this repository in the blinky's project file, you can then use the Newt tool to install dependencies: $ newt install Downloading repository description for apache-mynewt-core... success! Downloading repository incubator-mynewt-core (branch: develop) at https://github.com/apache/incubator-mynewt-core.git Cloning into '/var/folders/7l/7b3w9m4n2mg3sqmgw2q1b9p80000gn/T/newt-repo814721459'... remote: Counting objects: 17601, done. remote: Compressing objects: 100% (300/300), done. remote: Total 17601 (delta 142), reused 0 (delta 0), pack-reused 17284 Receiving objects: 100% (17601/17601), 6.09 MiB | 3.17 MiB/s, done. Resolving deltas: 100% (10347/10347), done. Checking connectivity... done. Repos successfully installed Newt will install this repository in the /repos directory. In the case of blinky, the directory structure ends up looking like: $ tree -L 2 . \u251c\u2500\u2500 DISCLAIMER \u251c\u2500\u2500 LICENSE \u251c\u2500\u2500 NOTICE \u251c\u2500\u2500 README.md \u251c\u2500\u2500 apps \u2502 \u2514\u2500\u2500 blinky \u251c\u2500\u2500 project.state \u251c\u2500\u2500 project.yml \u251c\u2500\u2500 repos \u2502 \u2514\u2500\u2500 apache-mynewt-core \u2514\u2500\u2500 targets \u251c\u2500\u2500 my_blinky_sim \u2514\u2500\u2500 unittest In order to reference the installed repositories in packages, the \"@\" notation should be specified in the repository specifier. As an example, the apps/blinky application has the following dependencies in its pkg.yml file. This tells the build system to look in the base directory of repos/apache-mynewt-core for the libs/os , hw/hal , and libs/console/full packages. $ more apps/blinky/pkg.yml <snip> pkg.deps: - \"@apache-mynewt-core/libs/os\" - \"@apache-mynewt-core/hw/hal\" - \"@apache-mynewt-core/libs/console/full\"","title":"toc"},{"location":"newt/newt_intro/#newt-tool","text":"","title":"Newt Tool"},{"location":"newt/newt_intro/#introduction","text":"Newt is a smart build and package management system for embedded contexts. It is a single tool that accomplishes both the following goals: source package management build, debug and install.","title":"Introduction"},{"location":"newt/newt_intro/#rationale","text":"In order for the Mynewt operating system to work well for constrained environments across the many different types of microcontroller applications (from doorbells to medical devices to power grids), a system is needed that lets you select which packages to install and which packages to build. The build systems for embedded devices are often fairly complicated and not well served for this purpose. For example, autoconf is designed for detecting system compatibility issues but not well suited when it comes to tasks like: Building for multiple targets Deciding what to build in and what not to build in Managing dependencies between components Fortunately, solutions addressing these very issues can be found in source package management systems in higher level languages such as Javascript (Node), Go, PHP and Ruby. We decided to fuse their source management systems with a make system built for embedded systems and create Newt.","title":"Rationale"},{"location":"newt/newt_intro/#build-system","text":"A good build system must allow the user to take a few common steps while developing embedded applications: Generate full flash images Download debug images to a target board using a debugger Conditionally compile libraries & code based upon build settings Newt can read a directory tree, build a dependency tree, and emit the right build artifacts. An example newt source tree is in incubator-mynewt-blinky/develop: $ tree -L 3 . \u251c\u2500\u2500 DISCLAIMER \u251c\u2500\u2500 LICENSE \u251c\u2500\u2500 NOTICE \u251c\u2500\u2500 README.md \u251c\u2500\u2500 apps \u2502 \u2514\u2500\u2500 blinky \u2502 \u251c\u2500\u2500 pkg.yml \u2502 \u2514\u2500\u2500 src \u251c\u2500\u2500 project.yml \u2514\u2500\u2500 targets \u251c\u2500\u2500 my_blinky_sim \u2502 \u251c\u2500\u2500 pkg.yml \u2502 \u2514\u2500\u2500 target.yml \u2514\u2500\u2500 unittest \u251c\u2500\u2500 pkg.yml \u2514\u2500\u2500 target.yml 6 directories, 10 files When Newt sees a directory tree that contains a \"project.yml\" file, it is smart enough to recognize it as the base directory of a project, and automatically builds a package tree. It also recognizes two important package directories in the package tree - \"apps\" and \"targets\". More on these directories in Newt Theory of Ops . When Newt is told to build a project, it recursively resolves all package dependencies and generates artifacts that are placed in the bin/ directory at the top-level of the project. The artifact directory is prefixed by the target name being built - my_blinky_sim for example: $ tree bin bin \u2514\u2500\u2500 my_blinky_sim \u251c\u2500\u2500 apps \u2502 \u2514\u2500\u2500 blinky \u2502 \u251c\u2500\u2500 blinky.a \u2502 \u251c\u2500\u2500 blinky.a.cmd \u2502 \u251c\u2500\u2500 blinky.elf \u2502 \u251c\u2500\u2500 blinky.elf.cmd \u2502 \u251c\u2500\u2500 blinky.elf.dSYM \u2502 \u2502 \u2514\u2500\u2500 Contents \u2502 \u2502 \u251c\u2500\u2500 Info.plist \u2502 \u2502 \u2514\u2500\u2500 Resources \u2502 \u2502 \u2514\u2500\u2500 DWARF \u2502 \u2502 \u2514\u2500\u2500 blinky.elf \u2502 \u251c\u2500\u2500 blinky.elf.lst \u2502 \u251c\u2500\u2500 main.d \u2502 \u251c\u2500\u2500 main.o \u2502 \u2514\u2500\u2500 main.o.cmd \u251c\u2500\u2500 hw \u2502 \u251c\u2500\u2500 bsp \u2502 \u2502 \u2514\u2500\u2500 native \u2502 \u2502 \u251c\u2500\u2500 hal_bsp.d \u2502 \u2502 \u251c\u2500\u2500 hal_bsp.o \u2502 \u2502 \u251c\u2500\u2500 hal_bsp.o.cmd <snip>","title":"Build System"},{"location":"newt/newt_intro/#more-operations-using-newt","text":"Once a target has been built, Newt allows additional operations on the target. download : Download built target to board debug : Open debugger session to target size : Get size of target components create-image : Add image header to the binary image For more details on how Newt works, go to Newt - Theory of Operations .","title":"More operations using Newt"},{"location":"newt/newt_intro/#source-management-and-repositories","text":"The other major element of the Newt tool is the ability to create reusable source distributions from a collection of code. A project can be a reusable container of source code. In other words, projects can be versioned and redistributed, not packages. A project bundles together packages that are typically needed to work together in a product e.g. RTOS core, filesystem APIs, and networking stack. A project that has been made redistributable is known as a repository . Repositories can be added to your local project by adding them into your project.yml file. Here is an example of the blinky project's yml file which relies on apache-mynewt-core: $ more project.yml <snip> project.repositories: - apache-mynewt-core # Use github's distribution mechanism for core ASF libraries. # This provides mirroring automatically for us. # repository.apache-mynewt-core: type: github vers: 0-latest user: apache repo: incubator-mynewt-core When you specify this repository in the blinky's project file, you can then use the Newt tool to install dependencies: $ newt install Downloading repository description for apache-mynewt-core... success! Downloading repository incubator-mynewt-core (branch: develop) at https://github.com/apache/incubator-mynewt-core.git Cloning into '/var/folders/7l/7b3w9m4n2mg3sqmgw2q1b9p80000gn/T/newt-repo814721459'... remote: Counting objects: 17601, done. remote: Compressing objects: 100% (300/300), done. remote: Total 17601 (delta 142), reused 0 (delta 0), pack-reused 17284 Receiving objects: 100% (17601/17601), 6.09 MiB | 3.17 MiB/s, done. Resolving deltas: 100% (10347/10347), done. Checking connectivity... done. Repos successfully installed Newt will install this repository in the /repos directory. In the case of blinky, the directory structure ends up looking like: $ tree -L 2 . \u251c\u2500\u2500 DISCLAIMER \u251c\u2500\u2500 LICENSE \u251c\u2500\u2500 NOTICE \u251c\u2500\u2500 README.md \u251c\u2500\u2500 apps \u2502 \u2514\u2500\u2500 blinky \u251c\u2500\u2500 project.state \u251c\u2500\u2500 project.yml \u251c\u2500\u2500 repos \u2502 \u2514\u2500\u2500 apache-mynewt-core \u2514\u2500\u2500 targets \u251c\u2500\u2500 my_blinky_sim \u2514\u2500\u2500 unittest In order to reference the installed repositories in packages, the \"@\" notation should be specified in the repository specifier. As an example, the apps/blinky application has the following dependencies in its pkg.yml file. This tells the build system to look in the base directory of repos/apache-mynewt-core for the libs/os , hw/hal , and libs/console/full packages. $ more apps/blinky/pkg.yml <snip> pkg.deps: - \"@apache-mynewt-core/libs/os\" - \"@apache-mynewt-core/hw/hal\" - \"@apache-mynewt-core/libs/console/full\"","title":"Source Management and Repositories"},{"location":"newt/newt_operation/","text":"Newt Tool - Theory of Operations Newt has a fairly smart package manager that can read a directory tree, build a dependency tree, and emit the right build artifacts. Building dependencies Newt can read a directory tree, build a dependency tree, and emit the right build artifacts. An example newt source tree is in incubator-mynewt-blinky/develop: $ tree -L 3 . \u251c\u2500\u2500 DISCLAIMER \u251c\u2500\u2500 LICENSE \u251c\u2500\u2500 NOTICE \u251c\u2500\u2500 README.md \u251c\u2500\u2500 apps \u2502 \u2514\u2500\u2500 blinky \u2502 \u251c\u2500\u2500 pkg.yml \u2502 \u2514\u2500\u2500 src \u251c\u2500\u2500 project.yml \u2514\u2500\u2500 targets \u251c\u2500\u2500 my_blinky_sim \u2502 \u251c\u2500\u2500 pkg.yml \u2502 \u2514\u2500\u2500 target.yml \u2514\u2500\u2500 unittest \u251c\u2500\u2500 pkg.yml \u2514\u2500\u2500 target.yml 6 directories, 10 files When Newt sees a directory tree that contains a \"project.yml\" file it knows that it is in the base directory of a project, and automatically builds a package tree. You can see that there are two essential package directories, \"apps\" and \"targets.\" \"apps\" Package Directory apps is where applications are stored, and applications are where the main() function is contained. Along with the targets directory, apps represents the top-level of the build tree, and define the dependencies and features for the rest of the system. The app definition is contained in a pkg.yml file. An example of blinky's pkg.yml file is: $ more apps/blinky/pkg.yml <snip> pkg.name: apps/blinky pkg.vers: 0.8.0 pkg.description: Basic example application which blinks an LED. pkg.author: \"Apache Mynewt <dev@mynewt.incubator.apache.org>\" pkg.homepage: \"http://mynewt.apache.org/\" pkg.repository: pkg.keywords: pkg.deps: - \"@apache-mynewt-core/libs/os\" - \"@apache-mynewt-core/hw/hal\" - \"@apache-mynewt-core/libs/console/full\" This file says that the name of the package is apps/blinky, and it depends on libs/os, hw/hal and libs/console/full packages. NOTE: @apache-mynewt-core is a repository descriptor, and this will be covered in the \"repository\" section. \"targets\" Package Directory targets is where targets are stored, and each target is a collection of parameters that must be passed to Newt in order to generate a reproducible build. Along with the apps directory, targets represents the top of the build tree. Any packages or parameters specified at the target level cascades down to all dependencies. Most targets consist of: app: The application to build bsp: The board support package to combine with that application build_profile: Either debug or optimized. The my_blinky_sim target in the example below has the following settings: $ newt target show targets/my_blinky_sim app=apps/blinky bsp=@apache-mynewt-core/hw/bsp/native build_profile=debug $ ls my_blinky_sim/ pkg.yml target.yml In general, the three basic parameters of a target ( app , bsp , and build_profile ) are stored in the target.yml file in that target's build directory under targets . You will also see a pkg.yml file in the same directory. Since targets are packages, a pkg.yml is expected. It contains typical package descriptors, dependencies, and additional parameters such as the following: Cflags: Any additional compiler flags you might want to specify to the build Aflags: Any additional assembler flags you might want to specify to the build Lflags: Any additional linker flags you might want to specify to the build features: Any system level features you want to enable. Resolving dependencies When newt is told to build a project, it will: find the top-level project.yml file recurse the packages in the package tree, and build a list of all source packages Newt then looks at the target that the user set, for example, blinky_sim: $ more targets/my_blinky_sim/ pkg.yml target.yml $ more targets/my_blinky_sim/target.yml ### Target: targets/my_blinky_sim target.app: \"apps/blinky\" target.bsp: \"@apache-mynewt-core/hw/bsp/native\" target.build_profile: \"debug\" The target specifies two major things: Application (target.app): The application to build Board Support Package (target.bsp): The board support package to build along with that application. Newt goes and builds the dependency tree specified by all the packages. While building this tree, it does a few other things: Any package that depends on another package, automatically gets the include directories from the package it includes. Include directories in the newt structure must always be prefixed by the package name. For example, libs/os has the following include tree and its include directory files contains the package name \"os\" before any header files. This is so in order to avoid any header file conflicts. $ tree . \u251c\u2500\u2500 README.md \u251c\u2500\u2500 include \u2502 \u2514\u2500\u2500 os \u2502 \u251c\u2500\u2500 arch \u2502 \u2502 \u251c\u2500\u2500 cortex_m0 \u2502 \u2502 \u2502 \u2514\u2500\u2500 os \u2502 \u2502 \u2502 \u2514\u2500\u2500 os_arch.h \u2502 \u2502 \u251c\u2500\u2500 cortex_m4 \u2502 \u2502 \u2502 \u2514\u2500\u2500 os \u2502 \u2502 \u2502 \u2514\u2500\u2500 os_arch.h \u2502 \u2502 \u2514\u2500\u2500 sim \u2502 \u2502 \u2514\u2500\u2500 os \u2502 \u2502 \u2514\u2500\u2500 os_arch.h \u2502 \u251c\u2500\u2500 endian.h \u2502 \u251c\u2500\u2500 os.h \u2502 \u251c\u2500\u2500 os_callout.h \u2502 \u251c\u2500\u2500 os_cfg.h \u2502 \u251c\u2500\u2500 os_eventq.h \u2502 \u251c\u2500\u2500 os_heap.h \u2502 \u251c\u2500\u2500 os_malloc.h \u2502 \u251c\u2500\u2500 os_mbuf.h \u2502 \u251c\u2500\u2500 os_mempool.h \u2502 \u251c\u2500\u2500 os_mutex.h \u2502 \u251c\u2500\u2500 os_sanity.h \u2502 \u251c\u2500\u2500 os_sched.h \u2502 \u251c\u2500\u2500 os_sem.h \u2502 \u251c\u2500\u2500 os_task.h \u2502 \u251c\u2500\u2500 os_test.h \u2502 \u251c\u2500\u2500 os_time.h \u2502 \u2514\u2500\u2500 queue.h \u251c\u2500\u2500 pkg.yml \u2514\u2500\u2500 src \u251c\u2500\u2500 arch <snip> API requirements are validated. Packages can export APIs they implement, (i.e. pkg.api: hw-hal-impl), and other packages can require those APIs (i.e. pkg.req_api: hw-hal-impl). \"Features\" options are supported. Packages can change what dependencies they have, or what flags they are using based upon what features are enabled in the system. As an example, many packages will add additional software, based on whether the shell package is present. To do this, they can overwrite cflags or deps based upon the shell \"feature.\" pkg.cflags.SHELL: -DSHELL_PRESENT In order to properly resolve all dependencies in the build system, Newt recursively processes the package dependencies until there are no new dependencies or features (because features can add dependencies.) And it builds a big list of all the packages that need to be build. Newt then goes through this package list, and builds every package into an archive file. NOTE: The Newt tool generates compiler dependencies for all of these packages, and only rebuilds the packages whose dependencies have changed. Changes in package & project dependencies are also taken into account. It is smart, after all! Producing artifacts Once Newt has built all the archive files, it then links the archive files together. The linkerscript to use is specified by the board support package (BSP.) NOTE: One common use of the \"features\" option above is to overwrite which linkerscript is used, based upon whether or not the BSP is being build for a raw image, bootable image or bootloader itself. The newt tool places all of it's artifacts into the bin/ directory at the top-level of the project, prefixed by the target name being built, for example: $ tree -L 4 bin/ bin/ \u2514\u2500\u2500 my_blinky_sim \u251c\u2500\u2500 apps \u2502 \u2514\u2500\u2500 blinky \u2502 \u251c\u2500\u2500 blinky.a \u2502 \u251c\u2500\u2500 blinky.a.cmd \u2502 \u251c\u2500\u2500 blinky.elf \u2502 \u251c\u2500\u2500 blinky.elf.cmd \u2502 \u251c\u2500\u2500 blinky.elf.dSYM \u2502 \u251c\u2500\u2500 blinky.elf.lst \u2502 \u251c\u2500\u2500 main.d \u2502 \u251c\u2500\u2500 main.o \u2502 \u2514\u2500\u2500 main.o.cmd \u251c\u2500\u2500 hw \u2502 \u251c\u2500\u2500 bsp \u2502 \u2502 \u2514\u2500\u2500 native \u2502 \u251c\u2500\u2500 hal \u2502 \u2502 \u251c\u2500\u2500 flash_map.d \u2502 \u2502 \u251c\u2500\u2500 flash_map.o <snip> As you can see, a number of files are generated: Archive File *.cmd: The command use to generate the object or archive file *.lst: The list file where symbols are located *.o The object files that get put into the archive file Download/Debug Support Once a target has been build, there are a number of helper functions that work on the target. These are: download Download built target to board debug Open debugger session to target size Size of target components create-image Add image header to target binary Download and debug handles driving GDB and the system debugger. These commands call out to scripts that are defined by the BSP. $ more repos/apache-mynewt-core/hw/bsp/nrf52pdk/nrf52pdk_debug.sh <snip> # if [ $# -lt 1 ]; then echo \"Need binary to download\" exit 1 fi FILE_NAME=$2.elf GDB_CMD_FILE=.gdb_cmds echo \"Debugging\" $FILE_NAME # Monitor mode. Background process gets it's own process group. set -m JLinkGDBServer -device nRF52 -speed 4000 -if SWD -port 3333 -singlerun & set +m echo \"target remote localhost:3333\" > $GDB_CMD_FILE arm-none-eabi-gdb -x $GDB_CMD_FILE $FILE_NAME rm $GDB_CMD_FILE The idea is that every BSP will add support for the debugger environment for that board. That way common tools can be used across various development boards and kits. NOTE: Both for compiler definitions and debugger scripts, the plan is to create Dockerizable containers of these toolchains. This should make things much easier to support across Mac OS X, Linux and Windows. Newt will know how to call out to Docker to perform these processes.","title":"Newt Theory of Ops"},{"location":"newt/newt_operation/#newt-tool-theory-of-operations","text":"Newt has a fairly smart package manager that can read a directory tree, build a dependency tree, and emit the right build artifacts.","title":"Newt Tool - Theory of Operations"},{"location":"newt/newt_operation/#building-dependencies","text":"Newt can read a directory tree, build a dependency tree, and emit the right build artifacts. An example newt source tree is in incubator-mynewt-blinky/develop: $ tree -L 3 . \u251c\u2500\u2500 DISCLAIMER \u251c\u2500\u2500 LICENSE \u251c\u2500\u2500 NOTICE \u251c\u2500\u2500 README.md \u251c\u2500\u2500 apps \u2502 \u2514\u2500\u2500 blinky \u2502 \u251c\u2500\u2500 pkg.yml \u2502 \u2514\u2500\u2500 src \u251c\u2500\u2500 project.yml \u2514\u2500\u2500 targets \u251c\u2500\u2500 my_blinky_sim \u2502 \u251c\u2500\u2500 pkg.yml \u2502 \u2514\u2500\u2500 target.yml \u2514\u2500\u2500 unittest \u251c\u2500\u2500 pkg.yml \u2514\u2500\u2500 target.yml 6 directories, 10 files When Newt sees a directory tree that contains a \"project.yml\" file it knows that it is in the base directory of a project, and automatically builds a package tree. You can see that there are two essential package directories, \"apps\" and \"targets.\"","title":"Building dependencies"},{"location":"newt/newt_operation/#apps-package-directory","text":"apps is where applications are stored, and applications are where the main() function is contained. Along with the targets directory, apps represents the top-level of the build tree, and define the dependencies and features for the rest of the system. The app definition is contained in a pkg.yml file. An example of blinky's pkg.yml file is: $ more apps/blinky/pkg.yml <snip> pkg.name: apps/blinky pkg.vers: 0.8.0 pkg.description: Basic example application which blinks an LED. pkg.author: \"Apache Mynewt <dev@mynewt.incubator.apache.org>\" pkg.homepage: \"http://mynewt.apache.org/\" pkg.repository: pkg.keywords: pkg.deps: - \"@apache-mynewt-core/libs/os\" - \"@apache-mynewt-core/hw/hal\" - \"@apache-mynewt-core/libs/console/full\" This file says that the name of the package is apps/blinky, and it depends on libs/os, hw/hal and libs/console/full packages. NOTE: @apache-mynewt-core is a repository descriptor, and this will be covered in the \"repository\" section.","title":"\"apps\" Package Directory"},{"location":"newt/newt_operation/#targets-package-directory","text":"targets is where targets are stored, and each target is a collection of parameters that must be passed to Newt in order to generate a reproducible build. Along with the apps directory, targets represents the top of the build tree. Any packages or parameters specified at the target level cascades down to all dependencies. Most targets consist of: app: The application to build bsp: The board support package to combine with that application build_profile: Either debug or optimized. The my_blinky_sim target in the example below has the following settings: $ newt target show targets/my_blinky_sim app=apps/blinky bsp=@apache-mynewt-core/hw/bsp/native build_profile=debug $ ls my_blinky_sim/ pkg.yml target.yml In general, the three basic parameters of a target ( app , bsp , and build_profile ) are stored in the target.yml file in that target's build directory under targets . You will also see a pkg.yml file in the same directory. Since targets are packages, a pkg.yml is expected. It contains typical package descriptors, dependencies, and additional parameters such as the following: Cflags: Any additional compiler flags you might want to specify to the build Aflags: Any additional assembler flags you might want to specify to the build Lflags: Any additional linker flags you might want to specify to the build features: Any system level features you want to enable.","title":"\"targets\" Package Directory"},{"location":"newt/newt_operation/#resolving-dependencies","text":"When newt is told to build a project, it will: find the top-level project.yml file recurse the packages in the package tree, and build a list of all source packages Newt then looks at the target that the user set, for example, blinky_sim: $ more targets/my_blinky_sim/ pkg.yml target.yml $ more targets/my_blinky_sim/target.yml ### Target: targets/my_blinky_sim target.app: \"apps/blinky\" target.bsp: \"@apache-mynewt-core/hw/bsp/native\" target.build_profile: \"debug\" The target specifies two major things: Application (target.app): The application to build Board Support Package (target.bsp): The board support package to build along with that application. Newt goes and builds the dependency tree specified by all the packages. While building this tree, it does a few other things: Any package that depends on another package, automatically gets the include directories from the package it includes. Include directories in the newt structure must always be prefixed by the package name. For example, libs/os has the following include tree and its include directory files contains the package name \"os\" before any header files. This is so in order to avoid any header file conflicts. $ tree . \u251c\u2500\u2500 README.md \u251c\u2500\u2500 include \u2502 \u2514\u2500\u2500 os \u2502 \u251c\u2500\u2500 arch \u2502 \u2502 \u251c\u2500\u2500 cortex_m0 \u2502 \u2502 \u2502 \u2514\u2500\u2500 os \u2502 \u2502 \u2502 \u2514\u2500\u2500 os_arch.h \u2502 \u2502 \u251c\u2500\u2500 cortex_m4 \u2502 \u2502 \u2502 \u2514\u2500\u2500 os \u2502 \u2502 \u2502 \u2514\u2500\u2500 os_arch.h \u2502 \u2502 \u2514\u2500\u2500 sim \u2502 \u2502 \u2514\u2500\u2500 os \u2502 \u2502 \u2514\u2500\u2500 os_arch.h \u2502 \u251c\u2500\u2500 endian.h \u2502 \u251c\u2500\u2500 os.h \u2502 \u251c\u2500\u2500 os_callout.h \u2502 \u251c\u2500\u2500 os_cfg.h \u2502 \u251c\u2500\u2500 os_eventq.h \u2502 \u251c\u2500\u2500 os_heap.h \u2502 \u251c\u2500\u2500 os_malloc.h \u2502 \u251c\u2500\u2500 os_mbuf.h \u2502 \u251c\u2500\u2500 os_mempool.h \u2502 \u251c\u2500\u2500 os_mutex.h \u2502 \u251c\u2500\u2500 os_sanity.h \u2502 \u251c\u2500\u2500 os_sched.h \u2502 \u251c\u2500\u2500 os_sem.h \u2502 \u251c\u2500\u2500 os_task.h \u2502 \u251c\u2500\u2500 os_test.h \u2502 \u251c\u2500\u2500 os_time.h \u2502 \u2514\u2500\u2500 queue.h \u251c\u2500\u2500 pkg.yml \u2514\u2500\u2500 src \u251c\u2500\u2500 arch <snip> API requirements are validated. Packages can export APIs they implement, (i.e. pkg.api: hw-hal-impl), and other packages can require those APIs (i.e. pkg.req_api: hw-hal-impl). \"Features\" options are supported. Packages can change what dependencies they have, or what flags they are using based upon what features are enabled in the system. As an example, many packages will add additional software, based on whether the shell package is present. To do this, they can overwrite cflags or deps based upon the shell \"feature.\" pkg.cflags.SHELL: -DSHELL_PRESENT In order to properly resolve all dependencies in the build system, Newt recursively processes the package dependencies until there are no new dependencies or features (because features can add dependencies.) And it builds a big list of all the packages that need to be build. Newt then goes through this package list, and builds every package into an archive file. NOTE: The Newt tool generates compiler dependencies for all of these packages, and only rebuilds the packages whose dependencies have changed. Changes in package & project dependencies are also taken into account. It is smart, after all!","title":"Resolving dependencies"},{"location":"newt/newt_operation/#producing-artifacts","text":"Once Newt has built all the archive files, it then links the archive files together. The linkerscript to use is specified by the board support package (BSP.) NOTE: One common use of the \"features\" option above is to overwrite which linkerscript is used, based upon whether or not the BSP is being build for a raw image, bootable image or bootloader itself. The newt tool places all of it's artifacts into the bin/ directory at the top-level of the project, prefixed by the target name being built, for example: $ tree -L 4 bin/ bin/ \u2514\u2500\u2500 my_blinky_sim \u251c\u2500\u2500 apps \u2502 \u2514\u2500\u2500 blinky \u2502 \u251c\u2500\u2500 blinky.a \u2502 \u251c\u2500\u2500 blinky.a.cmd \u2502 \u251c\u2500\u2500 blinky.elf \u2502 \u251c\u2500\u2500 blinky.elf.cmd \u2502 \u251c\u2500\u2500 blinky.elf.dSYM \u2502 \u251c\u2500\u2500 blinky.elf.lst \u2502 \u251c\u2500\u2500 main.d \u2502 \u251c\u2500\u2500 main.o \u2502 \u2514\u2500\u2500 main.o.cmd \u251c\u2500\u2500 hw \u2502 \u251c\u2500\u2500 bsp \u2502 \u2502 \u2514\u2500\u2500 native \u2502 \u251c\u2500\u2500 hal \u2502 \u2502 \u251c\u2500\u2500 flash_map.d \u2502 \u2502 \u251c\u2500\u2500 flash_map.o <snip> As you can see, a number of files are generated: Archive File *.cmd: The command use to generate the object or archive file *.lst: The list file where symbols are located *.o The object files that get put into the archive file","title":"Producing artifacts"},{"location":"newt/newt_operation/#downloaddebug-support","text":"Once a target has been build, there are a number of helper functions that work on the target. These are: download Download built target to board debug Open debugger session to target size Size of target components create-image Add image header to target binary Download and debug handles driving GDB and the system debugger. These commands call out to scripts that are defined by the BSP. $ more repos/apache-mynewt-core/hw/bsp/nrf52pdk/nrf52pdk_debug.sh <snip> # if [ $# -lt 1 ]; then echo \"Need binary to download\" exit 1 fi FILE_NAME=$2.elf GDB_CMD_FILE=.gdb_cmds echo \"Debugging\" $FILE_NAME # Monitor mode. Background process gets it's own process group. set -m JLinkGDBServer -device nRF52 -speed 4000 -if SWD -port 3333 -singlerun & set +m echo \"target remote localhost:3333\" > $GDB_CMD_FILE arm-none-eabi-gdb -x $GDB_CMD_FILE $FILE_NAME rm $GDB_CMD_FILE The idea is that every BSP will add support for the debugger environment for that board. That way common tools can be used across various development boards and kits. NOTE: Both for compiler definitions and debugger scripts, the plan is to create Dockerizable containers of these toolchains. This should make things much easier to support across Mac OS X, Linux and Windows. Newt will know how to call out to Docker to perform these processes.","title":"Download/Debug Support"},{"location":"newt/newt_ops/","text":"Command Structure Just like verbs are actions in a sentence and adverdbs modifiy verbs, so in newt tool, commands are actions and flags modify actions. A command can have subcommands, too. Arguments to commands and subcommands, with appropriate flags, will dictate the execution and result of a command. For instance, in the example below, the newt command has the subcommand target set in which the argument 'my_target1' is the target whose attribute, arch , is set to 'cortex_md.' newt target set my_target1 arch=cortex_m4 Global flags work uniformly across newt commands. Consider the flag -v, --verbose, It works both for command and subcommands, to generate verbose output. Likewise, the help flag -h or --help, to print helpful messsages. A command may additionally take flags specific to it. For example, the -b flag instructs newt pkg install to install the pkg from a git branch. newt pkg install -b <branchname> <eggname> In addition to the Newt Tool Manual in docs, command-line help is available for each command (and subcommand), through the -h or --help options. $ newt target export --help Export build targets from the current nest, and print them to standard output. If the -a (or -export-all) option is specified, then all targets will be exported. Otherwise, <target-name> must be specified, and only that target will be exported. Usage: newt target export [flags] Examples: newt target export [-a -export-all] [<target-name>] newt target export -a > my_exports.txt newt target export my_target > my_target_export.txt Flags: -a, --export-all=false: If present, export all targets -h, --help=false: help for export Global Flags: -l, --loglevel=\"WARN\": Log level, defaults to WARN. -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands.","title":"toc"},{"location":"newt/newt_ops/#command-structure","text":"Just like verbs are actions in a sentence and adverdbs modifiy verbs, so in newt tool, commands are actions and flags modify actions. A command can have subcommands, too. Arguments to commands and subcommands, with appropriate flags, will dictate the execution and result of a command. For instance, in the example below, the newt command has the subcommand target set in which the argument 'my_target1' is the target whose attribute, arch , is set to 'cortex_md.' newt target set my_target1 arch=cortex_m4 Global flags work uniformly across newt commands. Consider the flag -v, --verbose, It works both for command and subcommands, to generate verbose output. Likewise, the help flag -h or --help, to print helpful messsages. A command may additionally take flags specific to it. For example, the -b flag instructs newt pkg install to install the pkg from a git branch. newt pkg install -b <branchname> <eggname> In addition to the Newt Tool Manual in docs, command-line help is available for each command (and subcommand), through the -h or --help options. $ newt target export --help Export build targets from the current nest, and print them to standard output. If the -a (or -export-all) option is specified, then all targets will be exported. Otherwise, <target-name> must be specified, and only that target will be exported. Usage: newt target export [flags] Examples: newt target export [-a -export-all] [<target-name>] newt target export -a > my_exports.txt newt target export my_target > my_target_export.txt Flags: -a, --export-all=false: If present, export all targets -h, --help=false: help for export Global Flags: -l, --loglevel=\"WARN\": Log level, defaults to WARN. -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands.","title":"Command Structure"},{"location":"newt/command_list/newt_build/","text":"newt build Compiles, links, and builds one or more apps. Usage: newt build [flags] input1 where input1 is the name of the target to build. Flags: -h, --help=false: help for target Global Flags: -l, --loglevel=\"WARN\": Log level, defaults to WARN. -o, --outfile string Filename to tee log output to -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands. Examples Sub-command Usage Explanation build newt build input1 Builds the source code into an image that can be loaded on the hardware ( bsp ) associated with the target named input1 to run the application enabled by the app setting associated with that target. It creates 'bin/' directory and 'bin/ /apps/ ' subdirectory inside the base directory for the app, compiles and generates binaries and executables, and places them in that subdirectory. newt build my_blinky_sim For example, if app was set to apps/blinky for the target \"my_blinky_sim\", you will find the generated .elf, .a, and .lst files in bin/my_blinky_sim/apps/blinky directory created under the base directory for the app created using newt new at the start of the project. build newt build my_blinky_sim myble builds the apps defined for both the targets \"my_blinky_sim\" and \"myble\".","title":"newt build"},{"location":"newt/command_list/newt_build/#newt-build","text":"Compiles, links, and builds one or more apps.","title":"newt build "},{"location":"newt/command_list/newt_build/#usage","text":"newt build [flags] input1 where input1 is the name of the target to build.","title":"Usage:"},{"location":"newt/command_list/newt_build/#flags","text":"-h, --help=false: help for target","title":"Flags:"},{"location":"newt/command_list/newt_build/#global-flags","text":"-l, --loglevel=\"WARN\": Log level, defaults to WARN. -o, --outfile string Filename to tee log output to -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands.","title":"Global Flags:"},{"location":"newt/command_list/newt_build/#examples","text":"Sub-command Usage Explanation build newt build input1 Builds the source code into an image that can be loaded on the hardware ( bsp ) associated with the target named input1 to run the application enabled by the app setting associated with that target. It creates 'bin/' directory and 'bin/ /apps/ ' subdirectory inside the base directory for the app, compiles and generates binaries and executables, and places them in that subdirectory. newt build my_blinky_sim For example, if app was set to apps/blinky for the target \"my_blinky_sim\", you will find the generated .elf, .a, and .lst files in bin/my_blinky_sim/apps/blinky directory created under the base directory for the app created using newt new at the start of the project. build newt build my_blinky_sim myble builds the apps defined for both the targets \"my_blinky_sim\" and \"myble\".","title":"Examples"},{"location":"newt/command_list/newt_clean/","text":"newt clean Deletes application build artifacts for a specified target Usage: newt clean [flags] input1 Flags: -h, --help=false: help for target Global Flags: -l, --loglevel=\"WARN\": Log level, defaults to WARN. -o, --outfile string Filename to tee log output to -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands. Description Sub-command Explanation clean Deletes all the build artifacts generated for target specified by input1 . It does not delete the target definition. Examples Sub-command Usage Explanation clean newt clean myble2 Removes all the files generated while building the target myble2 and placed in the bin/myble2 directory created during the build process.","title":"newt clean"},{"location":"newt/command_list/newt_clean/#newt-clean","text":"Deletes application build artifacts for a specified target","title":"newt clean "},{"location":"newt/command_list/newt_clean/#usage","text":"newt clean [flags] input1","title":"Usage:"},{"location":"newt/command_list/newt_clean/#flags","text":"-h, --help=false: help for target","title":"Flags:"},{"location":"newt/command_list/newt_clean/#global-flags","text":"-l, --loglevel=\"WARN\": Log level, defaults to WARN. -o, --outfile string Filename to tee log output to -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands.","title":"Global Flags:"},{"location":"newt/command_list/newt_clean/#description","text":"Sub-command Explanation clean Deletes all the build artifacts generated for target specified by input1 . It does not delete the target definition.","title":"Description"},{"location":"newt/command_list/newt_clean/#examples","text":"Sub-command Usage Explanation clean newt clean myble2 Removes all the files generated while building the target myble2 and placed in the bin/myble2 directory created during the build process.","title":"Examples"},{"location":"newt/command_list/newt_create_image/","text":"newt create-image Creates a signed image by adding image header to created binary file for specified target. Version number in the header is set to be Usage: newt create-image <target-name> <version> [flags] Flags: -h, --help=false: help for target Global Flags: -l, --loglevel=\"WARN\": Log level, defaults to WARN. -o, --outfile string Filename to tee log output to -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands. Description Sub-command Explanation create-image Signs and adds image header to the created binary file for target named <target-name> and given the version specified as <version> . The application image generated is <app-name>.img where the app-name is the same as the app specified in the target definition. The generated application image can be found in /bin/<target-name>/apps/<app-name>/ . A build manifest file manifest.json is also generated in the same directory. This build manifest contains information such as build time, version, image name, a hash to identify the image, packages actually used to create the build, and the target for which the image is built. Examples Sub-command Usage Explanation create-image newt create-image myble2 1.0.1.0 Creates a signed image for target myble2 and assigns it the version 1.0.1.0 . If the target is as follows: targets/myble2 app=@apache-mynewt-core/apps/bletiny bsp=@apache-mynewt-core/hw/bsp/nrf52pdk build_profile=optimized cflags=-DSTATS_NAME_ENABLE then, the created image is bin/myble2/apps/bletiny/bletiny.img and the manifest is bin/myble2/apps/bletiny/manifest.json","title":"newt create-image"},{"location":"newt/command_list/newt_create_image/#newt-create-image","text":"Creates a signed image by adding image header to created binary file for specified target. Version number in the header is set to be","title":"newt create-image "},{"location":"newt/command_list/newt_create_image/#usage","text":"newt create-image <target-name> <version> [flags]","title":"Usage:"},{"location":"newt/command_list/newt_create_image/#flags","text":"-h, --help=false: help for target","title":"Flags:"},{"location":"newt/command_list/newt_create_image/#global-flags","text":"-l, --loglevel=\"WARN\": Log level, defaults to WARN. -o, --outfile string Filename to tee log output to -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands.","title":"Global Flags:"},{"location":"newt/command_list/newt_create_image/#description","text":"Sub-command Explanation create-image Signs and adds image header to the created binary file for target named <target-name> and given the version specified as <version> . The application image generated is <app-name>.img where the app-name is the same as the app specified in the target definition. The generated application image can be found in /bin/<target-name>/apps/<app-name>/ . A build manifest file manifest.json is also generated in the same directory. This build manifest contains information such as build time, version, image name, a hash to identify the image, packages actually used to create the build, and the target for which the image is built.","title":"Description"},{"location":"newt/command_list/newt_create_image/#examples","text":"Sub-command Usage Explanation create-image newt create-image myble2 1.0.1.0 Creates a signed image for target myble2 and assigns it the version 1.0.1.0 . If the target is as follows: targets/myble2 app=@apache-mynewt-core/apps/bletiny bsp=@apache-mynewt-core/hw/bsp/nrf52pdk build_profile=optimized cflags=-DSTATS_NAME_ENABLE then, the created image is bin/myble2/apps/bletiny/bletiny.img and the manifest is bin/myble2/apps/bletiny/manifest.json","title":"Examples"},{"location":"newt/command_list/newt_debug/","text":"newt debug Opens debugger session for specified target. Usage: newt debug <target-name> [flag] Flags: -h, --help=false: help for target Global Flags: -l, --loglevel=\"WARN\": Log level, defaults to WARN. -o, --outfile string Filename to tee log output to -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands. Description Sub-command Explanation debug Opens the appropriate debugging session for the image built for the named target. Examples Sub-command Usage Explanation debug newt debug myble2 Opens J-Link connection and starts a GNU gdb session to debug bin/myble2/apps/bletiny/bletiny.elf when the target is as follows: targets/myble2 app=@apache-mynewt-core/apps/bletiny bsp=@apache-mynewt-core/hw/bsp/nrf52pdk build_profile=optimized cflags=-DSTATS_NAME_ENABLE","title":"newt debug"},{"location":"newt/command_list/newt_debug/#newt-debug","text":"Opens debugger session for specified target.","title":"newt debug "},{"location":"newt/command_list/newt_debug/#usage","text":"newt debug <target-name> [flag]","title":"Usage:"},{"location":"newt/command_list/newt_debug/#flags","text":"-h, --help=false: help for target","title":"Flags:"},{"location":"newt/command_list/newt_debug/#global-flags","text":"-l, --loglevel=\"WARN\": Log level, defaults to WARN. -o, --outfile string Filename to tee log output to -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands.","title":"Global Flags:"},{"location":"newt/command_list/newt_debug/#description","text":"Sub-command Explanation debug Opens the appropriate debugging session for the image built for the named target.","title":"Description"},{"location":"newt/command_list/newt_debug/#examples","text":"Sub-command Usage Explanation debug newt debug myble2 Opens J-Link connection and starts a GNU gdb session to debug bin/myble2/apps/bletiny/bletiny.elf when the target is as follows: targets/myble2 app=@apache-mynewt-core/apps/bletiny bsp=@apache-mynewt-core/hw/bsp/nrf52pdk build_profile=optimized cflags=-DSTATS_NAME_ENABLE","title":"Examples"},{"location":"newt/command_list/newt_help/","text":"newt help Displays the help text for the newt command line tool: Newt allows you to create your own embedded application based on the Mynewt operating system. Newt provides both build and package management in a single tool, which allows you to compose an embedded application, and set of projects, and then build the necessary artifacts from those projects. For more information on the Mynewt operating system, please visit https://mynewt.apache.org/. Usage: newt help [input1] Flags: -h, --help=false: help for newt -o, --outfile string Filename to tee output to -l, --loglevel=\"WARN\": Log level, defaults to WARN. -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands. Available Commands: version Display the Newt version number. install Install project dependencies upgrade Upgrade project dependencies new Create a new project info Show project info target Command for manipulating targets build Builds one or more targets. clean Deletes build artifacts for one or more targets. test Executes unit tests for one or more packages load Load built target to board debug Open debugger session to target size Size of target components create-image Add image header to target binary run build/create-image/download/debug <target> Examples Sub-command Usage Explanation help newt help target Displays the help text for the newt command 'target' help newt help Displays the help text for newt tool","title":"newt help"},{"location":"newt/command_list/newt_help/#newt-help","text":"Displays the help text for the newt command line tool: Newt allows you to create your own embedded application based on the Mynewt operating system. Newt provides both build and package management in a single tool, which allows you to compose an embedded application, and set of projects, and then build the necessary artifacts from those projects. For more information on the Mynewt operating system, please visit https://mynewt.apache.org/.","title":"newt help "},{"location":"newt/command_list/newt_help/#usage","text":"newt help [input1]","title":"Usage:"},{"location":"newt/command_list/newt_help/#flags","text":"-h, --help=false: help for newt -o, --outfile string Filename to tee output to -l, --loglevel=\"WARN\": Log level, defaults to WARN. -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands.","title":"Flags:"},{"location":"newt/command_list/newt_help/#available-commands","text":"version Display the Newt version number. install Install project dependencies upgrade Upgrade project dependencies new Create a new project info Show project info target Command for manipulating targets build Builds one or more targets. clean Deletes build artifacts for one or more targets. test Executes unit tests for one or more packages load Load built target to board debug Open debugger session to target size Size of target components create-image Add image header to target binary run build/create-image/download/debug <target>","title":"Available Commands:"},{"location":"newt/command_list/newt_help/#examples","text":"Sub-command Usage Explanation help newt help target Displays the help text for the newt command 'target' help newt help Displays the help text for newt tool","title":"Examples"},{"location":"newt/command_list/newt_info/","text":"newt info Shows information about the current project. Usage: newt info [flags] Global Flags: -l, --loglevel=\"WARN\": Log level, defaults to WARN. -o, --outfile string Filename to tee output to -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands. Description Sub-command Explanation info Displays the repositories in the current project (the local as well as all the external repositories fetched). Also displays the packages in the local repository.","title":"newt info"},{"location":"newt/command_list/newt_info/#newt-info","text":"Shows information about the current project.","title":"newt info "},{"location":"newt/command_list/newt_info/#usage","text":"newt info [flags]","title":"Usage:"},{"location":"newt/command_list/newt_info/#global-flags","text":"-l, --loglevel=\"WARN\": Log level, defaults to WARN. -o, --outfile string Filename to tee output to -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands.","title":"Global Flags:"},{"location":"newt/command_list/newt_info/#description","text":"Sub-command Explanation info Displays the repositories in the current project (the local as well as all the external repositories fetched). Also displays the packages in the local repository.","title":"Description"},{"location":"newt/command_list/newt_install/","text":"newt install Install project dependencies. Usage: newt install [flags] Flags: -f, --force Force install of the repositories in project, regardless of what exists in repos directory Global Flags: -h, --help=false: help for newt -o, --outfile string Filename to tee output to -l, --loglevel=\"WARN\": Log level, defaults to WARN. -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands. Description Sub-command Explanation install Downloads description of all the repositories specified in the project.yml file of the current project directory. Installs all the correct versions of all the packages dictated by the project dependencies. Always run the command from within the project directory (i.e. remember to cd into the app directory after creating a new app using newt new ) before running newt install .","title":"newt install"},{"location":"newt/command_list/newt_install/#newt-install","text":"Install project dependencies.","title":"newt install "},{"location":"newt/command_list/newt_install/#usage","text":"newt install [flags]","title":"Usage:"},{"location":"newt/command_list/newt_install/#flags","text":"-f, --force Force install of the repositories in project, regardless of what exists in repos directory","title":"Flags:"},{"location":"newt/command_list/newt_install/#global-flags","text":"-h, --help=false: help for newt -o, --outfile string Filename to tee output to -l, --loglevel=\"WARN\": Log level, defaults to WARN. -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands.","title":"Global Flags:"},{"location":"newt/command_list/newt_install/#description","text":"Sub-command Explanation install Downloads description of all the repositories specified in the project.yml file of the current project directory. Installs all the correct versions of all the packages dictated by the project dependencies. Always run the command from within the project directory (i.e. remember to cd into the app directory after creating a new app using newt new ) before running newt install .","title":"Description"},{"location":"newt/command_list/newt_load/","text":"newt load Load app image to specified target. Usage: newt load <target-name> [flags] Flags: -h, --help=false: help for target Global Flags: -l, --loglevel=\"WARN\": Log level, defaults to WARN. -o, --outfile string Filename to tee output to -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands. Description Sub-command Explanation load Uses download scripts to automatically load, onto the connected board, the image built for the app defined in the target specified by . If the wrong board is connected, or the target definition is wrong (i.e. the wrong values are given for bsp or app), the command will fail with error messages such as Can not connect to J-Link via USB or Unspecified error -1 .","title":"newt load"},{"location":"newt/command_list/newt_load/#newt-load","text":"Load app image to specified target.","title":"newt load "},{"location":"newt/command_list/newt_load/#usage","text":"newt load <target-name> [flags]","title":"Usage:"},{"location":"newt/command_list/newt_load/#flags","text":"-h, --help=false: help for target","title":"Flags:"},{"location":"newt/command_list/newt_load/#global-flags","text":"-l, --loglevel=\"WARN\": Log level, defaults to WARN. -o, --outfile string Filename to tee output to -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands.","title":"Global Flags:"},{"location":"newt/command_list/newt_load/#description","text":"Sub-command Explanation load Uses download scripts to automatically load, onto the connected board, the image built for the app defined in the target specified by . If the wrong board is connected, or the target definition is wrong (i.e. the wrong values are given for bsp or app), the command will fail with error messages such as Can not connect to J-Link via USB or Unspecified error -1 .","title":"Description"},{"location":"newt/command_list/newt_new/","text":"newt new Create a new application, specified by , from a given skeleton. Currently, the default skeleton is the blinky repository in Apache Mynewt (or https://github.com/apache/incubator-mynewt-blinky on its github mirror.) Usage: newt new [flags] <app-name> Flags: -h, --help=false: help for new Global Flags: -h, --help=false: help for newt -o, --outfile string Filename to tee output to -l, --loglevel=\"WARN\": Log level, defaults to WARN. -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands. Examples Sub-command Usage Explanation newt new newt new test_project Creates a new app named \"test_project \" using the default skeleton from the apache/incubator-mynewt-blinky repo.","title":"newt new"},{"location":"newt/command_list/newt_new/#newt-new","text":"Create a new application, specified by , from a given skeleton. Currently, the default skeleton is the blinky repository in Apache Mynewt (or https://github.com/apache/incubator-mynewt-blinky on its github mirror.)","title":"newt new "},{"location":"newt/command_list/newt_new/#usage","text":"newt new [flags] <app-name>","title":"Usage:"},{"location":"newt/command_list/newt_new/#flags","text":"-h, --help=false: help for new","title":"Flags:"},{"location":"newt/command_list/newt_new/#global-flags","text":"-h, --help=false: help for newt -o, --outfile string Filename to tee output to -l, --loglevel=\"WARN\": Log level, defaults to WARN. -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands.","title":"Global Flags:"},{"location":"newt/command_list/newt_new/#examples","text":"Sub-command Usage Explanation newt new newt new test_project Creates a new app named \"test_project \" using the default skeleton from the apache/incubator-mynewt-blinky repo.","title":"Examples"},{"location":"newt/command_list/newt_run/","text":"newt run A single command to do four steps - build a target, create-image, load image on a board, and start a debug session with the image on board. Note : If version number is omitted, create-image step is skipped Usage: newt run <target-name> [<version>][flags] Flags: -h, --help=false: help for target Global Flags: -l, --loglevel=\"WARN\": Log level, defaults to WARN. -o, --outfile string Filename to tee log output to -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands. Description Sub-command Explanation run Same as running build <target> , create-image <target> <version> , load <target> , and debug <target> . Examples Sub-command Usage Explanation run newt run blink_rigado First compiles and builds executable for running the app defined in the target blink_rigado on the board defined in the same target, then loads image onto the board, and finally opens an active GNU gdb debugging session to run the image. run newt run ble_rigado 0.1.0.0 First compiles and builds executable for running the app defined in the target ble_rigado on the board defined in the same target, then signs and creates image with version number 0.1.0.0, loads the image onto the board, and finally opens an active GNU gdb debugging session to run the image. Note that if there is no bootloader available for a particular board/kit, a signed image creation step is not necessary.","title":"newt run"},{"location":"newt/command_list/newt_run/#newt-run","text":"A single command to do four steps - build a target, create-image, load image on a board, and start a debug session with the image on board. Note : If version number is omitted, create-image step is skipped","title":"newt run "},{"location":"newt/command_list/newt_run/#usage","text":"newt run <target-name> [<version>][flags]","title":"Usage:"},{"location":"newt/command_list/newt_run/#flags","text":"-h, --help=false: help for target","title":"Flags:"},{"location":"newt/command_list/newt_run/#global-flags","text":"-l, --loglevel=\"WARN\": Log level, defaults to WARN. -o, --outfile string Filename to tee log output to -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands.","title":"Global Flags:"},{"location":"newt/command_list/newt_run/#description","text":"Sub-command Explanation run Same as running build <target> , create-image <target> <version> , load <target> , and debug <target> .","title":"Description"},{"location":"newt/command_list/newt_run/#examples","text":"Sub-command Usage Explanation run newt run blink_rigado First compiles and builds executable for running the app defined in the target blink_rigado on the board defined in the same target, then loads image onto the board, and finally opens an active GNU gdb debugging session to run the image. run newt run ble_rigado 0.1.0.0 First compiles and builds executable for running the app defined in the target ble_rigado on the board defined in the same target, then signs and creates image with version number 0.1.0.0, loads the image onto the board, and finally opens an active GNU gdb debugging session to run the image. Note that if there is no bootloader available for a particular board/kit, a signed image creation step is not necessary.","title":"Examples"},{"location":"newt/command_list/newt_size/","text":"newt size Calculate the size of target components specified by Usage: newt size <target-name> [flags] Flags: -h, --help=false: help for target Global Flags: -l, --loglevel=\"WARN\": Log level, defaults to WARN. -o, --outfile string Filename to tee log output to -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands. Examples Sub-command Usage Explanation size newt size blink_rigado Inspects and lists the RAM and Flash memory use by each component (object files and libraries) of the target. Example output for newt size boot_olimex : $ newt size blink_rigado FLASH RAM 9 223 *fill* 1052 0 baselibc.a 195 1116 blinky.a 616 452 bmd300eval.a 64 0 cmsis-core.a 124 0 crt0.o 8 0 crti.o 16 0 crtn.o 277 196 full.a 20 8 hal.a 96 1068 libg.a 1452 0 libgcc.a 332 28 nrf52xxx.a 3143 677 os.a objsize text data bss dec hex filename 7404 1172 2212 10788 2a24 /Users/<username>/dev/rigado/bin/blink_rigado/apps/blinky/blinky.elf","title":"newt size"},{"location":"newt/command_list/newt_size/#newt-size","text":"Calculate the size of target components specified by","title":"newt size "},{"location":"newt/command_list/newt_size/#usage","text":"newt size <target-name> [flags]","title":"Usage:"},{"location":"newt/command_list/newt_size/#flags","text":"-h, --help=false: help for target","title":"Flags:"},{"location":"newt/command_list/newt_size/#global-flags","text":"-l, --loglevel=\"WARN\": Log level, defaults to WARN. -o, --outfile string Filename to tee log output to -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands.","title":"Global Flags:"},{"location":"newt/command_list/newt_size/#examples","text":"Sub-command Usage Explanation size newt size blink_rigado Inspects and lists the RAM and Flash memory use by each component (object files and libraries) of the target.","title":"Examples"},{"location":"newt/command_list/newt_size/#example-output-for-newt-size-boot_olimex","text":"$ newt size blink_rigado FLASH RAM 9 223 *fill* 1052 0 baselibc.a 195 1116 blinky.a 616 452 bmd300eval.a 64 0 cmsis-core.a 124 0 crt0.o 8 0 crti.o 16 0 crtn.o 277 196 full.a 20 8 hal.a 96 1068 libg.a 1452 0 libgcc.a 332 28 nrf52xxx.a 3143 677 os.a objsize text data bss dec hex filename 7404 1172 2212 10788 2a24 /Users/<username>/dev/rigado/bin/blink_rigado/apps/blinky/blinky.elf","title":"Example output for newt size boot_olimex:"},{"location":"newt/command_list/newt_target/","text":"newt target Provides commands to create, build, delete, and query targets. Usage: newt target [command] input1 [input2] Available Commands: show View target configuration variables set Set target configuration variable create Create a target delete Delete target copy Copy target vars Show variable names possible for a target Flags: -h, --help=false: help for target Global Flags: -l, --loglevel=\"WARN\": Log level, defaults to WARN. -o, --outfile string Filename to tee log output to -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands. Description Sub-command Explanation show Shows what variables (attributes) are set on the specified target input1 . If no input1 is specified then show the configuration for all the targets defined so far. set Set variables (attributes) of the target named via input1 . Currently the list of possible attributes (variables) are: app , bsp , build_profile , features , cflags , lflags . For a simulated target, e.g. for software testing purposes, bsp is set to @apache-mynewt-core/hw/bsp/native . To display all the existing values for a target variable (attribute), you can simply hit return after that variable. For example, newt target set input1 app displays the valid values available for the variable app for a target named input11 . Currently, the only two values available for build_profile are optimized and debug . create Creates an empty target definition by the name of input1 . delete Deletes only the description for the target. Does not delete the target directory with associated binaries. If you want to clean out the binaries, list files, and executables use newt target clean <target-name> before deleting the target! copy Creates a new target by the name of input2 by cloning the definition of an existing target named input1 . vars Shows what variables (attributes) are available to set on the target Examples Sub-command Usage Explanation show newt target show myble Shows all variable settings for the target named \"myble\" i.e. what app, bsp, build_profile, features, cflags are set to. Note that all variables are not required to be set in order to successfully define a target. show newt target show Shows all variable settings for all the targets defined. set newt target set myble app=@apache-mynewt-core/apps/bletiny Assign bletiny to be the application to be included in the build for the target named myble . copy newt target copy my_blinky_sim test1 Creates a new target by the name test1 by copying the attributes from my_blinky_sim vars newt target vars Shows all the variables newt recognizes - app, bsp, build_profile, features","title":"newt target"},{"location":"newt/command_list/newt_target/#newt-target","text":"Provides commands to create, build, delete, and query targets.","title":"newt target "},{"location":"newt/command_list/newt_target/#usage","text":"newt target [command] input1 [input2]","title":"Usage:"},{"location":"newt/command_list/newt_target/#available-commands","text":"show View target configuration variables set Set target configuration variable create Create a target delete Delete target copy Copy target vars Show variable names possible for a target","title":"Available Commands:"},{"location":"newt/command_list/newt_target/#flags","text":"-h, --help=false: help for target","title":"Flags:"},{"location":"newt/command_list/newt_target/#global-flags","text":"-l, --loglevel=\"WARN\": Log level, defaults to WARN. -o, --outfile string Filename to tee log output to -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands.","title":"Global Flags:"},{"location":"newt/command_list/newt_target/#description","text":"Sub-command Explanation show Shows what variables (attributes) are set on the specified target input1 . If no input1 is specified then show the configuration for all the targets defined so far. set Set variables (attributes) of the target named via input1 . Currently the list of possible attributes (variables) are: app , bsp , build_profile , features , cflags , lflags . For a simulated target, e.g. for software testing purposes, bsp is set to @apache-mynewt-core/hw/bsp/native . To display all the existing values for a target variable (attribute), you can simply hit return after that variable. For example, newt target set input1 app displays the valid values available for the variable app for a target named input11 . Currently, the only two values available for build_profile are optimized and debug . create Creates an empty target definition by the name of input1 . delete Deletes only the description for the target. Does not delete the target directory with associated binaries. If you want to clean out the binaries, list files, and executables use newt target clean <target-name> before deleting the target! copy Creates a new target by the name of input2 by cloning the definition of an existing target named input1 . vars Shows what variables (attributes) are available to set on the target","title":"Description"},{"location":"newt/command_list/newt_target/#examples","text":"Sub-command Usage Explanation show newt target show myble Shows all variable settings for the target named \"myble\" i.e. what app, bsp, build_profile, features, cflags are set to. Note that all variables are not required to be set in order to successfully define a target. show newt target show Shows all variable settings for all the targets defined. set newt target set myble app=@apache-mynewt-core/apps/bletiny Assign bletiny to be the application to be included in the build for the target named myble . copy newt target copy my_blinky_sim test1 Creates a new target by the name test1 by copying the attributes from my_blinky_sim vars newt target vars Shows all the variables newt recognizes - app, bsp, build_profile, features","title":"Examples"},{"location":"newt/command_list/newt_test/","text":"newt test Executes unit tests for one or more packages Usage: newt test [flags] input1 [input2] ... Flags: -h, --help=false: help for target Global Flags: -l, --loglevel=\"WARN\": Log level, defaults to WARN. -o, --outfile string Filename to tee log output to -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands. Description Sub-command Explanation test Test a pkg named input1 . You may specify multiple packages separated by space in the same command. Examples Sub-command Usage Explanation test newt test targets/myble2 Tests the pkg named 'targets/myble2' newt test @apache-mynewt-core/libs/os Tests the libs/os pkg in the repo named apache-mynewt-core newt test libs/os libs/json Tests the libs/os and libs/json packages in the current repo. Should indicate at the end of the output: Passed tests: [libs/os libs/json] All tests passed","title":"newt test"},{"location":"newt/command_list/newt_test/#newt-test","text":"Executes unit tests for one or more packages","title":"newt test "},{"location":"newt/command_list/newt_test/#usage","text":"newt test [flags] input1 [input2] ...","title":"Usage:"},{"location":"newt/command_list/newt_test/#flags","text":"-h, --help=false: help for target","title":"Flags:"},{"location":"newt/command_list/newt_test/#global-flags","text":"-l, --loglevel=\"WARN\": Log level, defaults to WARN. -o, --outfile string Filename to tee log output to -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands.","title":"Global Flags:"},{"location":"newt/command_list/newt_test/#description","text":"Sub-command Explanation test Test a pkg named input1 . You may specify multiple packages separated by space in the same command.","title":"Description"},{"location":"newt/command_list/newt_test/#examples","text":"Sub-command Usage Explanation test newt test targets/myble2 Tests the pkg named 'targets/myble2' newt test @apache-mynewt-core/libs/os Tests the libs/os pkg in the repo named apache-mynewt-core newt test libs/os libs/json Tests the libs/os and libs/json packages in the current repo. Should indicate at the end of the output: Passed tests: [libs/os libs/json] All tests passed","title":"Examples"},{"location":"newt/command_list/newt_upgrade/","text":"newt upgrade Upgrade project dependencies Usage: newt pkg [command][flag] input1 input2 Flags: -f, --force Force upgrade of the repositories to latest state in project.yml #### Global Flags: -l, --loglevel=\"WARN\": Log level, defaults to WARN. -o, --outfile string Filename to tee log output to -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands. Description Sub-command Explanation upgrade If you have changed the project.yml description for the project, you need to run this command to update all the package dependencies.","title":"newt upgrade"},{"location":"newt/command_list/newt_upgrade/#newt-upgrade","text":"Upgrade project dependencies","title":"newt upgrade "},{"location":"newt/command_list/newt_upgrade/#usage","text":"newt pkg [command][flag] input1 input2","title":"Usage:"},{"location":"newt/command_list/newt_upgrade/#flags","text":"-f, --force Force upgrade of the repositories to latest state in project.yml #### Global Flags: -l, --loglevel=\"WARN\": Log level, defaults to WARN. -o, --outfile string Filename to tee log output to -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands.","title":"Flags:"},{"location":"newt/command_list/newt_upgrade/#description","text":"Sub-command Explanation upgrade If you have changed the project.yml description for the project, you need to run this command to update all the package dependencies.","title":"Description"},{"location":"newt/command_list/newt_version/","text":"newt version Allows you to query the version of newt installed in your application space. Usage: newt version [flags] Flags: -h, --help=false: help for version Global Flags: -l, --loglevel string Log level, defaults to WARN. (default \"WARN\") -o, --outfile string Filename to tee output to -q, --quiet Be quiet; only display error output. -s, --silent Be silent; don't output anything. -v, --verbose Enable verbose output when executing commands. Examples Sub-command Usage Explanation version newt version Displays the version of newt tool installed","title":"newt version"},{"location":"newt/command_list/newt_version/#newt-version","text":"Allows you to query the version of newt installed in your application space.","title":"newt version "},{"location":"newt/command_list/newt_version/#usage","text":"newt version [flags]","title":"Usage:"},{"location":"newt/command_list/newt_version/#flags","text":"-h, --help=false: help for version","title":"Flags:"},{"location":"newt/command_list/newt_version/#global-flags","text":"-l, --loglevel string Log level, defaults to WARN. (default \"WARN\") -o, --outfile string Filename to tee output to -q, --quiet Be quiet; only display error output. -s, --silent Be silent; don't output anything. -v, --verbose Enable verbose output when executing commands.","title":"Global Flags:"},{"location":"newt/command_list/newt_version/#examples","text":"Sub-command Usage Explanation version newt version Displays the version of newt tool installed","title":"Examples"},{"location":"newt/install/newt_linux/","text":"Install newt tool on Linux Getting your Linux box Ready If you want to build the newt tool from its source code, follow the following steps: 1. Install git, libcurl $ sudo apt-get install git $ sudo apt-get install libcurl4-gnutls-dev 2. Install Go, the programming language Go language environment dictates a directory structure. Known in Go parlanace as workspace, it must contain three sibling directories with the directory names src, pkg and bin, as explained below. src contains Go source files organized into packages (one package per directory), pkg contains package objects, and bin contains executable commands. The GOPATH environment variable specifies the location of your workspace. To setup this workspace environment, create a 'dev' directory and then a 'go' directory under it. Set the GOPATH environment variable to this directory where you will soon clone the newt tool repository. $ cd $HOME $ mkdir -p dev/go $ cd dev/go $ export GOPATH=`pwd` (Note that you need to add export statements to ~/.bash_profile to export variables permanently. Don't forget to source the file for the change to go into effect.) $ vi ~/.bash_profile $ source ~/.bash_profile Next, install Go. When installed, Go offers you as a developer a language environment (to compile Go code), construct Go packages (to assemble Go packages) and import Go code (from github). In the next step, you will use the Go commands to import newt repo into your local Go environment. Note : The Newt tool requires Go version 1.5 or later. It uses the support for \"vendoring\" that was added in Go 1.5. Depending on the Ubuntu version you have, the following may install an earlier version. In that case, download the latest package of Go 1.5 or 1.6 from https://golang.org/dl/ . You can search for more detailed instructions such as installing Go 1.6 on Ubuntu 14.04 which can be found at https://www.digitalocean.com/community/tutorials/how-to-install-go-1-6-on-ubuntu-14-04 . $ sudo apt-get install golang 3. Create local repository Use Go commands to copy the directory (currently the ASF incubator directory). Be patient as it may take a minute or two. Check the directories installed. $ go get mynewt.apache.org/newt/... Check that newt.go is in place. $ ls $GOPATH/src/mynewt.apache.org/newt DISCLAIMER NOTICE newt newtvm viper LICENSE README.md newtmgr util yaml 4. Build the Newt tool Use Go to run the newt.go program to build the newt tool. The command go install compiles and writes the resulting executable to an output file named newt , which is then installed, along with its dependencies, in $GOPATH/bin. If you get errors it is likely because of path resolution issues. Try go build followed by go install in that case. $ cd $GOPATH/src/mynewt.apache.org/newt/newt $ go install $ ls \"$GOPATH\"/bin/ newt newtmgr newtvm At this point, you can try using newt . For example, check for the version number by typing 'newt version'. See all the possible commands available to a user of newt by typing 'newt -h'. (Note: If you are going to be modifying the newt often and going to be compile the program every time you call it, you will want to store the command in a variable in your .bash_profile. So type in export newt=\"go run $GOPATH/mynewt.apache.org/newt/newt/newt.go\" in your .bash_profile and execute it by calling $newt at the prompt instead of newt . Essentially, $newt calls go run which runs the compiled binary directly without producing an executable. Don't forget to reload the updated bash profile by typing source ~/.bash_profile at the prompt! ) $ newt version Newt version: 1.0 $ newt -h Newt allows you to create your own embedded project based on the Mynewt operating system. Newt provides both build and package management in a single tool, which allows you to compose an embedded workspace, and set of projects, and then build the necessary artifacts from those projects. For more information on the Mynewt operating system, please visit https://www.github.com/mynewt/documentation. Please use the newt help command, and specify the name of the command you want help for, for help on how to use a specific command Usage: newt [flags] newt [command] Examples: newt newt help [<command-name>] For help on <command-name>. If not specified, print this message. Available Commands: version Display the Newt version number. target Set and view target information egg Commands to list and inspect eggs on a nest nest Commands to manage nests & clutches (remote egg repositories) help Help about any command Flags: -h, --help=false: help for newt -l, --loglevel=\"WARN\": Log level, defaults to WARN. -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands. Use \"newt help [command]\" for more information about a command.","title":"Install Newt on Linux"},{"location":"newt/install/newt_linux/#install-newt-tool-on-linux","text":"","title":"Install newt tool on Linux"},{"location":"newt/install/newt_linux/#getting-your-linux-box-ready","text":"If you want to build the newt tool from its source code, follow the following steps:","title":"Getting your Linux box Ready"},{"location":"newt/install/newt_linux/#1-install-git-libcurl","text":"$ sudo apt-get install git $ sudo apt-get install libcurl4-gnutls-dev","title":"1. Install git, libcurl"},{"location":"newt/install/newt_linux/#2-install-go-the-programming-language","text":"Go language environment dictates a directory structure. Known in Go parlanace as workspace, it must contain three sibling directories with the directory names src, pkg and bin, as explained below. src contains Go source files organized into packages (one package per directory), pkg contains package objects, and bin contains executable commands. The GOPATH environment variable specifies the location of your workspace. To setup this workspace environment, create a 'dev' directory and then a 'go' directory under it. Set the GOPATH environment variable to this directory where you will soon clone the newt tool repository. $ cd $HOME $ mkdir -p dev/go $ cd dev/go $ export GOPATH=`pwd` (Note that you need to add export statements to ~/.bash_profile to export variables permanently. Don't forget to source the file for the change to go into effect.) $ vi ~/.bash_profile $ source ~/.bash_profile Next, install Go. When installed, Go offers you as a developer a language environment (to compile Go code), construct Go packages (to assemble Go packages) and import Go code (from github). In the next step, you will use the Go commands to import newt repo into your local Go environment. Note : The Newt tool requires Go version 1.5 or later. It uses the support for \"vendoring\" that was added in Go 1.5. Depending on the Ubuntu version you have, the following may install an earlier version. In that case, download the latest package of Go 1.5 or 1.6 from https://golang.org/dl/ . You can search for more detailed instructions such as installing Go 1.6 on Ubuntu 14.04 which can be found at https://www.digitalocean.com/community/tutorials/how-to-install-go-1-6-on-ubuntu-14-04 . $ sudo apt-get install golang","title":"2. Install Go, the programming language"},{"location":"newt/install/newt_linux/#3-create-local-repository","text":"Use Go commands to copy the directory (currently the ASF incubator directory). Be patient as it may take a minute or two. Check the directories installed. $ go get mynewt.apache.org/newt/... Check that newt.go is in place. $ ls $GOPATH/src/mynewt.apache.org/newt DISCLAIMER NOTICE newt newtvm viper LICENSE README.md newtmgr util yaml","title":"3. Create local repository"},{"location":"newt/install/newt_linux/#4-build-the-newt-tool","text":"Use Go to run the newt.go program to build the newt tool. The command go install compiles and writes the resulting executable to an output file named newt , which is then installed, along with its dependencies, in $GOPATH/bin. If you get errors it is likely because of path resolution issues. Try go build followed by go install in that case. $ cd $GOPATH/src/mynewt.apache.org/newt/newt $ go install $ ls \"$GOPATH\"/bin/ newt newtmgr newtvm At this point, you can try using newt . For example, check for the version number by typing 'newt version'. See all the possible commands available to a user of newt by typing 'newt -h'. (Note: If you are going to be modifying the newt often and going to be compile the program every time you call it, you will want to store the command in a variable in your .bash_profile. So type in export newt=\"go run $GOPATH/mynewt.apache.org/newt/newt/newt.go\" in your .bash_profile and execute it by calling $newt at the prompt instead of newt . Essentially, $newt calls go run which runs the compiled binary directly without producing an executable. Don't forget to reload the updated bash profile by typing source ~/.bash_profile at the prompt! ) $ newt version Newt version: 1.0 $ newt -h Newt allows you to create your own embedded project based on the Mynewt operating system. Newt provides both build and package management in a single tool, which allows you to compose an embedded workspace, and set of projects, and then build the necessary artifacts from those projects. For more information on the Mynewt operating system, please visit https://www.github.com/mynewt/documentation. Please use the newt help command, and specify the name of the command you want help for, for help on how to use a specific command Usage: newt [flags] newt [command] Examples: newt newt help [<command-name>] For help on <command-name>. If not specified, print this message. Available Commands: version Display the Newt version number. target Set and view target information egg Commands to list and inspect eggs on a nest nest Commands to manage nests & clutches (remote egg repositories) help Help about any command Flags: -h, --help=false: help for newt -l, --loglevel=\"WARN\": Log level, defaults to WARN. -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands. Use \"newt help [command]\" for more information about a command.","title":"4. Build the Newt tool"},{"location":"newt/install/newt_mac/","text":"Install newt tool on your Mac Getting your Mac Ready If you want to build the newt tool from its source code, follow the following steps: 1. Install Homebrew on your Mac OS X Do you have Homebrew? If not, open a terminal on your Mac and paste the following at a Terminal prompt. It will ask you for your sudo password. $ ruby -e \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)\" Alternatively, you can just extract (or git clone ) Homebrew and install it to /usr/local . 2. Install Go, the programming language Go language environment dictates a directory structure. Known in Go parlanace as workspace, it must contain three sibling directories with the directory names src, pkg and bin, as explained below. src contains Go source files organized into packages (one package per directory), pkg contains package objects, and bin contains executable commands. The GOPATH environment variable specifies the location of your workspace. To setup this workspace environment, create a 'dev' directory and then a 'go' directory under it. Set the GOPATH environment variable to this directory where you will soon clone the newt tool repository. $ cd $HOME $ mkdir -p dev/go $ cd dev/go $ export GOPATH=`pwd` (Note that you need to add export statements to ~/.bash_profile to export variables permanently. Don't forget to source the file for the change to go into effect.) $ vi ~/.bash_profile $ source ~/.bash_profile Next, using brew , install Go. When installed, Go offers you as a developer a language environment (to compile Go code), construct Go packages (to assemble Go packages) and import Go code (from github). In the next step, you will use the Go commands to import newt repo into your local Go environment. $ brew install go ==> ... ... ==> *Summary* \ud83c\udf7a /usr/local/Cellar/go/1.5.1: 5330 files, 273M Alternatively, you can download the Go package directly from (https://golang.org/dl/) instead of brewing it. Install it in /usr/local directory. 3. Create local repository Use Go commands to copy the directory (currently the ASF incubator directory). Be patient as it may take a minute or two. Check the directories installed. $ go get mynewt.apache.org/newt/... Check that newt.go is in place. $ ls $GOPATH/src/mynewt.apache.org/newt DISCLAIMER NOTICE newt newtvm viper LICENSE README.md newtmgr util yaml 4. Build the Newt tool Use Go to run the newt.go program to build the newt tool. The command go install compiles and writes the resulting executable to an output file named newt , which is then installed, along with its dependencies, in $GOPATH/bin. $ cd $GOPATH/src/mynewt.apache.org/newt/newt $ go install $ ls \"$GOPATH\"/bin/ newt newtmgr newtvm At this point, you can try using newt . For example, check for the version number by typing 'newt version'. See all the possible commands available to a user of newt by typing 'newt -h'. (Note: If you are going to be modifying the newt often and going to be compile the program every time you call it, you will want to store the command in a variable in your .bash_profile. So type in export newt=\"go run $GOPATH/mynewt.apache.org/newt/newt/newt.go\" in your .bash_profile and execute it by calling $newt at the prompt instead of newt . Essentially, $newt calls go run which runs the compiled binary directly without producing an executable. Don't forget to reload the updated bash profile by typing source ~/.bash_profile at the prompt! ) $ newt version Newt version: 1.0 $ newt -h Newt allows you to create your own embedded project based on the Mynewt operating system. Newt provides both build and package management in a single tool, which allows you to compose an embedded workspace, and set of projects, and then build the necessary artifacts from those projects. For more information on the Mynewt operating system, please visit https://www.github.com/mynewt/documentation. Please use the newt help command, and specify the name of the command you want help for, for help on how to use a specific command Usage: newt [flags] newt [command] Examples: newt newt help [<command-name>] For help on <command-name>. If not specified, print this message. Available Commands: version Display the Newt version number. target Set and view target information egg Commands to list and inspect eggs on a nest nest Commands to manage nests & clutches (remote egg repositories) help Help about any command Flags: -h, --help=false: help for newt -l, --loglevel=\"WARN\": Log level, defaults to WARN. -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands. Use \"newt help [command]\" for more information about a command.","title":"Install Newt on Mac"},{"location":"newt/install/newt_mac/#install-newt-tool-on-your-mac","text":"","title":"Install newt tool on your Mac"},{"location":"newt/install/newt_mac/#getting-your-mac-ready","text":"If you want to build the newt tool from its source code, follow the following steps:","title":"Getting your Mac Ready"},{"location":"newt/install/newt_mac/#1-install-homebrew-on-your-mac-os-x","text":"Do you have Homebrew? If not, open a terminal on your Mac and paste the following at a Terminal prompt. It will ask you for your sudo password. $ ruby -e \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)\" Alternatively, you can just extract (or git clone ) Homebrew and install it to /usr/local .","title":"1. Install Homebrew on your Mac OS X"},{"location":"newt/install/newt_mac/#2-install-go-the-programming-language","text":"Go language environment dictates a directory structure. Known in Go parlanace as workspace, it must contain three sibling directories with the directory names src, pkg and bin, as explained below. src contains Go source files organized into packages (one package per directory), pkg contains package objects, and bin contains executable commands. The GOPATH environment variable specifies the location of your workspace. To setup this workspace environment, create a 'dev' directory and then a 'go' directory under it. Set the GOPATH environment variable to this directory where you will soon clone the newt tool repository. $ cd $HOME $ mkdir -p dev/go $ cd dev/go $ export GOPATH=`pwd` (Note that you need to add export statements to ~/.bash_profile to export variables permanently. Don't forget to source the file for the change to go into effect.) $ vi ~/.bash_profile $ source ~/.bash_profile Next, using brew , install Go. When installed, Go offers you as a developer a language environment (to compile Go code), construct Go packages (to assemble Go packages) and import Go code (from github). In the next step, you will use the Go commands to import newt repo into your local Go environment. $ brew install go ==> ... ... ==> *Summary* \ud83c\udf7a /usr/local/Cellar/go/1.5.1: 5330 files, 273M Alternatively, you can download the Go package directly from (https://golang.org/dl/) instead of brewing it. Install it in /usr/local directory.","title":"2. Install Go, the programming language"},{"location":"newt/install/newt_mac/#3-create-local-repository","text":"Use Go commands to copy the directory (currently the ASF incubator directory). Be patient as it may take a minute or two. Check the directories installed. $ go get mynewt.apache.org/newt/... Check that newt.go is in place. $ ls $GOPATH/src/mynewt.apache.org/newt DISCLAIMER NOTICE newt newtvm viper LICENSE README.md newtmgr util yaml","title":"3. Create local repository"},{"location":"newt/install/newt_mac/#4-build-the-newt-tool","text":"Use Go to run the newt.go program to build the newt tool. The command go install compiles and writes the resulting executable to an output file named newt , which is then installed, along with its dependencies, in $GOPATH/bin. $ cd $GOPATH/src/mynewt.apache.org/newt/newt $ go install $ ls \"$GOPATH\"/bin/ newt newtmgr newtvm At this point, you can try using newt . For example, check for the version number by typing 'newt version'. See all the possible commands available to a user of newt by typing 'newt -h'. (Note: If you are going to be modifying the newt often and going to be compile the program every time you call it, you will want to store the command in a variable in your .bash_profile. So type in export newt=\"go run $GOPATH/mynewt.apache.org/newt/newt/newt.go\" in your .bash_profile and execute it by calling $newt at the prompt instead of newt . Essentially, $newt calls go run which runs the compiled binary directly without producing an executable. Don't forget to reload the updated bash profile by typing source ~/.bash_profile at the prompt! ) $ newt version Newt version: 1.0 $ newt -h Newt allows you to create your own embedded project based on the Mynewt operating system. Newt provides both build and package management in a single tool, which allows you to compose an embedded workspace, and set of projects, and then build the necessary artifacts from those projects. For more information on the Mynewt operating system, please visit https://www.github.com/mynewt/documentation. Please use the newt help command, and specify the name of the command you want help for, for help on how to use a specific command Usage: newt [flags] newt [command] Examples: newt newt help [<command-name>] For help on <command-name>. If not specified, print this message. Available Commands: version Display the Newt version number. target Set and view target information egg Commands to list and inspect eggs on a nest nest Commands to manage nests & clutches (remote egg repositories) help Help about any command Flags: -h, --help=false: help for newt -l, --loglevel=\"WARN\": Log level, defaults to WARN. -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands. Use \"newt help [command]\" for more information about a command.","title":"4. Build the Newt tool"},{"location":"newtmgr/installing/","text":"Installing Newtmgr This page shows you how to install newtmgr from source code. Install Go (golang) If you have not already done so, install Go for your platform. The easiest way on a MAC is to use brew . brew install go ==> Downloading https://homebrew.bintray.com/bottles/go-1.5.3.mavericks.bottle.t ... ==> Summary \ud83c\udf7a /usr/local/Cellar/go/1.5.3: 5,336 files, 259.6M Alternatively, you can download binaries from the golang.org site To test your Go implementation, you can query Go for its version information $ go version go version go1.5.3 darwin/amd64 To use go, you must set a $GOPATH variable in your environment. This tells go where to put all the packages it downloads, builds and runs. $ mkdir $HOME/dev $ export GOPATH=$HOME/dev/Go Its best to add this to your .profile so its set automatically for your environment. Download the newtmgr source You will first download the source code for newt. go get mynewt.apache.org/newt/... (wait a few minutes please, this sits without any indications of working) Building newtmgr Change into the directory where the newmgr tool was downloaded and install the newtmgr tool cd $GOPATH/src/mynewt.apache.org/newt/newtmgr go install $ ls $GOPATH/bin ... newtmgr ... Note: If the go install command results in errors indicating some package cannot be found, do a go get to download all the third-party files needed from github.com and then run go install again. Add to your Path Add your $GOPATH/bin directory to your path.","title":"Install"},{"location":"newtmgr/installing/#installing-newtmgr","text":"This page shows you how to install newtmgr from source code.","title":"Installing Newtmgr"},{"location":"newtmgr/installing/#install-go-golang","text":"If you have not already done so, install Go for your platform. The easiest way on a MAC is to use brew . brew install go ==> Downloading https://homebrew.bintray.com/bottles/go-1.5.3.mavericks.bottle.t ... ==> Summary \ud83c\udf7a /usr/local/Cellar/go/1.5.3: 5,336 files, 259.6M Alternatively, you can download binaries from the golang.org site To test your Go implementation, you can query Go for its version information $ go version go version go1.5.3 darwin/amd64 To use go, you must set a $GOPATH variable in your environment. This tells go where to put all the packages it downloads, builds and runs. $ mkdir $HOME/dev $ export GOPATH=$HOME/dev/Go Its best to add this to your .profile so its set automatically for your environment.","title":"Install Go (golang)"},{"location":"newtmgr/installing/#download-the-newtmgr-source","text":"You will first download the source code for newt. go get mynewt.apache.org/newt/... (wait a few minutes please, this sits without any indications of working)","title":"Download the newtmgr source"},{"location":"newtmgr/installing/#building-newtmgr","text":"Change into the directory where the newmgr tool was downloaded and install the newtmgr tool cd $GOPATH/src/mynewt.apache.org/newt/newtmgr go install $ ls $GOPATH/bin ... newtmgr ... Note: If the go install command results in errors indicating some package cannot be found, do a go get to download all the third-party files needed from github.com and then run go install again.","title":"Building newtmgr"},{"location":"newtmgr/installing/#add-to-your-path","text":"Add your $GOPATH/bin directory to your path.","title":"Add to your Path"},{"location":"newtmgr/overview/","text":"Newt Manager Newt Manager (newtmgr) is the application tool that enables a user to communicate with and manage remote instances of Mynewt OS. Description Command List Available high-level commands help Lists commands and flags available conn Manage newtmgr connection profiles echo Send data to remote endpoint using newtmgr, and receive data back image Manage images on remote instance stat Read statistics from a remote endpoint taskstats Read statistics from a remote endpoint mpstats Read statistics from a remote endpoint config Read or write config value on target Available Flags -c, --connection string connection profile to use. -l, --loglevel string log level to use (default WARN.) Examples Sub-command Usage Explanation newtmgr -caditi03 taskstats help Usage: newtmgr help [input1] You can also use \"newtmgr [command] --help\" to display the help text for a newtmgr command. Flags: -c, --connection string connection profile to use. -l, --loglevel string log level to use (default WARN.) Examples Sub-command Available Flags Explanation taskstats newtmgr -cprofile1 taskstats Run the taskstats subcommand on the device connected via the 'profile1' connection conn Usage: newtmgr conn [flags] newtmgr conn [command] Available commands: add Add a newtmgr connection profile delete Delete a newtmgr connection profile show Show newtmgr connection profiles Flags: -c, --conn string connection profile to use. -l, --loglevel string log level to use (default WARN.) Description Sub-command Explanation add Adds a connection profile. A properly defined profile needs a name, a connection type, and the physical or virtual port to be used for communication. delete Deletes a connection profile associated with the given name show List the specified or all the connection profiles with the name, connection type, and the controlling terminal or port. Examples Sub-command Usage Explanation add newtmgr conn add myserial02 type=serial connstring=/dev/ttys002 Adds a newtmgr connection profile for the serial port /dev/ttys002 and names it 'myserial02' delete newtmgr conn delete myserial02 Deletes the connection profile named 'myserial02' show newtmgr conn show myserial01 Shows the details of the profile named 'myserial01' show newtmgr conn show Shows all the current profiles defined echo Usage: newtmgr echo [flags] [text] This command sends the text to the remote device at the other end of the connection specified with the -c flag and outputs the text when it gets a response from the device. If the device is not responding or if the connection profile is invalid it displays errors. Flags: -c, --conn string connection profile to use. -l, --loglevel string log level to use (default WARN.) Examples Sub-command Usage Explanation echo newtmgr echo -c profile01 hello Sends the string 'hello' to the remote device over the connection profile 'profile01' and receives the string back and displays it. image Usage: newtmgr image [flags] newtmgr image [command] Available commands: list Show target images upload Upload image to target boot Which image to boot fileupload Upload file to target filedownload Download file from target Flags: -c, --conn string connection profile to use. -l, --loglevel string log level to use (default WARN.) Description Sub-command Explanation list Adds a connection profile. A properly defined profile needs a name, a connection type, and the physical or virtual port to be used for communication. upload Deletes a connection profile associated with the given name boot Specify the image to boot fileupload upload file to the remote target filedownload download/retrieve file from remote target Examples Sub-command Usage Explanation list newtmgr list upload newtmgr upload boot newtmgr boot fileupload newtmgr fileupload filedownload newtmgr filedownload stat Usage: newtmgr stat [flags] newtmgr stat [command] Flags: -c, --conn string connection profile to use. -l, --loglevel string log level to use (default WARN.) Examples Sub-command Usage Explanation stat newtmgr stat taskstats Usage: newtmgr taskstats [flags] newtmgr taskstats [command] Lists all the tasks running on the remote endpoint at the end of the specified connection and for each task lists statistics such as priority, task id, runtime (how long the task has been running in ms), context switch count, stack size allocated, actual stack usage, last sanity checkin, next sanity check-in. Flags: -c, --conn string connection profile to use. -l, --loglevel string log level to use (default WARN.) Examples Sub-command Usage Explanation stat newtmgr taskstats -c profile01 Lists all the tasks running on the remote device at the end of connection named 'profile01' Example output $ newtmgr -c profile01 taskstats Return Code = 0 idle (prio=255 tid=0 runtime=3299340 cswcnt=280342 stksize=1024 stkusage=1000 last_checkin=0 next_checkin=0) os_sanity (prio=254 tid=1 runtime=0 cswcnt=3287 stksize=1024 stkusage=1000 last_checkin=0 next_checkin=0) shell (prio=3 tid=2 runtime=0 cswcnt=165 stksize=1024 stkusage=1000 last_checkin=0 next_checkin=0) uart_poller (prio=0 tid=3 runtime=0 cswcnt=279368 stksize=1024 stkusage=1000 last_checkin=0 next_checkin=0) newtmgr (prio=4 tid=4 runtime=0 cswcnt=14 stksize=1024 stkusage=1000 last_checkin=0 next_checkin=0) task1 (prio=1 tid=5 runtime=0 cswcnt=3287 stksize=1024 stkusage=1000 last_checkin=0 next_checkin=0) task2 (prio=2 tid=6 runtime=0 cswcnt=3287 stksize=1024 stkusage=1000 last_checkin=0 next_checkin=0)","title":"toc"},{"location":"newtmgr/overview/#newt-manager","text":"Newt Manager (newtmgr) is the application tool that enables a user to communicate with and manage remote instances of Mynewt OS.","title":"Newt Manager"},{"location":"newtmgr/overview/#description","text":"","title":"Description"},{"location":"newtmgr/overview/#command-list","text":"","title":"Command List"},{"location":"newtmgr/overview/#available-high-level-commands","text":"help Lists commands and flags available conn Manage newtmgr connection profiles echo Send data to remote endpoint using newtmgr, and receive data back image Manage images on remote instance stat Read statistics from a remote endpoint taskstats Read statistics from a remote endpoint mpstats Read statistics from a remote endpoint config Read or write config value on target","title":"Available high-level commands"},{"location":"newtmgr/overview/#available-flags","text":"-c, --connection string connection profile to use. -l, --loglevel string log level to use (default WARN.) Examples Sub-command Usage Explanation newtmgr -caditi03 taskstats","title":"Available Flags"},{"location":"newtmgr/overview/#help","text":"","title":"help"},{"location":"newtmgr/overview/#usage","text":"newtmgr help [input1] You can also use \"newtmgr [command] --help\" to display the help text for a newtmgr command. Flags: -c, --connection string connection profile to use. -l, --loglevel string log level to use (default WARN.) Examples Sub-command Available Flags Explanation taskstats newtmgr -cprofile1 taskstats Run the taskstats subcommand on the device connected via the 'profile1' connection","title":"Usage:"},{"location":"newtmgr/overview/#conn","text":"","title":"conn"},{"location":"newtmgr/overview/#usage_1","text":"newtmgr conn [flags] newtmgr conn [command] Available commands: add Add a newtmgr connection profile delete Delete a newtmgr connection profile show Show newtmgr connection profiles Flags: -c, --conn string connection profile to use. -l, --loglevel string log level to use (default WARN.) Description Sub-command Explanation add Adds a connection profile. A properly defined profile needs a name, a connection type, and the physical or virtual port to be used for communication. delete Deletes a connection profile associated with the given name show List the specified or all the connection profiles with the name, connection type, and the controlling terminal or port. Examples Sub-command Usage Explanation add newtmgr conn add myserial02 type=serial connstring=/dev/ttys002 Adds a newtmgr connection profile for the serial port /dev/ttys002 and names it 'myserial02' delete newtmgr conn delete myserial02 Deletes the connection profile named 'myserial02' show newtmgr conn show myserial01 Shows the details of the profile named 'myserial01' show newtmgr conn show Shows all the current profiles defined","title":"Usage:"},{"location":"newtmgr/overview/#echo","text":"","title":"echo"},{"location":"newtmgr/overview/#usage_2","text":"newtmgr echo [flags] [text] This command sends the text to the remote device at the other end of the connection specified with the -c flag and outputs the text when it gets a response from the device. If the device is not responding or if the connection profile is invalid it displays errors. Flags: -c, --conn string connection profile to use. -l, --loglevel string log level to use (default WARN.) Examples Sub-command Usage Explanation echo newtmgr echo -c profile01 hello Sends the string 'hello' to the remote device over the connection profile 'profile01' and receives the string back and displays it.","title":"Usage:"},{"location":"newtmgr/overview/#image","text":"","title":"image"},{"location":"newtmgr/overview/#usage_3","text":"newtmgr image [flags] newtmgr image [command] Available commands: list Show target images upload Upload image to target boot Which image to boot fileupload Upload file to target filedownload Download file from target Flags: -c, --conn string connection profile to use. -l, --loglevel string log level to use (default WARN.) Description Sub-command Explanation list Adds a connection profile. A properly defined profile needs a name, a connection type, and the physical or virtual port to be used for communication. upload Deletes a connection profile associated with the given name boot Specify the image to boot fileupload upload file to the remote target filedownload download/retrieve file from remote target Examples Sub-command Usage Explanation list newtmgr list upload newtmgr upload boot newtmgr boot fileupload newtmgr fileupload filedownload newtmgr filedownload","title":"Usage:"},{"location":"newtmgr/overview/#stat","text":"","title":"stat"},{"location":"newtmgr/overview/#usage_4","text":"newtmgr stat [flags] newtmgr stat [command] Flags: -c, --conn string connection profile to use. -l, --loglevel string log level to use (default WARN.) Examples Sub-command Usage Explanation stat newtmgr stat","title":"Usage:"},{"location":"newtmgr/overview/#taskstats","text":"","title":"taskstats"},{"location":"newtmgr/overview/#usage_5","text":"newtmgr taskstats [flags] newtmgr taskstats [command] Lists all the tasks running on the remote endpoint at the end of the specified connection and for each task lists statistics such as priority, task id, runtime (how long the task has been running in ms), context switch count, stack size allocated, actual stack usage, last sanity checkin, next sanity check-in. Flags: -c, --conn string connection profile to use. -l, --loglevel string log level to use (default WARN.) Examples Sub-command Usage Explanation stat newtmgr taskstats -c profile01 Lists all the tasks running on the remote device at the end of connection named 'profile01' Example output $ newtmgr -c profile01 taskstats Return Code = 0 idle (prio=255 tid=0 runtime=3299340 cswcnt=280342 stksize=1024 stkusage=1000 last_checkin=0 next_checkin=0) os_sanity (prio=254 tid=1 runtime=0 cswcnt=3287 stksize=1024 stkusage=1000 last_checkin=0 next_checkin=0) shell (prio=3 tid=2 runtime=0 cswcnt=165 stksize=1024 stkusage=1000 last_checkin=0 next_checkin=0) uart_poller (prio=0 tid=3 runtime=0 cswcnt=279368 stksize=1024 stkusage=1000 last_checkin=0 next_checkin=0) newtmgr (prio=4 tid=4 runtime=0 cswcnt=14 stksize=1024 stkusage=1000 last_checkin=0 next_checkin=0) task1 (prio=1 tid=5 runtime=0 cswcnt=3287 stksize=1024 stkusage=1000 last_checkin=0 next_checkin=0) task2 (prio=2 tid=6 runtime=0 cswcnt=3287 stksize=1024 stkusage=1000 last_checkin=0 next_checkin=0)","title":"Usage:"},{"location":"newtmgr/protocol/","text":"Newt Manager Protocol Description How it works","title":"Protocol"},{"location":"newtmgr/protocol/#newt-manager-protocol","text":"","title":"Newt Manager Protocol"},{"location":"newtmgr/protocol/#description","text":"","title":"Description"},{"location":"newtmgr/protocol/#how-it-works","text":"","title":"How it works"},{"location":"os/introduction/","text":"Introduction Welcome to Apache Mynewt Apache Mynewt is an operating system that makes it easy to develop applications for microcontroller environments where power and cost are driving factors. Examples of these devices are connected locks, lights, and wearables. Microcontroller environments have a number of characteristics that makes the operating system requirements for them unique: Low memory footprint: memory on these systems range from 8-16KB (on the low end) to 16MB (on the high end). Reduced code size: code often runs out of flash, and total available code size ranges from 64-128KB to 16-32MB. Low processing speed: processor speeds vary from 10-12MHz to 160-200MHz. Low power operation: devices operate in mostly sleeping mode, in order to conserve battery power and maximize power usage. As more and more devices get connected, these interconnected devices perform complex tasks. To perform these tasks, you need low-level operational functionality built into the operating system. Typically, connected devices built with these microcontrollers perform a myriad of functions: Networking Stacks: Bluetooth Low Energy and Thread Peripherals: PWM to drive motors, ADCs to measure sensor data, and RTCs to keep time. Scheduled Processing: actions must happen on a calendared or periodic basis. Apache Mynewt accomplishes all the above easily, by providing a complete operating system for constrained devices, including: A fully open-source Bluetooth Low Energy stack with both Host and Controller implementations. A pre-emptive, multi-tasking Real Time operating system kernel A Hardware Abstraction Layer (HAL) that abstracts the MCU's peripheral functions, allowing developers to easily write cross-platform code. Newt In order to provide all this functionality, and operate in an extremely low resource environment, Mynewt provides a very fine-grained source package management and build system tool, called newt . You can install and build newt for Linux or Mac . Newt Manager In order to enable a user to communicate with remote instances of Mynewt OS and query, configure, and operate them, Mynewt provides an application tool called Newt Manager or newtmgr . You can install and build newtmgr from source code on Linux or Mac . Build your first Mynewt App with Newt With the introductions out of the way, now is a good time to get set up and started with your first Mynewt application. Happy Hacking!","title":"toc"},{"location":"os/introduction/#introduction","text":"","title":"Introduction"},{"location":"os/introduction/#welcome-to-apache-mynewt","text":"Apache Mynewt is an operating system that makes it easy to develop applications for microcontroller environments where power and cost are driving factors. Examples of these devices are connected locks, lights, and wearables. Microcontroller environments have a number of characteristics that makes the operating system requirements for them unique: Low memory footprint: memory on these systems range from 8-16KB (on the low end) to 16MB (on the high end). Reduced code size: code often runs out of flash, and total available code size ranges from 64-128KB to 16-32MB. Low processing speed: processor speeds vary from 10-12MHz to 160-200MHz. Low power operation: devices operate in mostly sleeping mode, in order to conserve battery power and maximize power usage. As more and more devices get connected, these interconnected devices perform complex tasks. To perform these tasks, you need low-level operational functionality built into the operating system. Typically, connected devices built with these microcontrollers perform a myriad of functions: Networking Stacks: Bluetooth Low Energy and Thread Peripherals: PWM to drive motors, ADCs to measure sensor data, and RTCs to keep time. Scheduled Processing: actions must happen on a calendared or periodic basis. Apache Mynewt accomplishes all the above easily, by providing a complete operating system for constrained devices, including: A fully open-source Bluetooth Low Energy stack with both Host and Controller implementations. A pre-emptive, multi-tasking Real Time operating system kernel A Hardware Abstraction Layer (HAL) that abstracts the MCU's peripheral functions, allowing developers to easily write cross-platform code.","title":"Welcome to Apache Mynewt"},{"location":"os/introduction/#newt","text":"In order to provide all this functionality, and operate in an extremely low resource environment, Mynewt provides a very fine-grained source package management and build system tool, called newt . You can install and build newt for Linux or Mac .","title":"Newt"},{"location":"os/introduction/#newt-manager","text":"In order to enable a user to communicate with remote instances of Mynewt OS and query, configure, and operate them, Mynewt provides an application tool called Newt Manager or newtmgr . You can install and build newtmgr from source code on Linux or Mac .","title":"Newt Manager"},{"location":"os/introduction/#build-your-first-mynewt-app-with-newt","text":"With the introductions out of the way, now is a good time to get set up and started with your first Mynewt application. Happy Hacking!","title":"Build your first Mynewt App with Newt"},{"location":"os/os_user_guide/","text":"OS User Guide This guide provides comprehensive information about Mynewt OS, the real-time operating system for embedded systems. It is intended both for an embedded real-time software developer as well as higher-level applications developer wanting to understand the features and benefits of the system. Mynewt OS is highly composable and flexible. Only those features actually used by the application are compiled into the run-time image. Hence, the actual size of Mynewt is completely determined by the application. The guide covers all the features and services available in the OS and contains several examples showing how they can be used. Send us an email on the dev@ mailing list if you have comments or suggestions! If you haven't joined the mailing list, you will find the links here .","title":"toc"},{"location":"os/os_user_guide/#os-user-guide","text":"This guide provides comprehensive information about Mynewt OS, the real-time operating system for embedded systems. It is intended both for an embedded real-time software developer as well as higher-level applications developer wanting to understand the features and benefits of the system. Mynewt OS is highly composable and flexible. Only those features actually used by the application are compiled into the run-time image. Hence, the actual size of Mynewt is completely determined by the application. The guide covers all the features and services available in the OS and contains several examples showing how they can be used. Send us an email on the dev@ mailing list if you have comments or suggestions! If you haven't joined the mailing list, you will find the links here .","title":"OS User Guide"},{"location":"os/core_os/mynewt_os/","text":"Mynewt Core OS The Mynewt Core OS is a multitasking, preemptive real-time operating system combining a scheduler with typical RTOS features such as mutexes, semaphores, memory pools, etc. The Mynewt Core OS also provides a number of useful utilities such as a task watchdog, networking stack memory buffers and time management API. Each of these features is described in detail in its own section of the manual. A multitasking, preemptive operating system is one in which a number of different tasks can be instantiated and assigned a priority, with higher priority tasks running before lower priority tasks. Furthermore, if a lower priority task is running and a higher priority task wants to run, the lower priority task is halted and the higher priority task is allowed to run. In other words, the lower priority task is preempted by the higher priority task. Why use an OS? You may ask yourself \"why do I need a multitasking preemptive OS\"? The answer may indeed be that you do not. Some applications are simple and only require a polling loop. Others are more complex and may require that certain jobs are executed in a timely manner or before other jobs are executed. If you have a simple polling loop, you cannot move on to service a job until the current job is done being serviced. With the Mynewt OS, the application developer need not worry about certain jobs taking too long or not executing in a timely fashion; the OS provides mechanisms to deal with these situations. Another benefit of using an OS is that it helps shield application developers from other application code being written; the developer does not have to worry (or has to worry less) about other application code behaving badly and causing undesirable behavior or preventing their code from executing properly. Other benefits of using an OS (and the Mynewt OS in particular) is that it also provides features that the developer would otherwise need to create on his/her own. Core OS Features Scheduler/context switching Time Tasks Event queues/callouts Semaphores Mutexes Memory pools Heap Mbufs Sanity Callouts Porting OS to other platforms Basic OS Application Creation Creating an application using the Mynewt Core OS is a relatively simple task: once you have installed the basic Newt Tool structure (build structure) for your application and created your BSP (Board Support Package), the developer initializes the OS by calling os_init() , performs application specific initializations, and then starts the os by calling os_start() . The os_init() API performs two basic functions: calls architecture and bsp specific setup and initializes the idle task of the OS. This is required before the OS is started. The OS start API initializes the OS time tick interrupt and starts the highest priority task running (i.e starts the scheduler). Note that os_start() never returns; once called the device is either running in an application task context or in idle task context. Initializing application modules and tasks can get somewhat complicated with RTOS's similar to Mynewt. Care must be taken that the API provided by a task are initialized prior to being called by another (higher priority) task. For example, take a simple application with two tasks (tasks 1 and 2, with task 1 higher priority than task 2). Task 2 provides an API which has a semaphore lock and this semaphore is initialized by task 2 when the task handler for task 2 is called. Task 1 is expected to call this API. Consider the sequence of events when the OS is started. The scheduler starts running and picks the highest priority task (task 1 in this case). The task handler function for task 1 is called and will keep running until it yields execution. Before yielding, code in the task 1 handler function calls the API provided by task 2. The semaphore being accessed in the task 2 API has yet to be initialized since the task 2 handler function has not had a chance to run! This will lead to undesirable behavior and will need to be addressed by the application developer. Note that the Mynewt OS does guard against internal API being called before the OS has started (they will return error) but it does not safeguard application defined objects from access prior to initialization. Example One way to avoid initialization issues like the one described above is to perform task initializations prior to starting the OS. The code example shown below illustrates this concept. The application initializes the OS, calls an application specific \"task initialization\" function, and then starts the OS. The application task initialization function is responsible for initializing all the data objects that each task exposes to the other tasks. The tasks themselves are also initialized at this time (by calling os_task_init() ). In the example, each task works in a ping-pong like fashion: task 1 wakes up, adds a token to semaphore 1 and then waits for a token from semaphore 2. Task 2 waits for a token on semaphore 1 and once it gets it, adds a token to semaphore 2. Notice that the semaphores are initialized by the application specific task initialization functions and not inside the task handler functions. If task 2 (being lower in priority than task 1) had called os_sem_init() for task2_sem inside task2_handler(), task 1 would have called os_sem_pend() using task2_sem before task2_sem was initialized. /* Task 1 handler function */ void task1_handler(void *arg) { while (1) { /* Release semaphore to task 2 */ os_sem_release(&task1_sem); /* Wait for semaphore from task 2 */ os_sem_pend(&task2_sem, OS_TIMEOUT_NEVER); } } /* Task 2 handler function */ void task2_handler(void *arg) { struct os_task *t; while (1) { /* Wait for semaphore from task1 */ os_sem_pend(&task1_sem, OS_TIMEOUT_NEVER); /* Release task2 semaphore */ os_sem_release(&task2_sem); } } /* Initialize task 1 exposed data objects */ void task1_init(void) { /* Initialize task1 semaphore */ os_sem_init(&task1_sem, 0); } /* Initialize task 2 exposed data objects */ void task2_init(void) { /* Initialize task1 semaphore */ os_sem_init(&task2_sem, 0); } /** * init_app_tasks * * Called by main.c after os_init(). This function performs initializations * that are required before tasks are running. * * @return int 0 success; error otherwise. */ static int init_app_tasks(void) { /* * Initialize tasks 1 and 2. Note that the task handlers are not called yet; they will * be called when the OS is started. */ os_task_init(&task1, \"task1\", task1_handler, NULL, TASK1_PRIO, OS_WAIT_FOREVER, task1_stack, TASK1_STACK_SIZE); os_task_init(&task2, \"task2\", task2_handler, NULL, TASK2_PRIO, OS_WAIT_FOREVER, task2_stack, TASK2_STACK_SIZE); /* Call task specific initialization functions. */ task1_init(); task2_init(); return 0; } /** * main * * The main function for the application. This function initializes the os, calls * the application specific task initialization function. then starts the * OS. We should not return from os start! */ int main(void) { int i; int rc; uint32_t seed; /* Initialize OS */ os_init(); /* Initialize application specific tasks */ init_app_tasks(); /* Start the OS */ os_start(); /* os start should never return. If it does, this should be an error */ assert(0); return rc; } OS Functions The functions available at the OS level are: os_init os_start os_started","title":"toc"},{"location":"os/core_os/mynewt_os/#mynewt-core-os","text":"The Mynewt Core OS is a multitasking, preemptive real-time operating system combining a scheduler with typical RTOS features such as mutexes, semaphores, memory pools, etc. The Mynewt Core OS also provides a number of useful utilities such as a task watchdog, networking stack memory buffers and time management API. Each of these features is described in detail in its own section of the manual. A multitasking, preemptive operating system is one in which a number of different tasks can be instantiated and assigned a priority, with higher priority tasks running before lower priority tasks. Furthermore, if a lower priority task is running and a higher priority task wants to run, the lower priority task is halted and the higher priority task is allowed to run. In other words, the lower priority task is preempted by the higher priority task.","title":"Mynewt Core OS"},{"location":"os/core_os/mynewt_os/#why-use-an-os","text":"You may ask yourself \"why do I need a multitasking preemptive OS\"? The answer may indeed be that you do not. Some applications are simple and only require a polling loop. Others are more complex and may require that certain jobs are executed in a timely manner or before other jobs are executed. If you have a simple polling loop, you cannot move on to service a job until the current job is done being serviced. With the Mynewt OS, the application developer need not worry about certain jobs taking too long or not executing in a timely fashion; the OS provides mechanisms to deal with these situations. Another benefit of using an OS is that it helps shield application developers from other application code being written; the developer does not have to worry (or has to worry less) about other application code behaving badly and causing undesirable behavior or preventing their code from executing properly. Other benefits of using an OS (and the Mynewt OS in particular) is that it also provides features that the developer would otherwise need to create on his/her own.","title":"Why use an OS?"},{"location":"os/core_os/mynewt_os/#core-os-features","text":"Scheduler/context switching Time Tasks Event queues/callouts Semaphores Mutexes Memory pools Heap Mbufs Sanity Callouts Porting OS to other platforms","title":"Core OS Features"},{"location":"os/core_os/mynewt_os/#basic-os-application-creation","text":"Creating an application using the Mynewt Core OS is a relatively simple task: once you have installed the basic Newt Tool structure (build structure) for your application and created your BSP (Board Support Package), the developer initializes the OS by calling os_init() , performs application specific initializations, and then starts the os by calling os_start() . The os_init() API performs two basic functions: calls architecture and bsp specific setup and initializes the idle task of the OS. This is required before the OS is started. The OS start API initializes the OS time tick interrupt and starts the highest priority task running (i.e starts the scheduler). Note that os_start() never returns; once called the device is either running in an application task context or in idle task context. Initializing application modules and tasks can get somewhat complicated with RTOS's similar to Mynewt. Care must be taken that the API provided by a task are initialized prior to being called by another (higher priority) task. For example, take a simple application with two tasks (tasks 1 and 2, with task 1 higher priority than task 2). Task 2 provides an API which has a semaphore lock and this semaphore is initialized by task 2 when the task handler for task 2 is called. Task 1 is expected to call this API. Consider the sequence of events when the OS is started. The scheduler starts running and picks the highest priority task (task 1 in this case). The task handler function for task 1 is called and will keep running until it yields execution. Before yielding, code in the task 1 handler function calls the API provided by task 2. The semaphore being accessed in the task 2 API has yet to be initialized since the task 2 handler function has not had a chance to run! This will lead to undesirable behavior and will need to be addressed by the application developer. Note that the Mynewt OS does guard against internal API being called before the OS has started (they will return error) but it does not safeguard application defined objects from access prior to initialization.","title":"Basic OS Application Creation"},{"location":"os/core_os/mynewt_os/#example","text":"One way to avoid initialization issues like the one described above is to perform task initializations prior to starting the OS. The code example shown below illustrates this concept. The application initializes the OS, calls an application specific \"task initialization\" function, and then starts the OS. The application task initialization function is responsible for initializing all the data objects that each task exposes to the other tasks. The tasks themselves are also initialized at this time (by calling os_task_init() ). In the example, each task works in a ping-pong like fashion: task 1 wakes up, adds a token to semaphore 1 and then waits for a token from semaphore 2. Task 2 waits for a token on semaphore 1 and once it gets it, adds a token to semaphore 2. Notice that the semaphores are initialized by the application specific task initialization functions and not inside the task handler functions. If task 2 (being lower in priority than task 1) had called os_sem_init() for task2_sem inside task2_handler(), task 1 would have called os_sem_pend() using task2_sem before task2_sem was initialized. /* Task 1 handler function */ void task1_handler(void *arg) { while (1) { /* Release semaphore to task 2 */ os_sem_release(&task1_sem); /* Wait for semaphore from task 2 */ os_sem_pend(&task2_sem, OS_TIMEOUT_NEVER); } } /* Task 2 handler function */ void task2_handler(void *arg) { struct os_task *t; while (1) { /* Wait for semaphore from task1 */ os_sem_pend(&task1_sem, OS_TIMEOUT_NEVER); /* Release task2 semaphore */ os_sem_release(&task2_sem); } } /* Initialize task 1 exposed data objects */ void task1_init(void) { /* Initialize task1 semaphore */ os_sem_init(&task1_sem, 0); } /* Initialize task 2 exposed data objects */ void task2_init(void) { /* Initialize task1 semaphore */ os_sem_init(&task2_sem, 0); } /** * init_app_tasks * * Called by main.c after os_init(). This function performs initializations * that are required before tasks are running. * * @return int 0 success; error otherwise. */ static int init_app_tasks(void) { /* * Initialize tasks 1 and 2. Note that the task handlers are not called yet; they will * be called when the OS is started. */ os_task_init(&task1, \"task1\", task1_handler, NULL, TASK1_PRIO, OS_WAIT_FOREVER, task1_stack, TASK1_STACK_SIZE); os_task_init(&task2, \"task2\", task2_handler, NULL, TASK2_PRIO, OS_WAIT_FOREVER, task2_stack, TASK2_STACK_SIZE); /* Call task specific initialization functions. */ task1_init(); task2_init(); return 0; } /** * main * * The main function for the application. This function initializes the os, calls * the application specific task initialization function. then starts the * OS. We should not return from os start! */ int main(void) { int i; int rc; uint32_t seed; /* Initialize OS */ os_init(); /* Initialize application specific tasks */ init_app_tasks(); /* Start the OS */ os_start(); /* os start should never return. If it does, this should be an error */ assert(0); return rc; }","title":"Example"},{"location":"os/core_os/mynewt_os/#os-functions","text":"The functions available at the OS level are: os_init os_start os_started","title":"OS Functions"},{"location":"os/core_os/os_init/","text":"os_init void os_init(void) Initializes the OS. Must be called before the OS is started (i.e. os_start() is called). Arguments None Returned values None Notes The call to os_init performs architecture and bsp initializations and initializes the idle task. This function does not start the OS, the OS time tick interrupt, or the scheduler.","title":"os_init"},{"location":"os/core_os/os_init/#os_init","text":"void os_init(void) Initializes the OS. Must be called before the OS is started (i.e. os_start() is called).","title":"os_init"},{"location":"os/core_os/os_init/#arguments","text":"None","title":"Arguments"},{"location":"os/core_os/os_init/#returned-values","text":"None","title":"Returned values"},{"location":"os/core_os/os_init/#notes","text":"The call to os_init performs architecture and bsp initializations and initializes the idle task. This function does not start the OS, the OS time tick interrupt, or the scheduler.","title":"Notes"},{"location":"os/core_os/os_start/","text":"os_start void os_start(void) Starts the OS by initializing and enabling the OS time tick and starting the scheduler. This function does not return. Arguments None Returned values None (does not return). Notes Once os_start has been called, context is switched to the highest priority task that was initialized prior to calling os_start.","title":"os_start"},{"location":"os/core_os/os_start/#os_start","text":"void os_start(void) Starts the OS by initializing and enabling the OS time tick and starting the scheduler. This function does not return.","title":"os_start"},{"location":"os/core_os/os_start/#arguments","text":"None","title":"Arguments"},{"location":"os/core_os/os_start/#returned-values","text":"None (does not return).","title":"Returned values"},{"location":"os/core_os/os_start/#notes","text":"Once os_start has been called, context is switched to the highest priority task that was initialized prior to calling os_start.","title":"Notes"},{"location":"os/core_os/os_started/","text":"os_started int os_started(void) Returns 'true' (1) if the os has been started; 0 otherwise. Arguments None Returned values Integer value with 0 meaning the OS has not been started and 1 indicating the OS has been started (i.e. os_start() has been called).","title":"os_started"},{"location":"os/core_os/os_started/#os_started","text":"int os_started(void) Returns 'true' (1) if the os has been started; 0 otherwise.","title":"os_started"},{"location":"os/core_os/os_started/#arguments","text":"None","title":"Arguments"},{"location":"os/core_os/os_started/#returned-values","text":"Integer value with 0 meaning the OS has not been started and 1 indicating the OS has been started (i.e. os_start() has been called).","title":"Returned values"},{"location":"os/core_os/callout/callout/","text":"Callout Callouts are MyNewt OS timers. Description Callout is a way of setting up an OS timer. When the timer fires, it is delivered as an event to task's event queue. User would initialize their callout structure using os_callout_init() , or os_callout_func_init() and then arm it with os_callout_reset() . If user wants to cancel the timer before it expires, they can either use os_callout_reset() to arm it for later expiry, or stop it altogether by calling os_callout_stop() . There are 2 different options for data structure to use. First is struct os_callout , which is a bare-bones version. You would initialize this with os_callout_init() . Second option is struct os_callout_func . This you can use if you expect to have multiple different types of timers in your task, running concurrently. The structure contains a function pointer, and you would call that function from your task's event processing loop. Time unit when arming the timer is OS ticks. This rate of this ticker depends on the platform this is running on. You should use OS define OS_TICKS_PER_SEC to convert wallclock time to OS ticks. Callout timer fires out just once. For periodic timer type of operation you need to rearm it once it fires. Data structures struct os_callout { struct os_event c_ev; struct os_eventq *c_evq; uint32_t c_ticks; TAILQ_ENTRY(os_callout) c_next; }; Element Description c_ev Event structure of this callout c_evq Event queue where this callout is placed on timer expiry c_ticks OS tick amount when timer fires c_next Linkage to other unexpired callouts struct os_callout_func { struct os_callout cf_c; os_callout_func_t cf_func; void *cf_arg; }; Element Description cf_c struct os_callout. See above cf_func Function pointer which should be called by event queue processing cf_arg Generic void * argument to that function List of Functions The functions available in callout are: Function Description os_callout_func_init Initializes the given callout function struct. os_callout_init Initializes the given callout struct. os_callout_queued Checks whether the given callout has been armed. os_callout_reset Resets the callout to happen in the given number of OS ticks. os_callout_stop Disarms a timer.","title":"toc"},{"location":"os/core_os/callout/callout/#callout","text":"Callouts are MyNewt OS timers.","title":"Callout"},{"location":"os/core_os/callout/callout/#description","text":"Callout is a way of setting up an OS timer. When the timer fires, it is delivered as an event to task's event queue. User would initialize their callout structure using os_callout_init() , or os_callout_func_init() and then arm it with os_callout_reset() . If user wants to cancel the timer before it expires, they can either use os_callout_reset() to arm it for later expiry, or stop it altogether by calling os_callout_stop() . There are 2 different options for data structure to use. First is struct os_callout , which is a bare-bones version. You would initialize this with os_callout_init() . Second option is struct os_callout_func . This you can use if you expect to have multiple different types of timers in your task, running concurrently. The structure contains a function pointer, and you would call that function from your task's event processing loop. Time unit when arming the timer is OS ticks. This rate of this ticker depends on the platform this is running on. You should use OS define OS_TICKS_PER_SEC to convert wallclock time to OS ticks. Callout timer fires out just once. For periodic timer type of operation you need to rearm it once it fires.","title":"Description"},{"location":"os/core_os/callout/callout/#data-structures","text":"struct os_callout { struct os_event c_ev; struct os_eventq *c_evq; uint32_t c_ticks; TAILQ_ENTRY(os_callout) c_next; }; Element Description c_ev Event structure of this callout c_evq Event queue where this callout is placed on timer expiry c_ticks OS tick amount when timer fires c_next Linkage to other unexpired callouts struct os_callout_func { struct os_callout cf_c; os_callout_func_t cf_func; void *cf_arg; }; Element Description cf_c struct os_callout. See above cf_func Function pointer which should be called by event queue processing cf_arg Generic void * argument to that function","title":"Data structures"},{"location":"os/core_os/callout/callout/#list-of-functions","text":"The functions available in callout are: Function Description os_callout_func_init Initializes the given callout function struct. os_callout_init Initializes the given callout struct. os_callout_queued Checks whether the given callout has been armed. os_callout_reset Resets the callout to happen in the given number of OS ticks. os_callout_stop Disarms a timer.","title":"List of Functions"},{"location":"os/core_os/callout/os_callout_func_init/","text":"os_callout_func_init void os_callout_func_init(struct os_callout_func *cf, struct os_eventq *evq, os_callout_func_t timo_func, void *ev_arg) Initializes the given struct os_callout_func . Data structure is filled in with elements given as argument. Arguments Arguments Description cf Pointer to os_callout_func being initialized evq Event queue where this gets delivered to timo_func Timeout function. Event processing should call this ev_arg Generic argument for the event Returned values N/A Notes The same notes as with os_callout_init() . Example struct os_callout_func g_native_cputimer; struct os_eventq g_native_cputime_evq; void native_cputimer_cb(void *arg); /* Initialize the callout function */ os_callout_func_init(&g_native_cputimer, &g_native_cputime_evq, native_cputimer_cb, NULL);","title":"os_callout_func_init"},{"location":"os/core_os/callout/os_callout_func_init/#os_callout_func_init","text":"void os_callout_func_init(struct os_callout_func *cf, struct os_eventq *evq, os_callout_func_t timo_func, void *ev_arg) Initializes the given struct os_callout_func . Data structure is filled in with elements given as argument.","title":" os_callout_func_init "},{"location":"os/core_os/callout/os_callout_func_init/#arguments","text":"Arguments Description cf Pointer to os_callout_func being initialized evq Event queue where this gets delivered to timo_func Timeout function. Event processing should call this ev_arg Generic argument for the event","title":"Arguments"},{"location":"os/core_os/callout/os_callout_func_init/#returned-values","text":"N/A","title":"Returned values"},{"location":"os/core_os/callout/os_callout_func_init/#notes","text":"The same notes as with os_callout_init() .","title":"Notes"},{"location":"os/core_os/callout/os_callout_func_init/#example","text":"struct os_callout_func g_native_cputimer; struct os_eventq g_native_cputime_evq; void native_cputimer_cb(void *arg); /* Initialize the callout function */ os_callout_func_init(&g_native_cputimer, &g_native_cputime_evq, native_cputimer_cb, NULL);","title":"Example"},{"location":"os/core_os/callout/os_callout_init/","text":"os_callout_init void os_callout_init(struct os_callout *c, struct os_eventq *evq, void *ev_arg) Initializes struct os_callout . Event type will be set to OS_EVENT_T_TIMER . Arguments Arguments Description c Pointer to os_callout to initialize evq Event queue where this gets delivered to ev_arg Generic argument which is filled in for the event Returned values N/A Notes Be careful not to call this if the callout is armed, because that will mess up the list of pending callouts. Or if the timer has already fired, it will mess up the event queue where the callout was delivered to. Example struct os_eventq my_evq; struct os_callout my_callouts[8]; for (i = 0; i < 8; i++) { os_callout_init(&my_callouts[i], &my_evq, (void *)i); }","title":"os_callout_init"},{"location":"os/core_os/callout/os_callout_init/#os_callout_init","text":"void os_callout_init(struct os_callout *c, struct os_eventq *evq, void *ev_arg) Initializes struct os_callout . Event type will be set to OS_EVENT_T_TIMER .","title":"os_callout_init "},{"location":"os/core_os/callout/os_callout_init/#arguments","text":"Arguments Description c Pointer to os_callout to initialize evq Event queue where this gets delivered to ev_arg Generic argument which is filled in for the event","title":"Arguments"},{"location":"os/core_os/callout/os_callout_init/#returned-values","text":"N/A","title":"Returned values"},{"location":"os/core_os/callout/os_callout_init/#notes","text":"Be careful not to call this if the callout is armed, because that will mess up the list of pending callouts. Or if the timer has already fired, it will mess up the event queue where the callout was delivered to.","title":"Notes"},{"location":"os/core_os/callout/os_callout_init/#example","text":"struct os_eventq my_evq; struct os_callout my_callouts[8]; for (i = 0; i < 8; i++) { os_callout_init(&my_callouts[i], &my_evq, (void *)i); }","title":"Example"},{"location":"os/core_os/callout/os_callout_queued/","text":"os_callout_queued int os_callout_queued(struct os_callout *c) Tells whether the callout has been armed or not. Arguments Arguments Description c Pointer to callout being checked Returned values 0: timer is not armed non-zero: timer is armed","title":"os_callout_queued"},{"location":"os/core_os/callout/os_callout_queued/#os_callout_queued","text":"int os_callout_queued(struct os_callout *c) Tells whether the callout has been armed or not.","title":"os_callout_queued"},{"location":"os/core_os/callout/os_callout_queued/#arguments","text":"Arguments Description c Pointer to callout being checked","title":"Arguments"},{"location":"os/core_os/callout/os_callout_queued/#returned-values","text":"0: timer is not armed non-zero: timer is armed","title":"Returned values"},{"location":"os/core_os/callout/os_callout_reset/","text":"os_callout_reset void os_callout_reset(struct os_callout *c, int32_t timo) Resets the callout to happen timo in OS ticks. Arguments Arguments Description c Pointer to os_callout being reset timo OS ticks the timer is being set to Returned values N/A Notes Example /* Re-start the timer (run every 50 msecs) */ os_callout_reset(&g_bletest_timer.cf_c, OS_TICKS_PER_SEC / 20);","title":"os_callout_reset"},{"location":"os/core_os/callout/os_callout_reset/#os_callout_reset","text":"void os_callout_reset(struct os_callout *c, int32_t timo) Resets the callout to happen timo in OS ticks.","title":" os_callout_reset "},{"location":"os/core_os/callout/os_callout_reset/#arguments","text":"Arguments Description c Pointer to os_callout being reset timo OS ticks the timer is being set to","title":"Arguments"},{"location":"os/core_os/callout/os_callout_reset/#returned-values","text":"N/A","title":"Returned values"},{"location":"os/core_os/callout/os_callout_reset/#notes","text":"","title":"Notes"},{"location":"os/core_os/callout/os_callout_reset/#example","text":"/* Re-start the timer (run every 50 msecs) */ os_callout_reset(&g_bletest_timer.cf_c, OS_TICKS_PER_SEC / 20);","title":"Example"},{"location":"os/core_os/callout/os_callout_stop/","text":"os_callout_stop void os_callout_stop(struct os_callout *c) Disarms a timer. Arguments Arguments Description c Pointer to os_callout being stopped Returned values N/A Example struct os_callout_func g_native_cputimer; os_callout_stop(&g_native_cputimer.cf_c);","title":"os_callout_stop"},{"location":"os/core_os/callout/os_callout_stop/#os_callout_stop","text":"void os_callout_stop(struct os_callout *c) Disarms a timer.","title":" os_callout_stop "},{"location":"os/core_os/callout/os_callout_stop/#arguments","text":"Arguments Description c Pointer to os_callout being stopped","title":"Arguments"},{"location":"os/core_os/callout/os_callout_stop/#returned-values","text":"N/A","title":"Returned values"},{"location":"os/core_os/callout/os_callout_stop/#example","text":"struct os_callout_func g_native_cputimer; os_callout_stop(&g_native_cputimer.cf_c);","title":"Example"},{"location":"os/core_os/context_switch/context_switch/","text":"Scheduler/Context Switching Scheduler's job is to maintain the list of tasks and decide which one should be running next. Description Task states can be running , ready to run or sleeping . When task is running , CPU is executing in that task's context. The program counter (PC) is pointing to instructions task wants to execute and stack pointer (SP) is pointing to task's stack. Task which is ready to run wants to get on the CPU to do its work. Task which is sleeping has no more work to do. It's waiting for someone else to wake it up. Scheduler algorithm is simple: from among the tasks which are ready to run, pick the the one with highest priority (lowest numeric value in task's t_prio field), and make its state running . Tasks which are either running or ready to run are kept in linked list g_os_run_list . This list is ordered by priority. Tasks which are sleeping are kept in linked list g_os_sleep_list . Scheduler has a CPU architecture specific component; this code is responsible for swapping in the task which should be running . This process is called context switch. During context switching the state of the CPU (e.g. registers) for the currently running task is stored and the new task is swapped in. List of Functions The functions available in context_switch are: Function Description os_sched Performs context switch if needed. os_arch_ctx_sw Change the state of task given task to running . os_sched_ctx_sw_hook Performs task accounting when context switching. os_sched_get_current_task Returns the pointer to task which is currently running . os_sched_insert Insert task into scheduler's ready to run list. os_sched_next_task Returns the pointer to highest priority task from the list which are ready to run . os_sched_os_timer_exp Inform scheduler that OS time has moved forward. os_sched_resort Inform scheduler that the priority of the given task has changed and the ready to run list should be re-sorted. os_sched_set_current_task Sets the given task to running . os_sched_sleep The given task's state is changed from ready to run to sleeping . os_sched_wakeup Called to make task ready to run . If task is sleeping , it is woken up.","title":"toc"},{"location":"os/core_os/context_switch/context_switch/#schedulercontext-switching","text":"Scheduler's job is to maintain the list of tasks and decide which one should be running next.","title":"Scheduler/Context Switching"},{"location":"os/core_os/context_switch/context_switch/#description","text":"Task states can be running , ready to run or sleeping . When task is running , CPU is executing in that task's context. The program counter (PC) is pointing to instructions task wants to execute and stack pointer (SP) is pointing to task's stack. Task which is ready to run wants to get on the CPU to do its work. Task which is sleeping has no more work to do. It's waiting for someone else to wake it up. Scheduler algorithm is simple: from among the tasks which are ready to run, pick the the one with highest priority (lowest numeric value in task's t_prio field), and make its state running . Tasks which are either running or ready to run are kept in linked list g_os_run_list . This list is ordered by priority. Tasks which are sleeping are kept in linked list g_os_sleep_list . Scheduler has a CPU architecture specific component; this code is responsible for swapping in the task which should be running . This process is called context switch. During context switching the state of the CPU (e.g. registers) for the currently running task is stored and the new task is swapped in.","title":"Description"},{"location":"os/core_os/context_switch/context_switch/#list-of-functions","text":"The functions available in context_switch are: Function Description os_sched Performs context switch if needed. os_arch_ctx_sw Change the state of task given task to running . os_sched_ctx_sw_hook Performs task accounting when context switching. os_sched_get_current_task Returns the pointer to task which is currently running . os_sched_insert Insert task into scheduler's ready to run list. os_sched_next_task Returns the pointer to highest priority task from the list which are ready to run . os_sched_os_timer_exp Inform scheduler that OS time has moved forward. os_sched_resort Inform scheduler that the priority of the given task has changed and the ready to run list should be re-sorted. os_sched_set_current_task Sets the given task to running . os_sched_sleep The given task's state is changed from ready to run to sleeping . os_sched_wakeup Called to make task ready to run . If task is sleeping , it is woken up.","title":"List of Functions"},{"location":"os/core_os/context_switch/os_arch_ctx_sw/","text":"os_arch_ctx_sw void os_arch_ctx_sw(struct os_task *next_t) Change the state of task pointed by next_t to be running . Arguments Arguments Description next_t Pointer to task which must run next Returned values N/A Notes This would get called from another task's context. Example void os_sched ( struct os_task *next_t ) { os_sr_t sr ; OS_ENTER_CRITICAL ( sr ); if ( !next_t ) { next_t = os_sched_next_task (); } if ( next_t != g_current_task ) { os_arch_ctx_sw ( next_t ); } OS_EXIT_CRITICAL ( sr ); }","title":"os_arch_ctx_sw"},{"location":"os/core_os/context_switch/os_arch_ctx_sw/#os_arch_ctx_sw","text":"void os_arch_ctx_sw(struct os_task *next_t) Change the state of task pointed by next_t to be running .","title":" os_arch_ctx_sw "},{"location":"os/core_os/context_switch/os_arch_ctx_sw/#arguments","text":"Arguments Description next_t Pointer to task which must run next","title":"Arguments"},{"location":"os/core_os/context_switch/os_arch_ctx_sw/#returned-values","text":"N/A","title":"Returned values"},{"location":"os/core_os/context_switch/os_arch_ctx_sw/#notes","text":"This would get called from another task's context.","title":"Notes"},{"location":"os/core_os/context_switch/os_arch_ctx_sw/#example","text":"void os_sched ( struct os_task *next_t ) { os_sr_t sr ; OS_ENTER_CRITICAL ( sr ); if ( !next_t ) { next_t = os_sched_next_task (); } if ( next_t != g_current_task ) { os_arch_ctx_sw ( next_t ); } OS_EXIT_CRITICAL ( sr ); }","title":"Example"},{"location":"os/core_os/context_switch/os_sched/","text":"os_sched void os_sched ( struct os_task *next_t ) Performs context switch if needed. If next_t is set, that task will be made running . If next_t is NULL, highest priority ready to run is swapped in. This function can be called when new tasks were made ready to run or if the current task is moved to sleeping state. This function will call the architecture specific routine to swap in the new task. Arguments Arguments Description next_t Pointer to task which must run next (optional) Returned values N/A Notes Interrupts must be disabled when calling this. Example os_error_t os_mutex_release ( struct os_mutex *mu ) { ... OS_EXIT_CRITICAL ( sr ); /* Re-schedule if needed */ if ( resched ) { os_sched ( rdy ); } return OS_OK ; }","title":"os_sched"},{"location":"os/core_os/context_switch/os_sched/#os_sched","text":"void os_sched ( struct os_task *next_t ) Performs context switch if needed. If next_t is set, that task will be made running . If next_t is NULL, highest priority ready to run is swapped in. This function can be called when new tasks were made ready to run or if the current task is moved to sleeping state. This function will call the architecture specific routine to swap in the new task.","title":" os_sched "},{"location":"os/core_os/context_switch/os_sched/#arguments","text":"Arguments Description next_t Pointer to task which must run next (optional)","title":"Arguments"},{"location":"os/core_os/context_switch/os_sched/#returned-values","text":"N/A","title":"Returned values"},{"location":"os/core_os/context_switch/os_sched/#notes","text":"Interrupts must be disabled when calling this.","title":"Notes"},{"location":"os/core_os/context_switch/os_sched/#example","text":"os_error_t os_mutex_release ( struct os_mutex *mu ) { ... OS_EXIT_CRITICAL ( sr ); /* Re-schedule if needed */ if ( resched ) { os_sched ( rdy ); } return OS_OK ; }","title":"Example"},{"location":"os/core_os/context_switch/os_sched_ctx_sw_hook/","text":"os_sched_ctx_sw_hook void os_sched_ctx_sw_hook ( struct os_task *next_t ) Performs task accounting when context switching. This function must be called from the architecture specific context switching routine os_arch_ctx_sw() before resuming execution of the running task. Arguments N/A Returned values N/A Notes Example void os_arch_ctx_sw ( struct os_task *t ) { os_sched_ctx_sw_hook ( t ); /* Set PendSV interrupt pending bit to force context switch */ SCB->ICSR = SCB_ICSR_PENDSVSET_Msk ; }","title":"os_sched_ctx_sw_hook"},{"location":"os/core_os/context_switch/os_sched_ctx_sw_hook/#os_sched_ctx_sw_hook","text":"void os_sched_ctx_sw_hook ( struct os_task *next_t ) Performs task accounting when context switching. This function must be called from the architecture specific context switching routine os_arch_ctx_sw() before resuming execution of the running task.","title":" os_sched_ctx_sw_hook "},{"location":"os/core_os/context_switch/os_sched_ctx_sw_hook/#arguments","text":"N/A","title":"Arguments"},{"location":"os/core_os/context_switch/os_sched_ctx_sw_hook/#returned-values","text":"N/A","title":"Returned values"},{"location":"os/core_os/context_switch/os_sched_ctx_sw_hook/#notes","text":"","title":"Notes"},{"location":"os/core_os/context_switch/os_sched_ctx_sw_hook/#example","text":"void os_arch_ctx_sw ( struct os_task *t ) { os_sched_ctx_sw_hook ( t ); /* Set PendSV interrupt pending bit to force context switch */ SCB->ICSR = SCB_ICSR_PENDSVSET_Msk ; }","title":"Example"},{"location":"os/core_os/context_switch/os_sched_get_current_task/","text":"os_sched_get_current_task struct os_task *os_sched_get_current_task ( void ) Returns the pointer to task which is currently running . Arguments N/A Returned values See description. Notes Example void os_time_delay ( int32_t osticks ) { os_sr_t sr ; if ( osticks > 0 ) { OS_ENTER_CRITICAL ( sr ); os_sched_sleep ( os_sched_get_current_task (), ( os_time_t ) osticks ); OS_EXIT_CRITICAL ( sr ); os_sched ( NULL ); } }","title":"os_sched_get_current_task"},{"location":"os/core_os/context_switch/os_sched_get_current_task/#os_sched_get_current_task","text":"struct os_task *os_sched_get_current_task ( void ) Returns the pointer to task which is currently running .","title":" os_sched_get_current_task "},{"location":"os/core_os/context_switch/os_sched_get_current_task/#arguments","text":"N/A","title":"Arguments"},{"location":"os/core_os/context_switch/os_sched_get_current_task/#returned-values","text":"See description.","title":"Returned values"},{"location":"os/core_os/context_switch/os_sched_get_current_task/#notes","text":"","title":"Notes"},{"location":"os/core_os/context_switch/os_sched_get_current_task/#example","text":"void os_time_delay ( int32_t osticks ) { os_sr_t sr ; if ( osticks > 0 ) { OS_ENTER_CRITICAL ( sr ); os_sched_sleep ( os_sched_get_current_task (), ( os_time_t ) osticks ); OS_EXIT_CRITICAL ( sr ); os_sched ( NULL ); } }","title":"Example"},{"location":"os/core_os/context_switch/os_sched_insert/","text":"os_sched_insert os_error_t os_sched_insert ( struct os_task *t ) Insert task into scheduler's ready to run list. Arguments Arguments Description t Pointer to task Returned values Returns OS_EINVAL if task state is not READY . Returns 0 on success. Notes You probably don't need to call this.","title":"os_sched_insert"},{"location":"os/core_os/context_switch/os_sched_insert/#os_sched_insert","text":"os_error_t os_sched_insert ( struct os_task *t ) Insert task into scheduler's ready to run list.","title":" os_sched_insert "},{"location":"os/core_os/context_switch/os_sched_insert/#arguments","text":"Arguments Description t Pointer to task","title":"Arguments"},{"location":"os/core_os/context_switch/os_sched_insert/#returned-values","text":"Returns OS_EINVAL if task state is not READY . Returns 0 on success.","title":"Returned values"},{"location":"os/core_os/context_switch/os_sched_insert/#notes","text":"You probably don't need to call this.","title":"Notes"},{"location":"os/core_os/context_switch/os_sched_next_task/","text":"os_sched_next_task struct os_task *os_sched_next_task ( void ) Returns the pointer to highest priority task from the list which are ready to run . Arguments N/A Returned values See description. Notes Should be called with interrupts disabled.","title":"os_sched_next_task"},{"location":"os/core_os/context_switch/os_sched_next_task/#os_sched_next_task","text":"struct os_task *os_sched_next_task ( void ) Returns the pointer to highest priority task from the list which are ready to run .","title":" os_sched_next_task "},{"location":"os/core_os/context_switch/os_sched_next_task/#arguments","text":"N/A","title":"Arguments"},{"location":"os/core_os/context_switch/os_sched_next_task/#returned-values","text":"See description.","title":"Returned values"},{"location":"os/core_os/context_switch/os_sched_next_task/#notes","text":"Should be called with interrupts disabled.","title":"Notes"},{"location":"os/core_os/context_switch/os_sched_os_timer_exp/","text":"os_sched_os_timer_exp void os_sched_os_timer_exp ( void ) Inform scheduler that OS time has moved forward, and it should inspect tasks which are sleeping to check whether they should be moved to g_run_list or not. This function should be called from code which handles moving OS time forward. After calling it, the highest priority task which is ready to run might've changed, so call to os_sched() should be done. Arguments N/A Returned values N/A Notes Example void timer_handler ( void ) { os_time_tick (); os_callout_tick (); os_sched_os_timer_exp (); os_sched ( NULL ); }","title":"os_sched_os_timer_exp"},{"location":"os/core_os/context_switch/os_sched_os_timer_exp/#os_sched_os_timer_exp","text":"void os_sched_os_timer_exp ( void ) Inform scheduler that OS time has moved forward, and it should inspect tasks which are sleeping to check whether they should be moved to g_run_list or not. This function should be called from code which handles moving OS time forward. After calling it, the highest priority task which is ready to run might've changed, so call to os_sched() should be done.","title":" os_sched_os_timer_exp "},{"location":"os/core_os/context_switch/os_sched_os_timer_exp/#arguments","text":"N/A","title":"Arguments"},{"location":"os/core_os/context_switch/os_sched_os_timer_exp/#returned-values","text":"N/A","title":"Returned values"},{"location":"os/core_os/context_switch/os_sched_os_timer_exp/#notes","text":"","title":"Notes"},{"location":"os/core_os/context_switch/os_sched_os_timer_exp/#example","text":"void timer_handler ( void ) { os_time_tick (); os_callout_tick (); os_sched_os_timer_exp (); os_sched ( NULL ); }","title":"Example"},{"location":"os/core_os/context_switch/os_sched_resort/","text":"os_sched_resort void os_sched_resort ( struct os_task *t ) Inform scheduler that the priority of the task t has changed (e.g. in order to avoid priority inversion), and the ready to run list should be re-sorted. Arguments Arguments Description t Pointer to a task whose priority has changed Returned values N/A Notes t must be ready to run before calling this. Example os_error_t os_mutex_pend ( struct os_mutex *mu , uint32_t timeout ) { .... /* Change priority of owner if needed */ if ( mu->mu_owner->t_prio > current->t_prio ) { mu->mu_owner->t_prio = current->t_prio ; os_sched_resort ( mu->mu_owner ); } .... }","title":"os_sched_resort"},{"location":"os/core_os/context_switch/os_sched_resort/#os_sched_resort","text":"void os_sched_resort ( struct os_task *t ) Inform scheduler that the priority of the task t has changed (e.g. in order to avoid priority inversion), and the ready to run list should be re-sorted.","title":" os_sched_resort "},{"location":"os/core_os/context_switch/os_sched_resort/#arguments","text":"Arguments Description t Pointer to a task whose priority has changed","title":"Arguments"},{"location":"os/core_os/context_switch/os_sched_resort/#returned-values","text":"N/A","title":"Returned values"},{"location":"os/core_os/context_switch/os_sched_resort/#notes","text":"t must be ready to run before calling this.","title":"Notes"},{"location":"os/core_os/context_switch/os_sched_resort/#example","text":"os_error_t os_mutex_pend ( struct os_mutex *mu , uint32_t timeout ) { .... /* Change priority of owner if needed */ if ( mu->mu_owner->t_prio > current->t_prio ) { mu->mu_owner->t_prio = current->t_prio ; os_sched_resort ( mu->mu_owner ); } .... }","title":"Example"},{"location":"os/core_os/context_switch/os_sched_set_current_task/","text":"os_sched_set_current_task void os_sched_set_current_task ( struct os_task *t ) Sets the currently running task to 't'. This is called from architecture specific context switching code to update scheduler state. Call is made when state of the task 't' is made running . Arguments Arguments Description t Pointer to a task Returned values N/A Notes This function simply sets the global variable holding the currently running task. It does not perform a context switch or change the os run or sleep list.","title":"os_sched_set_current_task"},{"location":"os/core_os/context_switch/os_sched_set_current_task/#os_sched_set_current_task","text":"void os_sched_set_current_task ( struct os_task *t ) Sets the currently running task to 't'. This is called from architecture specific context switching code to update scheduler state. Call is made when state of the task 't' is made running .","title":" os_sched_set_current_task "},{"location":"os/core_os/context_switch/os_sched_set_current_task/#arguments","text":"Arguments Description t Pointer to a task","title":"Arguments"},{"location":"os/core_os/context_switch/os_sched_set_current_task/#returned-values","text":"N/A","title":"Returned values"},{"location":"os/core_os/context_switch/os_sched_set_current_task/#notes","text":"This function simply sets the global variable holding the currently running task. It does not perform a context switch or change the os run or sleep list.","title":"Notes"},{"location":"os/core_os/context_switch/os_sched_sleep/","text":"os_sched_sleep int os_sched_sleep ( struct os_task *t , os_time_t nticks ) Task 't' state is changed from ready to run to sleeping . Sleep time will be specified in nticks . Task will be woken up after sleep timer expires, unless there are other signals causing it to wake up. If nticks is set to OS_TIMEOUT_NEVER , task never wakes up with a sleep timer. Arguments Arguments Description t Pointer to task nticks Number of ticks to sleep in OS ticks Returned values Returns 0 on success. Notes Must be called with interrupts disabled. Example struct os_event * os_eventq_get ( struct os_eventq *evq ) { struct os_event *ev ; os_sr_t sr ; OS_ENTER_CRITICAL ( sr ); pull_one : ev = STAILQ_FIRST ( &evq->evq_list ); if ( ev ) { STAILQ_REMOVE ( &evq->evq_list , ev , os_event , ev_next ); ev->ev_queued = 0 ; } else { evq->evq_task = os_sched_get_current_task (); os_sched_sleep ( evq->evq_task , OS_TIMEOUT_NEVER ); OS_EXIT_CRITICAL ( sr ); os_sched ( NULL ); OS_ENTER_CRITICAL ( sr ); evq->evq_task = NULL ; goto pull_one ; } OS_EXIT_CRITICAL ( sr ); return ( ev ); }","title":"os_sched_sleep"},{"location":"os/core_os/context_switch/os_sched_sleep/#os_sched_sleep","text":"int os_sched_sleep ( struct os_task *t , os_time_t nticks ) Task 't' state is changed from ready to run to sleeping . Sleep time will be specified in nticks . Task will be woken up after sleep timer expires, unless there are other signals causing it to wake up. If nticks is set to OS_TIMEOUT_NEVER , task never wakes up with a sleep timer.","title":" os_sched_sleep "},{"location":"os/core_os/context_switch/os_sched_sleep/#arguments","text":"Arguments Description t Pointer to task nticks Number of ticks to sleep in OS ticks","title":"Arguments"},{"location":"os/core_os/context_switch/os_sched_sleep/#returned-values","text":"Returns 0 on success.","title":"Returned values"},{"location":"os/core_os/context_switch/os_sched_sleep/#notes","text":"Must be called with interrupts disabled.","title":"Notes"},{"location":"os/core_os/context_switch/os_sched_sleep/#example","text":"struct os_event * os_eventq_get ( struct os_eventq *evq ) { struct os_event *ev ; os_sr_t sr ; OS_ENTER_CRITICAL ( sr ); pull_one : ev = STAILQ_FIRST ( &evq->evq_list ); if ( ev ) { STAILQ_REMOVE ( &evq->evq_list , ev , os_event , ev_next ); ev->ev_queued = 0 ; } else { evq->evq_task = os_sched_get_current_task (); os_sched_sleep ( evq->evq_task , OS_TIMEOUT_NEVER ); OS_EXIT_CRITICAL ( sr ); os_sched ( NULL ); OS_ENTER_CRITICAL ( sr ); evq->evq_task = NULL ; goto pull_one ; } OS_EXIT_CRITICAL ( sr ); return ( ev ); }","title":"Example"},{"location":"os/core_os/context_switch/os_sched_wakeup/","text":"os_sched_wakeup int os_sched_wakeup ( struct os_task *t ) Called to make task ready to run . If task is sleeping , it is woken up. Arguments Arguments Description t Pointer to task Returned values Returns 0 on success. Notes Example void os_eventq_put ( struct os_eventq *evq , struct os_event *ev ) { .... /* If task waiting on event, wake it up. */ resched = 0 ; if ( evq->evq_task ) { os_sched_wakeup ( evq->evq_task ); evq->evq_task = NULL ; resched = 1 ; } .... }","title":"os_sched_wakeup"},{"location":"os/core_os/context_switch/os_sched_wakeup/#os_sched_wakeup","text":"int os_sched_wakeup ( struct os_task *t ) Called to make task ready to run . If task is sleeping , it is woken up.","title":" os_sched_wakeup "},{"location":"os/core_os/context_switch/os_sched_wakeup/#arguments","text":"Arguments Description t Pointer to task","title":"Arguments"},{"location":"os/core_os/context_switch/os_sched_wakeup/#returned-values","text":"Returns 0 on success.","title":"Returned values"},{"location":"os/core_os/context_switch/os_sched_wakeup/#notes","text":"","title":"Notes"},{"location":"os/core_os/context_switch/os_sched_wakeup/#example","text":"void os_eventq_put ( struct os_eventq *evq , struct os_event *ev ) { .... /* If task waiting on event, wake it up. */ resched = 0 ; if ( evq->evq_task ) { os_sched_wakeup ( evq->evq_task ); evq->evq_task = NULL ; resched = 1 ; } .... }","title":"Example"},{"location":"os/core_os/event_queue/event_queue/","text":"Event Queues Event queue is a way of serializing events arring to a task. This makes it easy to queue processing to happen inside task's context. This would be done either from an interrupt handler, or from another task. Events arrive in a form of a data structure struct os_event . Description Events are in form of a data structure struct os_event , and they are queued to data structure struct os_eventq . Queue must be initialized before trying to add events to it. This is done using os_eventq_init() . Common way of using event queues is to have a task loop while calling os_eventq_get() , waiting for work to do. Other tasks (or interrupts) then call os_eventq_put() to wake it up. Once event has been queued task waiting on that queue is woken up, and will get a pointer to queued event structure. Processing task would then act according to event type. When os_event is queued, it should not be freed until processing task is done with it. It is assumed that there is only one task consuming events from an event queue. Only one task should be sleeping on a particular os_eventq at a time. Note that os_callout subsystem assumes that event queue is used as the wakeup mechanism. Data structures struct os_event { uint8_t ev_queued ; uint8_t ev_type ; void *ev_arg ; STAILQ_ENTRY ( os_event ) ev_next ; }; Element Description ev_queued Internal field, which tells whether event is linked into an os_eventq already ev_type Type of an event. This should be unique, as it should be used by processing task to figure out what the event means ev_arg Can be used further as input to task processing this event ev_next Linkage attaching this event to an event queue struct os_eventq { struct os_task *evq_task ; STAILQ_HEAD (, os_event ) evq_list ; }; Element Description evq_task Pointer to task if there is task sleeping on os_eventq_get() evq_list Queue head for list of events in this queue List of Functions The functions available in event queue feature are: Function Description os_eventq_get Fetches the first event from a queue. Task will sleep until something gets queued. os_eventq_init Initializes the given event queue, making it ready for use. os_eventq_put Queues an event to tail of the event queue. os_eventq_remove Removes an event which has been placed in a queue.","title":"toc"},{"location":"os/core_os/event_queue/event_queue/#event-queues","text":"Event queue is a way of serializing events arring to a task. This makes it easy to queue processing to happen inside task's context. This would be done either from an interrupt handler, or from another task. Events arrive in a form of a data structure struct os_event .","title":"Event Queues"},{"location":"os/core_os/event_queue/event_queue/#description","text":"Events are in form of a data structure struct os_event , and they are queued to data structure struct os_eventq . Queue must be initialized before trying to add events to it. This is done using os_eventq_init() . Common way of using event queues is to have a task loop while calling os_eventq_get() , waiting for work to do. Other tasks (or interrupts) then call os_eventq_put() to wake it up. Once event has been queued task waiting on that queue is woken up, and will get a pointer to queued event structure. Processing task would then act according to event type. When os_event is queued, it should not be freed until processing task is done with it. It is assumed that there is only one task consuming events from an event queue. Only one task should be sleeping on a particular os_eventq at a time. Note that os_callout subsystem assumes that event queue is used as the wakeup mechanism.","title":"Description"},{"location":"os/core_os/event_queue/event_queue/#data-structures","text":"struct os_event { uint8_t ev_queued ; uint8_t ev_type ; void *ev_arg ; STAILQ_ENTRY ( os_event ) ev_next ; }; Element Description ev_queued Internal field, which tells whether event is linked into an os_eventq already ev_type Type of an event. This should be unique, as it should be used by processing task to figure out what the event means ev_arg Can be used further as input to task processing this event ev_next Linkage attaching this event to an event queue struct os_eventq { struct os_task *evq_task ; STAILQ_HEAD (, os_event ) evq_list ; }; Element Description evq_task Pointer to task if there is task sleeping on os_eventq_get() evq_list Queue head for list of events in this queue","title":"Data structures"},{"location":"os/core_os/event_queue/event_queue/#list-of-functions","text":"The functions available in event queue feature are: Function Description os_eventq_get Fetches the first event from a queue. Task will sleep until something gets queued. os_eventq_init Initializes the given event queue, making it ready for use. os_eventq_put Queues an event to tail of the event queue. os_eventq_remove Removes an event which has been placed in a queue.","title":"List of Functions"},{"location":"os/core_os/event_queue/os_eventq_dflt_get/","text":"os_eventq_dflt_get struct os_eventq *os_eventq_dflt_get ( void ) Get the default event queue that was set Arguments None Returned values struct os_eventq * A pointer to the default event queue, if set. Notes None Example This checks the default event queue and sets it if not already set. struct os_eventq g_my_evq ; int event_q_check () { if ( os_eventq_dflt_get () == NULL ) { os_eventq_dflt_set ( g_my_evq ); } }","title":"Os eventq dflt get"},{"location":"os/core_os/event_queue/os_eventq_dflt_get/#os_eventq_dflt_get","text":"struct os_eventq *os_eventq_dflt_get ( void ) Get the default event queue that was set","title":" os_eventq_dflt_get"},{"location":"os/core_os/event_queue/os_eventq_dflt_get/#arguments","text":"None","title":"Arguments"},{"location":"os/core_os/event_queue/os_eventq_dflt_get/#returned-values","text":"struct os_eventq * A pointer to the default event queue, if set.","title":"Returned values"},{"location":"os/core_os/event_queue/os_eventq_dflt_get/#notes","text":"None","title":"Notes"},{"location":"os/core_os/event_queue/os_eventq_dflt_get/#example","text":"This checks the default event queue and sets it if not already set. struct os_eventq g_my_evq ; int event_q_check () { if ( os_eventq_dflt_get () == NULL ) { os_eventq_dflt_set ( g_my_evq ); } }","title":"Example"},{"location":"os/core_os/event_queue/os_eventq_dflt_set/","text":"os_eventq_dflt_set void os_eventq_dflt_set ( struct os_eventq *evq ) Sets struct os_eventq as the default event queue Arguments Arguments Description evq Pointer to default event queue to use Returned values None Notes Usually done at subsystem init time; before OS has been started, and before interrupts generating events have been enabled. Example This sets the default event queue used by newtmgr task. struct os_eventq g_nmgr_evq ; int nmgr_task_init ( uint8_t prio , os_stack_t *stack_ptr , uint16_t stack_len ) { /* variable declarations here */ os_eventq_init ( &g_nmgr_evq ); os_eventq_dflt_set ( &g_nmgr_evq ); /* initialization continues here */ }","title":"Os eventq dflt set"},{"location":"os/core_os/event_queue/os_eventq_dflt_set/#os_eventq_dflt_set","text":"void os_eventq_dflt_set ( struct os_eventq *evq ) Sets struct os_eventq as the default event queue","title":" os_eventq_dflt_set"},{"location":"os/core_os/event_queue/os_eventq_dflt_set/#arguments","text":"Arguments Description evq Pointer to default event queue to use","title":"Arguments"},{"location":"os/core_os/event_queue/os_eventq_dflt_set/#returned-values","text":"None","title":"Returned values"},{"location":"os/core_os/event_queue/os_eventq_dflt_set/#notes","text":"Usually done at subsystem init time; before OS has been started, and before interrupts generating events have been enabled.","title":"Notes"},{"location":"os/core_os/event_queue/os_eventq_dflt_set/#example","text":"This sets the default event queue used by newtmgr task. struct os_eventq g_nmgr_evq ; int nmgr_task_init ( uint8_t prio , os_stack_t *stack_ptr , uint16_t stack_len ) { /* variable declarations here */ os_eventq_init ( &g_nmgr_evq ); os_eventq_dflt_set ( &g_nmgr_evq ); /* initialization continues here */ }","title":"Example"},{"location":"os/core_os/event_queue/os_eventq_get/","text":"os_eventq_get void os_eventq_get ( struct os_eventq *evq ) Fetches the first event from a queue. Task will sleep until something gets queued. Arguments Arguments Description evq Queue to wait on Returned values Will return with a pointer to first struct event which is in the queue. Notes Example Main loop of an example task. while ( 1 ) { ev = os_eventq_get ( &task1_evq ); assert ( ev ); if ( ev->ev_type == CONS_EV_TYPE ) { /* XXX do stuff */ } }","title":"os_eventq_get"},{"location":"os/core_os/event_queue/os_eventq_get/#os_eventq_get","text":"void os_eventq_get ( struct os_eventq *evq ) Fetches the first event from a queue. Task will sleep until something gets queued.","title":" os_eventq_get"},{"location":"os/core_os/event_queue/os_eventq_get/#arguments","text":"Arguments Description evq Queue to wait on","title":"Arguments"},{"location":"os/core_os/event_queue/os_eventq_get/#returned-values","text":"Will return with a pointer to first struct event which is in the queue.","title":"Returned values"},{"location":"os/core_os/event_queue/os_eventq_get/#notes","text":"","title":"Notes"},{"location":"os/core_os/event_queue/os_eventq_get/#example","text":"Main loop of an example task. while ( 1 ) { ev = os_eventq_get ( &task1_evq ); assert ( ev ); if ( ev->ev_type == CONS_EV_TYPE ) { /* XXX do stuff */ } }","title":"Example"},{"location":"os/core_os/event_queue/os_eventq_init/","text":"os_eventq_init void os_eventq_init ( struct os_eventq *evq ) Initializes struct os_eventq , making it ready for use. Arguments Arguments Description evq Pointer to event queue getting initialized Returned values None Notes Usually done at subsystem init time; before OS has been started, and before interrupts generating events have been enabled. Example This initializes event queue used by newtmgr task. struct os_eventq g_nmgr_evq ; int nmgr_task_init ( uint8_t prio , os_stack_t *stack_ptr , uint16_t stack_len ) { /* variable declarations here */ os_eventq_init ( &g_nmgr_evq ); /* initialization continues here */ }","title":"os_eventq_init"},{"location":"os/core_os/event_queue/os_eventq_init/#os_eventq_init","text":"void os_eventq_init ( struct os_eventq *evq ) Initializes struct os_eventq , making it ready for use.","title":" os_eventq_init"},{"location":"os/core_os/event_queue/os_eventq_init/#arguments","text":"Arguments Description evq Pointer to event queue getting initialized","title":"Arguments"},{"location":"os/core_os/event_queue/os_eventq_init/#returned-values","text":"None","title":"Returned values"},{"location":"os/core_os/event_queue/os_eventq_init/#notes","text":"Usually done at subsystem init time; before OS has been started, and before interrupts generating events have been enabled.","title":"Notes"},{"location":"os/core_os/event_queue/os_eventq_init/#example","text":"This initializes event queue used by newtmgr task. struct os_eventq g_nmgr_evq ; int nmgr_task_init ( uint8_t prio , os_stack_t *stack_ptr , uint16_t stack_len ) { /* variable declarations here */ os_eventq_init ( &g_nmgr_evq ); /* initialization continues here */ }","title":"Example"},{"location":"os/core_os/event_queue/os_eventq_inited/","text":"os_eventq_inited int os_eventq_inited ( const struct os_eventq *evq ) Check if event queue const struct os_eventq is ready for use. Arguments Arguments Description evq Pointer to event queue to check Returned values 0 if event queue is ready Notes If an event queue was properly initialized (and the proper checks were done at initialization) this check is not needed prior to using an event queue. Example This checks an event queue before using it. struct os_eventq g_my_evq ; int my_task_init ( uint8_t prio , os_stack_t *stack_ptr , uint16_t stack_len ) { /* variable declarations here */ if ( os_eventq_inited ( &g_my_evq )) { /* deal with the event queue */ }; }","title":"Os eventq inited"},{"location":"os/core_os/event_queue/os_eventq_inited/#os_eventq_inited","text":"int os_eventq_inited ( const struct os_eventq *evq ) Check if event queue const struct os_eventq is ready for use.","title":" os_eventq_inited"},{"location":"os/core_os/event_queue/os_eventq_inited/#arguments","text":"Arguments Description evq Pointer to event queue to check","title":"Arguments"},{"location":"os/core_os/event_queue/os_eventq_inited/#returned-values","text":"0 if event queue is ready","title":"Returned values"},{"location":"os/core_os/event_queue/os_eventq_inited/#notes","text":"If an event queue was properly initialized (and the proper checks were done at initialization) this check is not needed prior to using an event queue.","title":"Notes"},{"location":"os/core_os/event_queue/os_eventq_inited/#example","text":"This checks an event queue before using it. struct os_eventq g_my_evq ; int my_task_init ( uint8_t prio , os_stack_t *stack_ptr , uint16_t stack_len ) { /* variable declarations here */ if ( os_eventq_inited ( &g_my_evq )) { /* deal with the event queue */ }; }","title":"Example"},{"location":"os/core_os/event_queue/os_eventq_put/","text":"os_eventq_put void os_eventq_put ( struct os_eventq *evq , struct os_event *ev ) Queues an event to tail of the event queue. Arguments Arguments Description evq Queue where event is being placed ev Event which is being queued Returned values N/A Example This is used to pass info about an event to a task handling it. /* Get an event structure off the queue */ ev = ( struct os_event * ) os_memblock_get ( &g_hci_os_event_pool ); if ( !ev ) { err = os_memblock_put ( &g_hci_cmd_pool , hci_ev ); assert ( err == OS_OK ); return -1 ; } /* Fill out the event and post to Link Layer */ ev->ev_queued = 0 ; ev->ev_type = BLE_HOST_HCI_EVENT_CTLR_EVENT ; ev->ev_arg = hci_ev ; os_eventq_put ( &ble_hs_evq , ev );","title":"os_eventq_put"},{"location":"os/core_os/event_queue/os_eventq_put/#os_eventq_put","text":"void os_eventq_put ( struct os_eventq *evq , struct os_event *ev ) Queues an event to tail of the event queue.","title":" os_eventq_put"},{"location":"os/core_os/event_queue/os_eventq_put/#arguments","text":"Arguments Description evq Queue where event is being placed ev Event which is being queued","title":"Arguments"},{"location":"os/core_os/event_queue/os_eventq_put/#returned-values","text":"N/A","title":"Returned values"},{"location":"os/core_os/event_queue/os_eventq_put/#example","text":"This is used to pass info about an event to a task handling it. /* Get an event structure off the queue */ ev = ( struct os_event * ) os_memblock_get ( &g_hci_os_event_pool ); if ( !ev ) { err = os_memblock_put ( &g_hci_cmd_pool , hci_ev ); assert ( err == OS_OK ); return -1 ; } /* Fill out the event and post to Link Layer */ ev->ev_queued = 0 ; ev->ev_type = BLE_HOST_HCI_EVENT_CTLR_EVENT ; ev->ev_arg = hci_ev ; os_eventq_put ( &ble_hs_evq , ev );","title":"Example"},{"location":"os/core_os/event_queue/os_eventq_remove/","text":"os_eventq_remove void os_eventq_remove ( struct os_eventq *evq , struct os_event *ev ) Removes an event which has been placed in a queue. Arguments Arguments Description evq Queue where event is being removed from ev Event which is being removed Returned values N/A Notes Example This is from os_callout_stop(). User wants to stop a callout from getting passed to a task. If the event has already been queued, then remove it before it is seen. if ( c->c_evq ) { os_eventq_remove ( c->c_evq , &c->c_ev ); }","title":"os_eventq_remove"},{"location":"os/core_os/event_queue/os_eventq_remove/#os_eventq_remove","text":"void os_eventq_remove ( struct os_eventq *evq , struct os_event *ev ) Removes an event which has been placed in a queue.","title":" os_eventq_remove"},{"location":"os/core_os/event_queue/os_eventq_remove/#arguments","text":"Arguments Description evq Queue where event is being removed from ev Event which is being removed","title":"Arguments"},{"location":"os/core_os/event_queue/os_eventq_remove/#returned-values","text":"N/A","title":"Returned values"},{"location":"os/core_os/event_queue/os_eventq_remove/#notes","text":"","title":"Notes"},{"location":"os/core_os/event_queue/os_eventq_remove/#example","text":"This is from os_callout_stop(). User wants to stop a callout from getting passed to a task. If the event has already been queued, then remove it before it is seen. if ( c->c_evq ) { os_eventq_remove ( c->c_evq , &c->c_ev ); }","title":"Example"},{"location":"os/core_os/heap/heap/","text":"Heap API for doing dynamic memory allocation. Description This provides malloc()/free() functionality with locking. The shared resource heap needs to be protected from concurrent access when OS has been started. os_malloc() function grabs a mutex before calling malloc() . Data structures N/A List of Functions The functions available in heap are: Function Description os_free Frees previously allocated memory back to the heap. os_malloc Allocates the given number of bytes from heap and returns a pointer to it. os_realloc Tries to resize previously allocated memory block, and returns pointer to resized memory.","title":"toc"},{"location":"os/core_os/heap/heap/#heap","text":"API for doing dynamic memory allocation.","title":"Heap"},{"location":"os/core_os/heap/heap/#description","text":"This provides malloc()/free() functionality with locking. The shared resource heap needs to be protected from concurrent access when OS has been started. os_malloc() function grabs a mutex before calling malloc() .","title":"Description"},{"location":"os/core_os/heap/heap/#data-structures","text":"N/A","title":"Data structures"},{"location":"os/core_os/heap/heap/#list-of-functions","text":"The functions available in heap are: Function Description os_free Frees previously allocated memory back to the heap. os_malloc Allocates the given number of bytes from heap and returns a pointer to it. os_realloc Tries to resize previously allocated memory block, and returns pointer to resized memory.","title":"List of Functions"},{"location":"os/core_os/heap/os_free/","text":"os_free void os_free ( void *mem ) Frees previously allocated memory back to the heap. Arguments Arguments Description mem Pointer to memory being released Returned values N/A Notes Calls C-library free() behind the covers. Example os_free ( info );","title":"os_free"},{"location":"os/core_os/heap/os_free/#os_free","text":"void os_free ( void *mem ) Frees previously allocated memory back to the heap.","title":"os_free"},{"location":"os/core_os/heap/os_free/#arguments","text":"Arguments Description mem Pointer to memory being released","title":"Arguments"},{"location":"os/core_os/heap/os_free/#returned-values","text":"N/A","title":"Returned values"},{"location":"os/core_os/heap/os_free/#notes","text":"Calls C-library free() behind the covers.","title":"Notes"},{"location":"os/core_os/heap/os_free/#example","text":"os_free ( info );","title":"Example"},{"location":"os/core_os/heap/os_malloc/","text":"os_malloc void *os_malloc ( size_t size ) Allocates size number of bytes from heap and returns a pointer to it. Arguments Arguments Description size Number of bytes to allocate Returned values : pointer to memory allocated from heap. NULL: not enough memory available. Notes os_malloc() calls malloc() , which is provided by C-library. The heap must be set up during platform initialization. Depending on which C-library you use, you might have to do the heap setup differently. Most often malloc() implementation will maintain a list of allocated and then freed memory blocks. If user asks for memory which cannot be satisfied from free list, they'll call platform's sbrk() , which then tries to grow the heap. Example info = ( struct os_task_info * ) os_malloc ( sizeof ( struct os_task_info ) * tcount ); if ( !info ) { rc = -1 ; goto err ; }","title":"os_malloc"},{"location":"os/core_os/heap/os_malloc/#os_malloc","text":"void *os_malloc ( size_t size ) Allocates size number of bytes from heap and returns a pointer to it.","title":" os_malloc"},{"location":"os/core_os/heap/os_malloc/#arguments","text":"Arguments Description size Number of bytes to allocate","title":"Arguments"},{"location":"os/core_os/heap/os_malloc/#returned-values","text":": pointer to memory allocated from heap. NULL: not enough memory available.","title":"Returned values"},{"location":"os/core_os/heap/os_malloc/#notes","text":"os_malloc() calls malloc() , which is provided by C-library. The heap must be set up during platform initialization. Depending on which C-library you use, you might have to do the heap setup differently. Most often malloc() implementation will maintain a list of allocated and then freed memory blocks. If user asks for memory which cannot be satisfied from free list, they'll call platform's sbrk() , which then tries to grow the heap.","title":"Notes"},{"location":"os/core_os/heap/os_malloc/#example","text":"info = ( struct os_task_info * ) os_malloc ( sizeof ( struct os_task_info ) * tcount ); if ( !info ) { rc = -1 ; goto err ; }","title":"Example"},{"location":"os/core_os/heap/os_realloc/","text":"os_realloc void *os_realloc ( void *ptr , size_t size ) Tries to resize previously allocated memory block, and returns pointer to resized memory. ptr can be NULL, in which case the call is similar to calling os_malloc() . Arguments Arguments Description ptr Pointer to previously allocated memory size New size to adjust the memory block to Returned values NULL: size adjustment was not successful. ptr: pointer to new start of memory block Notes Example <Insert the code snippet here>","title":"os_realloc"},{"location":"os/core_os/heap/os_realloc/#os_realloc","text":"void *os_realloc ( void *ptr , size_t size ) Tries to resize previously allocated memory block, and returns pointer to resized memory. ptr can be NULL, in which case the call is similar to calling os_malloc() .","title":"os_realloc"},{"location":"os/core_os/heap/os_realloc/#arguments","text":"Arguments Description ptr Pointer to previously allocated memory size New size to adjust the memory block to","title":"Arguments"},{"location":"os/core_os/heap/os_realloc/#returned-values","text":"NULL: size adjustment was not successful. ptr: pointer to new start of memory block","title":"Returned values"},{"location":"os/core_os/heap/os_realloc/#notes","text":"","title":"Notes"},{"location":"os/core_os/heap/os_realloc/#example","text":"<Insert the code snippet here>","title":"Example"},{"location":"os/core_os/mbuf/OS_MBUF_DATA/","text":"OS_MBUF_DATA OS_MBUF_DATA ( __om , __type ) Macro used to cast the data pointer of an mbuf to a given type. Arguments Arguments Description __om Pointer to mbuf (struct os_mbuf *) __type Type to cast Example struct os_mbuf *om uint8_t *rxbuf ; rxbuf = OS_MBUF_DATA ( om , uint8_t * );","title":"OS_MBUF_DATA"},{"location":"os/core_os/mbuf/OS_MBUF_DATA/#os_mbuf_data","text":"OS_MBUF_DATA ( __om , __type ) Macro used to cast the data pointer of an mbuf to a given type.","title":"OS_MBUF_DATA"},{"location":"os/core_os/mbuf/OS_MBUF_DATA/#arguments","text":"Arguments Description __om Pointer to mbuf (struct os_mbuf *) __type Type to cast","title":"Arguments"},{"location":"os/core_os/mbuf/OS_MBUF_DATA/#example","text":"struct os_mbuf *om uint8_t *rxbuf ; rxbuf = OS_MBUF_DATA ( om , uint8_t * );","title":"Example"},{"location":"os/core_os/mbuf/OS_MBUF_LEADINGSPACE/","text":"OS_MBUF_LEADINGSPACE OS_MBUF_LEADINGSPACE ( __om ) Macro used to get the amount of leading space in an mbuf (in bytes). Arguments Arguments Description __om Pointer to mbuf (struct os_mbuf *) Notes This macro works on both normal mbufs and packet header mbufs. The amount of leading space is the number of bytes between the current om_data pointer of the mbuf and the start of the mbuf user data buffer. Example uint8_t *dptr ; uint16_t space ; struct os_mbuf *om ; struct my_data_struct my_data ; /* Copy data from \"my_data\" into the start of an mbuf but only if there is enough room */ space = OS_MBUF_LEADINGSPACE ( om ); if ( space >= sizeof ( struct my_data_struct )) { dptr = om->om_data - sizeof ( struct my_data_struct ); memcpy ( dptr , &my_data , sizeof ( struct my_data_struct )); }","title":"OS_MBUF_LEADINGSPACE"},{"location":"os/core_os/mbuf/OS_MBUF_LEADINGSPACE/#os_mbuf_leadingspace","text":"OS_MBUF_LEADINGSPACE ( __om ) Macro used to get the amount of leading space in an mbuf (in bytes).","title":"OS_MBUF_LEADINGSPACE"},{"location":"os/core_os/mbuf/OS_MBUF_LEADINGSPACE/#arguments","text":"Arguments Description __om Pointer to mbuf (struct os_mbuf *)","title":"Arguments"},{"location":"os/core_os/mbuf/OS_MBUF_LEADINGSPACE/#notes","text":"This macro works on both normal mbufs and packet header mbufs. The amount of leading space is the number of bytes between the current om_data pointer of the mbuf and the start of the mbuf user data buffer.","title":"Notes"},{"location":"os/core_os/mbuf/OS_MBUF_LEADINGSPACE/#example","text":"uint8_t *dptr ; uint16_t space ; struct os_mbuf *om ; struct my_data_struct my_data ; /* Copy data from \"my_data\" into the start of an mbuf but only if there is enough room */ space = OS_MBUF_LEADINGSPACE ( om ); if ( space >= sizeof ( struct my_data_struct )) { dptr = om->om_data - sizeof ( struct my_data_struct ); memcpy ( dptr , &my_data , sizeof ( struct my_data_struct )); }","title":"Example"},{"location":"os/core_os/mbuf/OS_MBUF_PKTHDR/","text":"OS_MBUF_PKTHDR OS_MBUF_PKTHDR ( __om ) Macro used to get a pointer to the os mbuf packet header of an mbuf. Arguments Arguments Description __om Pointer to mbuf (struct os_mbuf *) Example int does_packet_have_data ( struct os_mbuf *om ) { struct os_mbuf_pkthdr *hdr ; hdr = OS_MBUF_PKTHDR ( om ); if ( hdr->omp_len != 0 ) { /* Packet has data in it */ return TRUE } else { /* Packet has no data */ return FALSE ; } }","title":"OS_MBUF_PKTHDR"},{"location":"os/core_os/mbuf/OS_MBUF_PKTHDR/#os_mbuf_pkthdr","text":"OS_MBUF_PKTHDR ( __om ) Macro used to get a pointer to the os mbuf packet header of an mbuf.","title":"OS_MBUF_PKTHDR"},{"location":"os/core_os/mbuf/OS_MBUF_PKTHDR/#arguments","text":"Arguments Description __om Pointer to mbuf (struct os_mbuf *)","title":"Arguments"},{"location":"os/core_os/mbuf/OS_MBUF_PKTHDR/#example","text":"int does_packet_have_data ( struct os_mbuf *om ) { struct os_mbuf_pkthdr *hdr ; hdr = OS_MBUF_PKTHDR ( om ); if ( hdr->omp_len != 0 ) { /* Packet has data in it */ return TRUE } else { /* Packet has no data */ return FALSE ; } }","title":"Example"},{"location":"os/core_os/mbuf/OS_MBUF_PKTHDR_TO_MBUF/","text":"OS_MBUF_PKTHDR_TO_MBUF OS_MBUF_PKTHDR_TO_MBUF ( __hdr ) Macro used to get a pointer to the mbuf given a pointer to the os mbuf packet header Arguments Arguments Description __hdr Pointer to os mbuf packet header (struct os_mbuf_pkthdr *) Example struct os_mbuf *om ; struct os_mbuf_pkthdr *hdr ; om = OS_MBUF_PKTHDR_TO_MBUF ( hdr ); os_mbuf_free_chain ( om );","title":"OS_MBUF_PKTHDR_TO_MBUF"},{"location":"os/core_os/mbuf/OS_MBUF_PKTHDR_TO_MBUF/#os_mbuf_pkthdr_to_mbuf","text":"OS_MBUF_PKTHDR_TO_MBUF ( __hdr ) Macro used to get a pointer to the mbuf given a pointer to the os mbuf packet header","title":"OS_MBUF_PKTHDR_TO_MBUF"},{"location":"os/core_os/mbuf/OS_MBUF_PKTHDR_TO_MBUF/#arguments","text":"Arguments Description __hdr Pointer to os mbuf packet header (struct os_mbuf_pkthdr *)","title":"Arguments"},{"location":"os/core_os/mbuf/OS_MBUF_PKTHDR_TO_MBUF/#example","text":"struct os_mbuf *om ; struct os_mbuf_pkthdr *hdr ; om = OS_MBUF_PKTHDR_TO_MBUF ( hdr ); os_mbuf_free_chain ( om );","title":"Example"},{"location":"os/core_os/mbuf/OS_MBUF_PKTLEN/","text":"OS_MBUF_PKTLEN OS_MBUF_PKTLEN ( __om ) Macro used to get the length of an entire mbuf chain. Arguments Arguments Description __om Pointer to mbuf (struct os_mbuf *) Example uint16_t pktlen ; struct os_mbuf *om ; /* Check if there is any data in the mbuf chain */ pktlen = OS_MBUF_PKTLEN ( om ); if ( pktlen != 0 ) { /* mbuf chain has data */ }","title":"OS_MBUF_PKTLEN"},{"location":"os/core_os/mbuf/OS_MBUF_PKTLEN/#os_mbuf_pktlen","text":"OS_MBUF_PKTLEN ( __om ) Macro used to get the length of an entire mbuf chain.","title":"OS_MBUF_PKTLEN"},{"location":"os/core_os/mbuf/OS_MBUF_PKTLEN/#arguments","text":"Arguments Description __om Pointer to mbuf (struct os_mbuf *)","title":"Arguments"},{"location":"os/core_os/mbuf/OS_MBUF_PKTLEN/#example","text":"uint16_t pktlen ; struct os_mbuf *om ; /* Check if there is any data in the mbuf chain */ pktlen = OS_MBUF_PKTLEN ( om ); if ( pktlen != 0 ) { /* mbuf chain has data */ }","title":"Example"},{"location":"os/core_os/mbuf/OS_MBUF_TRAILINGSPACE/","text":"OS_MBUF_TRAILINGSPACE OS_MBUF_TRAILINGSPACE ( __om ) Macro used to get the amount of trailing space in an mbuf (in bytes). Arguments Arguments Description __om Pointer to mbuf (struct os_mbuf *) Notes This macro works on both normal mbufs and packet header mbufs. The amount of trailing space is the number of bytes between the current om_data pointer of the mbuf and the end of the mbuf. Example uint16_t space ; struct os_mbuf *om ; struct my_data_struct my_data ; /* Copy data from \"my_data\" to the end of an mbuf but only if there is enough room */ space = OS_MBUF_TRAILINGSPACE ( om ); if ( space >= sizeof ( struct my_data_struct )) { memcpy ( om->om_data , &my_data , sizeof ( struct my_data_struct )); }","title":"OS_MBUF_TRAILINGSPACE"},{"location":"os/core_os/mbuf/OS_MBUF_TRAILINGSPACE/#os_mbuf_trailingspace","text":"OS_MBUF_TRAILINGSPACE ( __om ) Macro used to get the amount of trailing space in an mbuf (in bytes).","title":"OS_MBUF_TRAILINGSPACE"},{"location":"os/core_os/mbuf/OS_MBUF_TRAILINGSPACE/#arguments","text":"Arguments Description __om Pointer to mbuf (struct os_mbuf *)","title":"Arguments"},{"location":"os/core_os/mbuf/OS_MBUF_TRAILINGSPACE/#notes","text":"This macro works on both normal mbufs and packet header mbufs. The amount of trailing space is the number of bytes between the current om_data pointer of the mbuf and the end of the mbuf.","title":"Notes"},{"location":"os/core_os/mbuf/OS_MBUF_TRAILINGSPACE/#example","text":"uint16_t space ; struct os_mbuf *om ; struct my_data_struct my_data ; /* Copy data from \"my_data\" to the end of an mbuf but only if there is enough room */ space = OS_MBUF_TRAILINGSPACE ( om ); if ( space >= sizeof ( struct my_data_struct )) { memcpy ( om->om_data , &my_data , sizeof ( struct my_data_struct )); }","title":"Example"},{"location":"os/core_os/mbuf/OS_MBUF_USRHDR/","text":"OS_MBUF_USRHDR OS_MBUF_USRHDR ( __om ) Macro used to get a pointer to the user packet header of an mbuf. Arguments Arguments Description __om Pointer to mbuf (struct os_mbuf *). Must be head of chain (i.e. a packet header mbuf) Example struct os_mbuf *om struct user_header *hdr ; hdr = OS_MBUF_USRHDR ( om );","title":"OS_MBUF_USRHDR"},{"location":"os/core_os/mbuf/OS_MBUF_USRHDR/#os_mbuf_usrhdr","text":"OS_MBUF_USRHDR ( __om ) Macro used to get a pointer to the user packet header of an mbuf.","title":"OS_MBUF_USRHDR"},{"location":"os/core_os/mbuf/OS_MBUF_USRHDR/#arguments","text":"Arguments Description __om Pointer to mbuf (struct os_mbuf *). Must be head of chain (i.e. a packet header mbuf)","title":"Arguments"},{"location":"os/core_os/mbuf/OS_MBUF_USRHDR/#example","text":"struct os_mbuf *om struct user_header *hdr ; hdr = OS_MBUF_USRHDR ( om );","title":"Example"},{"location":"os/core_os/mbuf/OS_MBUF_USRHDR_LEN/","text":"OS_MBUF_USRHDR_LEN OS_MBUF_USRHDR_LEN ( __om ) Macro used to retrieve the length of the user packet header in an mbuf. Arguments Arguments Description __om Pointer to mbuf (struct os_mbuf *). Must be head of chain (i.e. a packet header mbuf) Example uint16_t user_length ; struct os_mbuf *om struct user_header *hdr ; user_length = OS_MBUF_USRHDR_LEN ( om );","title":"OS_MBUF_USRHDR_LEN"},{"location":"os/core_os/mbuf/OS_MBUF_USRHDR_LEN/#os_mbuf_usrhdr_len","text":"OS_MBUF_USRHDR_LEN ( __om ) Macro used to retrieve the length of the user packet header in an mbuf.","title":"OS_MBUF_USRHDR_LEN"},{"location":"os/core_os/mbuf/OS_MBUF_USRHDR_LEN/#arguments","text":"Arguments Description __om Pointer to mbuf (struct os_mbuf *). Must be head of chain (i.e. a packet header mbuf)","title":"Arguments"},{"location":"os/core_os/mbuf/OS_MBUF_USRHDR_LEN/#example","text":"uint16_t user_length ; struct os_mbuf *om struct user_header *hdr ; user_length = OS_MBUF_USRHDR_LEN ( om );","title":"Example"},{"location":"os/core_os/mbuf/mbuf/","text":"Mbufs The mbuf (short for memory buffer) is a common concept in networking stacks. The mbuf is used to hold packet data as it traverses the stack. The mbuf also generally stores header information or other networking stack information that is carried around with the packet. The mbuf and its associated library of functions were developed to make common networking stack operations (like stripping and adding protocol headers) efficient and as copy-free as possible. In its simplest form, an mbuf is a memory block with some space reserved for internal information and a pointer which is used to \"chain\" memory blocks together in order to create a \"packet\". This is a very important aspect of the mbuf: the ability to chain mbufs together to create larger \"packets\" (chains of mbufs). Why use mbufs? The main reason is to conserve memory. Consider a networking protocol that generally sends small packets but occasionally sends large ones. The Bluetooth Low Energy (BLE) protocol is one such example. A flat buffer would need to be sized so that the maximum packet size could be contained by the buffer. With the mbuf, a number of mbufs can be chained together so that the occasional large packet can be handled while leaving more packet buffers available to the networking stack for smaller packets. Packet Header mbuf Not all mbufs are created equal. The first mbuf in a chain of mbufs is a special mbuf called a \"packet header mbuf\". The reason that this mbuf is special is that it contains the length of all the data contained by the chain of mbufs (the packet length, in other words). The packet header mbuf may also contain a user defined structure (called a \"user header\") so that networking protocol specific information can be conveyed to various layers of the networking stack. Any mbufs that are part of the packet (i.e. in the mbuf chain but not the first one) are \"normal\" (i.e. non-packet header) mbufs. A normal mbuf does not have any packet header or user packet header structures in them; they only contain the basic mbuf header ( struct os_mbuf ). Figure 1 illustrates these two types of mbufs. Note that the numbers/text in parentheses denote the size of the structures/elements (in bytes) and that MBLEN is the memory block length of the memory pool used by the mbuf pool. Normal mbuf Now let's take a deeper dive into the mbuf structure. Figure 2 illustrates a normal mbuf and breaks out the various fields in the os_mbuf structure. The om_data field is a pointer to where the data starts inside the data buffer. Typically, mbufs that are allocated from the mbuf pool (discussed later) have their om_data pointer set to the start of the data buffer but there are cases where this may not be desirable (added a protocol header to a packet, for example). The om_flags field is a set of flags used internally by the mbuf library. Currently, no flags have been defined. The om_pkthdr_len field is the total length of all packet headers in the mbuf. For normal mbufs this is set to 0 as there is no packet or user packet headers. For packet header mbufs, this would be set to the length of the packet header structure (16) plus the size of the user packet header (if any). Note that it is this field which differentiates packet header mbufs from normal mbufs (i.e. if om_pkthdr_len is zero, this is a normal mbuf; otherwise it is a packet header mbuf). The om_len field contains the amount of user data in the data buffer. When initially allocated, this field is 0 as there is no user data in the mbuf. The omp_pool field is a pointer to the pool from which this mbuf has been allocated. This is used internally by the mbuf library. The omp_next field is a linked list element which is used to chain mbufs. Figure 2 also shows a normal mbuf with actual values in the os_mbuf structure. This mbuf starts at address 0x1000 and is 256 bytes in total length. In this example, the user has copied 33 bytes into the data buffer starting at address 0x1010 (this is where om_data points). Note that the packet header length in this mbuf is 0 as it is not a packet header mbuf. Figure 3 illustrates the packet header mbuf along with some chained mbufs (i.e a \"packet\"). In this example, the user header structure is defined to be 8 bytes. Note that in figure 3 we show a number of different mbufs with varying om_data pointers and lengths since we want to show various examples of valid mbufs. For all the mbufs (both packet header and normal ones) the total length of the memory block is 128 bytes. Mbuf pools Mbufs are collected into \"mbuf pools\" much like memory blocks. The mbuf pool itself contains a pointer to a memory pool. The memory blocks in this memory pool are the actual mbufs; both normal and packet header mbufs. Thus, the memory block (and corresponding memory pool) must be sized correctly. In other words, the memory blocks which make up the memory pool used by the mbuf pool must be at least: sizeof(struct os_mbuf) + sizeof(struct os_mbuf_pkthdr) + sizeof(struct user_defined_header) + desired minimum data buffer length. For example, if the developer wants mbufs to contain at least 64 bytes of user data and they have a user header of 12 bytes, the size of the memory block would be (at least): 64 + 12 + 16 + 8, or 100 bytes. Yes, this is a fair amount of overhead. However, the flexibility provided by the mbuf library usually outweighs overhead concerns. Create mbuf pool Creating an mbuf pool is fairly simple: create a memory pool and then create the mbuf pool using that memory pool. Once the developer has determined the size of the user data needed per mbuf (this is based on the application/networking stack and is outside the scope of this discussion) and the size of the user header (if any), the memory blocks can be sized. In the example shown below, the application requires 64 bytes of user data per mbuf and also allocates a user header (called struct user_hdr). Note that we do not show the user header data structure as there really is no need; all we need to do is to account for it when creating the memory pool. In the example, we use the macro MBUF_PKTHDR_OVERHEAD to denote the amount of packet header overhead per mbuf and MBUF_MEMBLOCK_OVERHEAD to denote the total amount of overhead required per memory block. The macro MBUF_BUF_SIZE is used to denote the amount of payload that the application requires (aligned on a 32-bit boundary in this case). All this leads to the total memory block size required, denoted by the macro MBUF_MEMBLOCK_OVERHEAD . #define MBUF_PKTHDR_OVERHEAD sizeof(struct os_mbuf_pkthdr) + sizeof(struct user_hdr) #define MBUF_MEMBLOCK_OVERHEAD sizeof(struct os_mbuf) + MBUF_PKTHDR_OVERHEAD #define MBUF_NUM_MBUFS (32) #define MBUF_PAYLOAD_SIZE (64) #define MBUF_BUF_SIZE OS_ALIGN(MBUF_PAYLOAD_SIZE, 4) #define MBUF_MEMBLOCK_SIZE (MBUF_BUF_SIZE + MBUF_MEMBLOCK_OVERHEAD) #define MBUF_MEMPOOL_SIZE OS_MEMPOOL_SIZE(MBUF_NUM_MBUFS, MBUF_MEMBLOCK_SIZE) struct os_mbuf_pool g_mbuf_pool ; struct os_mempool g_mbuf_mempool ; os_membuf_t g_mbuf_buffer [ MBUF_MEMPOOL_SIZE ]; void create_mbuf_pool ( void ) { int rc ; rc = os_mempool_init ( &g_mbuf_mempool , MBUF_NUM_MBUFS , MBUF_MEMBLOCK_SIZE , &g_mbuf_buffer [ 0 ], \"mbuf_pool\" ); assert ( rc == 0 ); rc = os_mbuf_pool_init ( &g_mbuf_pool , &g_mbuf_mempool , MBUF_MEMBLOCK_SIZE , MBUF_NUM_MBUFS ); assert ( rc == 0 ); } Using mbufs The following examples illustrate typical mbuf usage. There are two basic mbuf allocation API: os_mbuf_get() and os_mbuf_get_pkthdr() . The first API obtains a normal mbuf whereas the latter obtains a packet header mbuf. Typically, application developers use os_mbuf_get_pkthdr() and rarely, if ever, need to call os_mbuf_get() as the rest of the mbuf API (e.g. os_mbuf_append() , os_mbuf_copyinto() , etc.) typically deal with allocating and chaining mbufs. It is recommended to use the provided API to copy data into/out of mbuf chains and/or manipulate mbufs. In example1 , the developer creates a packet and then sends the packet to a networking interface. The code sample also provides an example of copying data out of an mbuf as well as use of the \"pullup\" api (another very common mbuf api). void mbuf_usage_example1 ( uint8_t *mydata , int mydata_length ) { int rc ; struct os_mbuf *om ; /* get a packet header mbuf */ om = os_mbuf_get_pkthdr ( &g_mbuf_pool , sizeof ( struct user_hdr )); if ( om ) { /* * Copy user data into mbuf. NOTE: if mydata_length is greater than the * mbuf payload size (64 bytes using above example), mbufs are allocated * and chained together to accommodate the total packet length. */ rc = os_mbuf_copyinto ( om , 0 , mydata , len ); if ( rc ) { /* Error! Could not allocate enough mbufs for total packet length */ return -1 ; } /* Send packet to networking interface */ send_pkt ( om ); } } In example2 we show use of the pullup api as this illustrates some of the typical pitfalls developers encounter when using mbufs. The first pitfall is one of alignment/padding. Depending on the processor and/or compiler, the sizeof() a structure may vary. Thus, the size of my_protocol_header may be different inside the packet data of the mbuf than the size of the structure on the stack or as a global variable, for instance. While some networking protcols may align protocol information on convenient processor boundaries many others try to conserve bytes \"on the air\" (i.e inside the packet data). Typical methods used to deal with this are \"packing\" the structure (i.e. force compiler to not pad) or creating protocol headers that do not require padding. example2 assumes that one of these methods was used when defining the my_protocol_header structure. Another common pitfall occurs around endianness. A network protocol may be little endian or big endian; it all depends on the protocol specification. Processors also have an endianness; this means that the developer has to be careful that the processor endianness and the protocol endianness are handled correctly. In example2 , some common networking functions are used: ntohs() and ntohl() . These are shorthand for \"network order to host order, short\" and \"network order to host order, long\". Basically, these functions convert data of a certain size (i.e. 16 bits, 32 bits, etc) to the endianness of the host. Network byte order is big-endian (most significant byte first), so these functions convert big-endian byte order to host order (thus, the implementation of these functions is host dependent). Note that the BLE networking stack \"on the air\" format is least signigicant byte first (i.e. little endian), so a \"bletoh\" function would have to take little endian format and convert to host format. A long story short: the developer must take care when copying structure data to/from mbufs and flat buffers! A final note: these examples assume the same mbuf struture and definitions used in the first example. void mbuf_usage_example2 ( struct mbuf *rxpkt ) { int rc ; uint8_t packet_data [ 16 ]; struct mbuf *om ; struct my_protocol_header *phdr ; /* Make sure that \"my_protocol_header\" bytes are contiguous in mbuf */ om = os_mbuf_pullup ( &g_mbuf_pool , sizeof ( struct my_protocol_header )); if ( !om ) { /* Not able to pull up data into contiguous area */ return -1 ; } /* * Get the protocol information from the packet. In this example we presume that we * are interested in protocol types that are equal to MY_PROTOCOL_TYPE, are not zero * length, and have had some time in flight. */ phdr = OS_MBUF_DATA ( om , struct my_protocol_header * ); type = ntohs ( phdr->prot_type ); length = ntohs ( phdr->prot_length ); time_in_flight = ntohl ( phdr->prot_tif ); if (( type == MY_PROTOCOL_TYPE ) && ( length > 0 ) && ( time_in_flight > 0 )) { rc = os_mbuf_copydata ( rxpkt , sizeof ( struct my_protocol_header ), 16 , packet_data ); if ( !rc ) { /* Success! Perform operations on packet data */ < ... user code here ... > } } /* Free passed in packet (mbuf chain) since we don't need it anymore */ os_mbuf_free_chain ( om ); } Data Structures struct os_mbuf_pool { uint16_t omp_databuf_len ; uint16_t omp_mbuf_count ; struct os_mempool *omp_pool ; STAILQ_ENTRY ( os_mbuf_pool ) omp_next ; }; Element Description omp_databuf_len The length, in bytes, of the \"data buffer\" of the mbuf. The data buffer of the mbuf is everything except the os_mbuf structure (which is present in all types of mbufs) omp_mbuf_count Total number of mbufs in the pool when allocated. This is NOT the number of free mbufs in the pool! omp_pool The memory pool from which the mbufs are allocated omp_next This is a linked list pointer which chains memory pools. It is used by the system memory pool library struct os_mbuf_pkthdr { uint16_t omp_len ; uint16_t omp_flags ; STAILQ_ENTRY ( os_mbuf_pkthdr ) omp_next ; }; Element Description omp_len Length, in bytes, of the \"packet\". This is the sum of the user data in all the mbufs chained to the packet header mbuf (including the packet header mbuf) omp_flags Packet header flags. omp_next Linked list pointer to chain \"packets\". This can be used to add mbuf chains to a queue or linked list and is there for convenience. struct os_mbuf { uint8_t *om_data ; uint8_t om_flags ; uint8_t om_pkthdr_len ; uint16_t om_len ; struct os_mbuf_pool *om_omp ; SLIST_ENTRY ( os_mbuf ) om_next ; uint8_t om_databuf [ 0 ]; }; Element Description om_data Pointer to start of user data in mbuf data buffer om_flags mbuf flags field. Currently all flags unused. om_pkthdr_len The total length of all packet headers in the mbuf (mbuf packet header plus user packet header), in bytes om_len The length of the user data contained in this mbuf, in bytes om_omp Memory pool pointer. This is the mbuf pool from which this mbuf was allocated. om_next Pointer to next mbuf in packet chain om_databuf mbuf data buffer (accessor to start of mbuf data buffer). Note that the mbuf data buffer refers to the start of either the user data in normal mbufs or the start of the os mbuf packet header for packet header mbufs List of Functions/Macros The functions/macros available in mbuf are: Function/Macro Description OS_MBUF_PKTHDR Get a pointer to the os mbuf packet header of an mbuf. OS_MBUF_PKTHDR_TO_MBUF Get a pointer to the mbuf given a pointer to the os mbuf packet header. OS_MBUF_PKTLEN Get the length of an entire mbuf chain. OS_MBUF_DATA Cast the data pointer of an mbuf to a given type. OS_MBUF_USRHDR Get a pointer to the user packet header of an mbuf. OS_MBUF_USRHDR_LEN Retrieve the length of the user packet header in an mbuf. OS_MBUF_LEADINGSPACE Get the amount of leading space in an mbuf (in bytes). OS_MBUF_TRAILINGSPACE Get the amount of trailing space in an mbuf (in bytes). os_mbuf_adj Trims the given number of bytes from either the head (if positive) or tail (if negative) of an mbuf chain. os_mbuf_append Appends a data buffer of the given length to the end of an mbuf chain. os_mbuf_concat Attaches a second mbuf chain onto the end of the first. os_mbuf_copydata Copy data from an mbuf chain. os_mbuf_copyinto Copies the contents of a flat buffer into an mbuf chain. os_mbuf_dup Duplicate a chain of mbufs. os_mbuf_extend Increases the length of an mbuf chain by the specified amount. os_mbuf_free_chain Frees a chain of mbufs. os_mbuf_get Get an mbuf from the mbuf pool. os_mbuf_get_pkthdr Allocates a packet header mbuf from the given mbuf pool. Adds a user header to the packet header mbuf. os_mbuf_memcmp Performs a memory compare of the specified region of an mbuf chain against a flat buffer. os_mbuf_off Given an offset in the packet, return the mbuf and the offset in that mbuf where byte 'off' is located. os_mbuf_pool_init nitialize an mbuf pool. os_mbuf_prepend Increases the length of an mbuf chain by adding data to the front. os_mbuf_pullup Rearrange an mbuf chain so that the given length of bytes are contiguous and in the data area of an mbuf.","title":"toc"},{"location":"os/core_os/mbuf/mbuf/#mbufs","text":"The mbuf (short for memory buffer) is a common concept in networking stacks. The mbuf is used to hold packet data as it traverses the stack. The mbuf also generally stores header information or other networking stack information that is carried around with the packet. The mbuf and its associated library of functions were developed to make common networking stack operations (like stripping and adding protocol headers) efficient and as copy-free as possible. In its simplest form, an mbuf is a memory block with some space reserved for internal information and a pointer which is used to \"chain\" memory blocks together in order to create a \"packet\". This is a very important aspect of the mbuf: the ability to chain mbufs together to create larger \"packets\" (chains of mbufs).","title":"Mbufs"},{"location":"os/core_os/mbuf/mbuf/#why-use-mbufs","text":"The main reason is to conserve memory. Consider a networking protocol that generally sends small packets but occasionally sends large ones. The Bluetooth Low Energy (BLE) protocol is one such example. A flat buffer would need to be sized so that the maximum packet size could be contained by the buffer. With the mbuf, a number of mbufs can be chained together so that the occasional large packet can be handled while leaving more packet buffers available to the networking stack for smaller packets.","title":"Why use mbufs?"},{"location":"os/core_os/mbuf/mbuf/#packet-header-mbuf","text":"Not all mbufs are created equal. The first mbuf in a chain of mbufs is a special mbuf called a \"packet header mbuf\". The reason that this mbuf is special is that it contains the length of all the data contained by the chain of mbufs (the packet length, in other words). The packet header mbuf may also contain a user defined structure (called a \"user header\") so that networking protocol specific information can be conveyed to various layers of the networking stack. Any mbufs that are part of the packet (i.e. in the mbuf chain but not the first one) are \"normal\" (i.e. non-packet header) mbufs. A normal mbuf does not have any packet header or user packet header structures in them; they only contain the basic mbuf header ( struct os_mbuf ). Figure 1 illustrates these two types of mbufs. Note that the numbers/text in parentheses denote the size of the structures/elements (in bytes) and that MBLEN is the memory block length of the memory pool used by the mbuf pool.","title":"Packet Header mbuf"},{"location":"os/core_os/mbuf/mbuf/#normal-mbuf","text":"Now let's take a deeper dive into the mbuf structure. Figure 2 illustrates a normal mbuf and breaks out the various fields in the os_mbuf structure. The om_data field is a pointer to where the data starts inside the data buffer. Typically, mbufs that are allocated from the mbuf pool (discussed later) have their om_data pointer set to the start of the data buffer but there are cases where this may not be desirable (added a protocol header to a packet, for example). The om_flags field is a set of flags used internally by the mbuf library. Currently, no flags have been defined. The om_pkthdr_len field is the total length of all packet headers in the mbuf. For normal mbufs this is set to 0 as there is no packet or user packet headers. For packet header mbufs, this would be set to the length of the packet header structure (16) plus the size of the user packet header (if any). Note that it is this field which differentiates packet header mbufs from normal mbufs (i.e. if om_pkthdr_len is zero, this is a normal mbuf; otherwise it is a packet header mbuf). The om_len field contains the amount of user data in the data buffer. When initially allocated, this field is 0 as there is no user data in the mbuf. The omp_pool field is a pointer to the pool from which this mbuf has been allocated. This is used internally by the mbuf library. The omp_next field is a linked list element which is used to chain mbufs. Figure 2 also shows a normal mbuf with actual values in the os_mbuf structure. This mbuf starts at address 0x1000 and is 256 bytes in total length. In this example, the user has copied 33 bytes into the data buffer starting at address 0x1010 (this is where om_data points). Note that the packet header length in this mbuf is 0 as it is not a packet header mbuf. Figure 3 illustrates the packet header mbuf along with some chained mbufs (i.e a \"packet\"). In this example, the user header structure is defined to be 8 bytes. Note that in figure 3 we show a number of different mbufs with varying om_data pointers and lengths since we want to show various examples of valid mbufs. For all the mbufs (both packet header and normal ones) the total length of the memory block is 128 bytes.","title":"Normal mbuf"},{"location":"os/core_os/mbuf/mbuf/#mbuf-pools","text":"Mbufs are collected into \"mbuf pools\" much like memory blocks. The mbuf pool itself contains a pointer to a memory pool. The memory blocks in this memory pool are the actual mbufs; both normal and packet header mbufs. Thus, the memory block (and corresponding memory pool) must be sized correctly. In other words, the memory blocks which make up the memory pool used by the mbuf pool must be at least: sizeof(struct os_mbuf) + sizeof(struct os_mbuf_pkthdr) + sizeof(struct user_defined_header) + desired minimum data buffer length. For example, if the developer wants mbufs to contain at least 64 bytes of user data and they have a user header of 12 bytes, the size of the memory block would be (at least): 64 + 12 + 16 + 8, or 100 bytes. Yes, this is a fair amount of overhead. However, the flexibility provided by the mbuf library usually outweighs overhead concerns.","title":"Mbuf pools"},{"location":"os/core_os/mbuf/mbuf/#create-mbuf-pool","text":"Creating an mbuf pool is fairly simple: create a memory pool and then create the mbuf pool using that memory pool. Once the developer has determined the size of the user data needed per mbuf (this is based on the application/networking stack and is outside the scope of this discussion) and the size of the user header (if any), the memory blocks can be sized. In the example shown below, the application requires 64 bytes of user data per mbuf and also allocates a user header (called struct user_hdr). Note that we do not show the user header data structure as there really is no need; all we need to do is to account for it when creating the memory pool. In the example, we use the macro MBUF_PKTHDR_OVERHEAD to denote the amount of packet header overhead per mbuf and MBUF_MEMBLOCK_OVERHEAD to denote the total amount of overhead required per memory block. The macro MBUF_BUF_SIZE is used to denote the amount of payload that the application requires (aligned on a 32-bit boundary in this case). All this leads to the total memory block size required, denoted by the macro MBUF_MEMBLOCK_OVERHEAD . #define MBUF_PKTHDR_OVERHEAD sizeof(struct os_mbuf_pkthdr) + sizeof(struct user_hdr) #define MBUF_MEMBLOCK_OVERHEAD sizeof(struct os_mbuf) + MBUF_PKTHDR_OVERHEAD #define MBUF_NUM_MBUFS (32) #define MBUF_PAYLOAD_SIZE (64) #define MBUF_BUF_SIZE OS_ALIGN(MBUF_PAYLOAD_SIZE, 4) #define MBUF_MEMBLOCK_SIZE (MBUF_BUF_SIZE + MBUF_MEMBLOCK_OVERHEAD) #define MBUF_MEMPOOL_SIZE OS_MEMPOOL_SIZE(MBUF_NUM_MBUFS, MBUF_MEMBLOCK_SIZE) struct os_mbuf_pool g_mbuf_pool ; struct os_mempool g_mbuf_mempool ; os_membuf_t g_mbuf_buffer [ MBUF_MEMPOOL_SIZE ]; void create_mbuf_pool ( void ) { int rc ; rc = os_mempool_init ( &g_mbuf_mempool , MBUF_NUM_MBUFS , MBUF_MEMBLOCK_SIZE , &g_mbuf_buffer [ 0 ], \"mbuf_pool\" ); assert ( rc == 0 ); rc = os_mbuf_pool_init ( &g_mbuf_pool , &g_mbuf_mempool , MBUF_MEMBLOCK_SIZE , MBUF_NUM_MBUFS ); assert ( rc == 0 ); }","title":"Create mbuf pool"},{"location":"os/core_os/mbuf/mbuf/#using-mbufs","text":"The following examples illustrate typical mbuf usage. There are two basic mbuf allocation API: os_mbuf_get() and os_mbuf_get_pkthdr() . The first API obtains a normal mbuf whereas the latter obtains a packet header mbuf. Typically, application developers use os_mbuf_get_pkthdr() and rarely, if ever, need to call os_mbuf_get() as the rest of the mbuf API (e.g. os_mbuf_append() , os_mbuf_copyinto() , etc.) typically deal with allocating and chaining mbufs. It is recommended to use the provided API to copy data into/out of mbuf chains and/or manipulate mbufs. In example1 , the developer creates a packet and then sends the packet to a networking interface. The code sample also provides an example of copying data out of an mbuf as well as use of the \"pullup\" api (another very common mbuf api). void mbuf_usage_example1 ( uint8_t *mydata , int mydata_length ) { int rc ; struct os_mbuf *om ; /* get a packet header mbuf */ om = os_mbuf_get_pkthdr ( &g_mbuf_pool , sizeof ( struct user_hdr )); if ( om ) { /* * Copy user data into mbuf. NOTE: if mydata_length is greater than the * mbuf payload size (64 bytes using above example), mbufs are allocated * and chained together to accommodate the total packet length. */ rc = os_mbuf_copyinto ( om , 0 , mydata , len ); if ( rc ) { /* Error! Could not allocate enough mbufs for total packet length */ return -1 ; } /* Send packet to networking interface */ send_pkt ( om ); } } In example2 we show use of the pullup api as this illustrates some of the typical pitfalls developers encounter when using mbufs. The first pitfall is one of alignment/padding. Depending on the processor and/or compiler, the sizeof() a structure may vary. Thus, the size of my_protocol_header may be different inside the packet data of the mbuf than the size of the structure on the stack or as a global variable, for instance. While some networking protcols may align protocol information on convenient processor boundaries many others try to conserve bytes \"on the air\" (i.e inside the packet data). Typical methods used to deal with this are \"packing\" the structure (i.e. force compiler to not pad) or creating protocol headers that do not require padding. example2 assumes that one of these methods was used when defining the my_protocol_header structure. Another common pitfall occurs around endianness. A network protocol may be little endian or big endian; it all depends on the protocol specification. Processors also have an endianness; this means that the developer has to be careful that the processor endianness and the protocol endianness are handled correctly. In example2 , some common networking functions are used: ntohs() and ntohl() . These are shorthand for \"network order to host order, short\" and \"network order to host order, long\". Basically, these functions convert data of a certain size (i.e. 16 bits, 32 bits, etc) to the endianness of the host. Network byte order is big-endian (most significant byte first), so these functions convert big-endian byte order to host order (thus, the implementation of these functions is host dependent). Note that the BLE networking stack \"on the air\" format is least signigicant byte first (i.e. little endian), so a \"bletoh\" function would have to take little endian format and convert to host format. A long story short: the developer must take care when copying structure data to/from mbufs and flat buffers! A final note: these examples assume the same mbuf struture and definitions used in the first example. void mbuf_usage_example2 ( struct mbuf *rxpkt ) { int rc ; uint8_t packet_data [ 16 ]; struct mbuf *om ; struct my_protocol_header *phdr ; /* Make sure that \"my_protocol_header\" bytes are contiguous in mbuf */ om = os_mbuf_pullup ( &g_mbuf_pool , sizeof ( struct my_protocol_header )); if ( !om ) { /* Not able to pull up data into contiguous area */ return -1 ; } /* * Get the protocol information from the packet. In this example we presume that we * are interested in protocol types that are equal to MY_PROTOCOL_TYPE, are not zero * length, and have had some time in flight. */ phdr = OS_MBUF_DATA ( om , struct my_protocol_header * ); type = ntohs ( phdr->prot_type ); length = ntohs ( phdr->prot_length ); time_in_flight = ntohl ( phdr->prot_tif ); if (( type == MY_PROTOCOL_TYPE ) && ( length > 0 ) && ( time_in_flight > 0 )) { rc = os_mbuf_copydata ( rxpkt , sizeof ( struct my_protocol_header ), 16 , packet_data ); if ( !rc ) { /* Success! Perform operations on packet data */ < ... user code here ... > } } /* Free passed in packet (mbuf chain) since we don't need it anymore */ os_mbuf_free_chain ( om ); }","title":"Using mbufs"},{"location":"os/core_os/mbuf/mbuf/#data-structures","text":"struct os_mbuf_pool { uint16_t omp_databuf_len ; uint16_t omp_mbuf_count ; struct os_mempool *omp_pool ; STAILQ_ENTRY ( os_mbuf_pool ) omp_next ; }; Element Description omp_databuf_len The length, in bytes, of the \"data buffer\" of the mbuf. The data buffer of the mbuf is everything except the os_mbuf structure (which is present in all types of mbufs) omp_mbuf_count Total number of mbufs in the pool when allocated. This is NOT the number of free mbufs in the pool! omp_pool The memory pool from which the mbufs are allocated omp_next This is a linked list pointer which chains memory pools. It is used by the system memory pool library struct os_mbuf_pkthdr { uint16_t omp_len ; uint16_t omp_flags ; STAILQ_ENTRY ( os_mbuf_pkthdr ) omp_next ; }; Element Description omp_len Length, in bytes, of the \"packet\". This is the sum of the user data in all the mbufs chained to the packet header mbuf (including the packet header mbuf) omp_flags Packet header flags. omp_next Linked list pointer to chain \"packets\". This can be used to add mbuf chains to a queue or linked list and is there for convenience. struct os_mbuf { uint8_t *om_data ; uint8_t om_flags ; uint8_t om_pkthdr_len ; uint16_t om_len ; struct os_mbuf_pool *om_omp ; SLIST_ENTRY ( os_mbuf ) om_next ; uint8_t om_databuf [ 0 ]; }; Element Description om_data Pointer to start of user data in mbuf data buffer om_flags mbuf flags field. Currently all flags unused. om_pkthdr_len The total length of all packet headers in the mbuf (mbuf packet header plus user packet header), in bytes om_len The length of the user data contained in this mbuf, in bytes om_omp Memory pool pointer. This is the mbuf pool from which this mbuf was allocated. om_next Pointer to next mbuf in packet chain om_databuf mbuf data buffer (accessor to start of mbuf data buffer). Note that the mbuf data buffer refers to the start of either the user data in normal mbufs or the start of the os mbuf packet header for packet header mbufs","title":"Data Structures"},{"location":"os/core_os/mbuf/mbuf/#list-of-functionsmacros","text":"The functions/macros available in mbuf are: Function/Macro Description OS_MBUF_PKTHDR Get a pointer to the os mbuf packet header of an mbuf. OS_MBUF_PKTHDR_TO_MBUF Get a pointer to the mbuf given a pointer to the os mbuf packet header. OS_MBUF_PKTLEN Get the length of an entire mbuf chain. OS_MBUF_DATA Cast the data pointer of an mbuf to a given type. OS_MBUF_USRHDR Get a pointer to the user packet header of an mbuf. OS_MBUF_USRHDR_LEN Retrieve the length of the user packet header in an mbuf. OS_MBUF_LEADINGSPACE Get the amount of leading space in an mbuf (in bytes). OS_MBUF_TRAILINGSPACE Get the amount of trailing space in an mbuf (in bytes). os_mbuf_adj Trims the given number of bytes from either the head (if positive) or tail (if negative) of an mbuf chain. os_mbuf_append Appends a data buffer of the given length to the end of an mbuf chain. os_mbuf_concat Attaches a second mbuf chain onto the end of the first. os_mbuf_copydata Copy data from an mbuf chain. os_mbuf_copyinto Copies the contents of a flat buffer into an mbuf chain. os_mbuf_dup Duplicate a chain of mbufs. os_mbuf_extend Increases the length of an mbuf chain by the specified amount. os_mbuf_free_chain Frees a chain of mbufs. os_mbuf_get Get an mbuf from the mbuf pool. os_mbuf_get_pkthdr Allocates a packet header mbuf from the given mbuf pool. Adds a user header to the packet header mbuf. os_mbuf_memcmp Performs a memory compare of the specified region of an mbuf chain against a flat buffer. os_mbuf_off Given an offset in the packet, return the mbuf and the offset in that mbuf where byte 'off' is located. os_mbuf_pool_init nitialize an mbuf pool. os_mbuf_prepend Increases the length of an mbuf chain by adding data to the front. os_mbuf_pullup Rearrange an mbuf chain so that the given length of bytes are contiguous and in the data area of an mbuf.","title":"List of Functions/Macros"},{"location":"os/core_os/mbuf/os_mbuf_adj/","text":"os_mbuf_adj void os_mbuf_adj ( struct os_mbuf *mp , int req_len ); Trims req_len bytes from either the head (if positive) or tail (if negative) of an mbuf chain. Adjusts the packet length of the mbuf chain if mp points to a packet header mbuf. When trimming from the head, no mbufs are freed. When trimming from the tail, any mbufs of zero length left at the end of the chain are freed. Arguments Arguments Description mp Pointer to mbuf. Can be head of a chain of mbufs, a single mbuf or a packet header mbuf req_len Number of bytes to trim from head or tail of mbuf Returned values None Notes Example uint16_t pktlen ; struct os_mbuf *om ; struct my_pkt_header hdr ; /* Get mbuf chain length */ pktlen = OS_MBUF_PKTLEN ( om ); /* Strip header from mbuf chain */ os_mbuf_adj ( om , sizeof ( struct my_pkt_header )); pktlen -= sizeof ( struct my_pkt_header ); /* New packet length should be old packet length minus stripped header */ assert ( pktlen == OS_MBUF_PKTLEN ( om ));","title":"os_mbuf_adj"},{"location":"os/core_os/mbuf/os_mbuf_adj/#os_mbuf_adj","text":"void os_mbuf_adj ( struct os_mbuf *mp , int req_len ); Trims req_len bytes from either the head (if positive) or tail (if negative) of an mbuf chain. Adjusts the packet length of the mbuf chain if mp points to a packet header mbuf. When trimming from the head, no mbufs are freed. When trimming from the tail, any mbufs of zero length left at the end of the chain are freed.","title":" os_mbuf_adj"},{"location":"os/core_os/mbuf/os_mbuf_adj/#arguments","text":"Arguments Description mp Pointer to mbuf. Can be head of a chain of mbufs, a single mbuf or a packet header mbuf req_len Number of bytes to trim from head or tail of mbuf","title":"Arguments"},{"location":"os/core_os/mbuf/os_mbuf_adj/#returned-values","text":"None","title":"Returned values"},{"location":"os/core_os/mbuf/os_mbuf_adj/#notes","text":"","title":"Notes"},{"location":"os/core_os/mbuf/os_mbuf_adj/#example","text":"uint16_t pktlen ; struct os_mbuf *om ; struct my_pkt_header hdr ; /* Get mbuf chain length */ pktlen = OS_MBUF_PKTLEN ( om ); /* Strip header from mbuf chain */ os_mbuf_adj ( om , sizeof ( struct my_pkt_header )); pktlen -= sizeof ( struct my_pkt_header ); /* New packet length should be old packet length minus stripped header */ assert ( pktlen == OS_MBUF_PKTLEN ( om ));","title":"Example"},{"location":"os/core_os/mbuf/os_mbuf_append/","text":"os_mbuf_append int os_mbuf_append ( struct os_mbuf *om , const void *data , uint16_t len ) Appends a data buffer of length len to the end of an mbuf chain, adjusting packet length if om is a packet header mbuf. If not enough trailing space exists at the end of the mbuf chain, mbufs are allocated to hold the data. Arguments Arguments Description om Pointer to mbuf. Can be head of a chain of mbufs, a single mbuf or a packet header mbuf data Pointer to data buffer to copy from len Number of bytes to copy from data buffer to the end of the mbuf Returned values 0: success OS_ENOMEM: Could not allocate enough mbufs to hold data. OS_EINVAL: om was NULL on entry. Notes If not enough mbufs were available the packet header length of the mbuf may get adjusted even though the entire data buffer was not appended to the end of the mbuf. If any mbufs are allocated, they are allocated from the same pool as om Example int rc ; uint16_t pktlen ; struct os_mbuf *om ; struct my_data_struct my_data ; /* Get initial packet length */ pktlen = OS_MBUF_PKTLEN ( om ); /* Append \"my_data\" to end of mbuf, freeing mbuf if unable to append all the data */ rc = os_mbuf_append ( om , &my_data , sizeof ( struct my_pkt_header )); if ( rc ) { os_mbuf_free_chain ( om ); } pktlen += sizeof ( struct my_pkt_header ); /* New packet length should be initial packet length plus length of \"my_data\" */ assert ( pktlen == OS_MBUF_PKTLEN ( om ));","title":"os_mbuf_append"},{"location":"os/core_os/mbuf/os_mbuf_append/#os_mbuf_append","text":"int os_mbuf_append ( struct os_mbuf *om , const void *data , uint16_t len ) Appends a data buffer of length len to the end of an mbuf chain, adjusting packet length if om is a packet header mbuf. If not enough trailing space exists at the end of the mbuf chain, mbufs are allocated to hold the data.","title":" os_mbuf_append"},{"location":"os/core_os/mbuf/os_mbuf_append/#arguments","text":"Arguments Description om Pointer to mbuf. Can be head of a chain of mbufs, a single mbuf or a packet header mbuf data Pointer to data buffer to copy from len Number of bytes to copy from data buffer to the end of the mbuf","title":"Arguments"},{"location":"os/core_os/mbuf/os_mbuf_append/#returned-values","text":"0: success OS_ENOMEM: Could not allocate enough mbufs to hold data. OS_EINVAL: om was NULL on entry.","title":"Returned values"},{"location":"os/core_os/mbuf/os_mbuf_append/#notes","text":"If not enough mbufs were available the packet header length of the mbuf may get adjusted even though the entire data buffer was not appended to the end of the mbuf. If any mbufs are allocated, they are allocated from the same pool as om","title":"Notes"},{"location":"os/core_os/mbuf/os_mbuf_append/#example","text":"int rc ; uint16_t pktlen ; struct os_mbuf *om ; struct my_data_struct my_data ; /* Get initial packet length */ pktlen = OS_MBUF_PKTLEN ( om ); /* Append \"my_data\" to end of mbuf, freeing mbuf if unable to append all the data */ rc = os_mbuf_append ( om , &my_data , sizeof ( struct my_pkt_header )); if ( rc ) { os_mbuf_free_chain ( om ); } pktlen += sizeof ( struct my_pkt_header ); /* New packet length should be initial packet length plus length of \"my_data\" */ assert ( pktlen == OS_MBUF_PKTLEN ( om ));","title":"Example"},{"location":"os/core_os/mbuf/os_mbuf_concat/","text":"os_mbuf_concat void os_mbuf_concat ( struct os_mbuf *first , struct os_mbuf *second ) Attaches a second mbuf chain onto the end of the first. If the first chain contains a packet header, the header's length is updated. If the second chain has a packet header, its header is cleared. Arguments Arguments Description first Pointer to first mbuf chain second Pointer to second mbuf chain Returned values None Notes No data is copied or moved nor are any mbufs freed. Example uint16_t pktlen1 ; uint16_t pktlen2 ; struct os_mbuf *pkt1 ; struct os_mbuf *pkt2 ; /* Get initial packet lengths */ pktlen1 = OS_MBUF_PKTLEN ( pkt1 ); pktlen2 = OS_MBUF_PKTLEN ( pkt2 ); /* Add pkt2 to end of pkt1 */ os_mbuf_concat ( pkt1 , pkt2 ); /* New packet length should be sum of pkt1 and pkt2 */ assert (( pktlen1 + pktlen2 ) == OS_MBUF_PKTLEN ( pkt1 ));","title":"os_mbuf_concat"},{"location":"os/core_os/mbuf/os_mbuf_concat/#os_mbuf_concat","text":"void os_mbuf_concat ( struct os_mbuf *first , struct os_mbuf *second ) Attaches a second mbuf chain onto the end of the first. If the first chain contains a packet header, the header's length is updated. If the second chain has a packet header, its header is cleared.","title":" os_mbuf_concat"},{"location":"os/core_os/mbuf/os_mbuf_concat/#arguments","text":"Arguments Description first Pointer to first mbuf chain second Pointer to second mbuf chain","title":"Arguments"},{"location":"os/core_os/mbuf/os_mbuf_concat/#returned-values","text":"None","title":"Returned values"},{"location":"os/core_os/mbuf/os_mbuf_concat/#notes","text":"No data is copied or moved nor are any mbufs freed.","title":"Notes"},{"location":"os/core_os/mbuf/os_mbuf_concat/#example","text":"uint16_t pktlen1 ; uint16_t pktlen2 ; struct os_mbuf *pkt1 ; struct os_mbuf *pkt2 ; /* Get initial packet lengths */ pktlen1 = OS_MBUF_PKTLEN ( pkt1 ); pktlen2 = OS_MBUF_PKTLEN ( pkt2 ); /* Add pkt2 to end of pkt1 */ os_mbuf_concat ( pkt1 , pkt2 ); /* New packet length should be sum of pkt1 and pkt2 */ assert (( pktlen1 + pktlen2 ) == OS_MBUF_PKTLEN ( pkt1 ));","title":"Example"},{"location":"os/core_os/mbuf/os_mbuf_copydata/","text":"os_mbuf_copydata int os_mbuf_copydata ( const struct os_mbuf *m , int off , int len , void *dst ) Copy data from an mbuf chain starting off bytes from the beginning, continuing for len bytes, into the indicated buffer. Arguments Arguments Description m Pointer to mbuf chain off Start copy offset, in bytes, from beginning of mbuf chain len Number of bytes to copy dst Data buffer to copy into Returned values 0: success. -1: The mbuf does not contain enough data Example int rc ; struct os_mbuf *om ; struct my_hdr_1 my_hdr1 ; struct my_hdr_2 my_hdr2 ; /* Header 1 and Header 2 are contiguous in packet at start. Retrieve them from the mbuf chain */ rc = os_mbuf_copydata ( om , 0 , sizeof ( struct my_hdr_1 ), &my_hdr1 ); if ( rc ) { /* error! */ return -1 ; } rc = os_mbuf_copydata ( om , sizeof ( struct my_hdr_1 ), sizeof ( struct my_hdr_2 ), &my_hdr2 ); if ( rc ) { /* error! */ return -1 ; }","title":"os_mbuf_copydata"},{"location":"os/core_os/mbuf/os_mbuf_copydata/#os_mbuf_copydata","text":"int os_mbuf_copydata ( const struct os_mbuf *m , int off , int len , void *dst ) Copy data from an mbuf chain starting off bytes from the beginning, continuing for len bytes, into the indicated buffer.","title":" os_mbuf_copydata"},{"location":"os/core_os/mbuf/os_mbuf_copydata/#arguments","text":"Arguments Description m Pointer to mbuf chain off Start copy offset, in bytes, from beginning of mbuf chain len Number of bytes to copy dst Data buffer to copy into","title":"Arguments"},{"location":"os/core_os/mbuf/os_mbuf_copydata/#returned-values","text":"0: success. -1: The mbuf does not contain enough data","title":"Returned values"},{"location":"os/core_os/mbuf/os_mbuf_copydata/#example","text":"int rc ; struct os_mbuf *om ; struct my_hdr_1 my_hdr1 ; struct my_hdr_2 my_hdr2 ; /* Header 1 and Header 2 are contiguous in packet at start. Retrieve them from the mbuf chain */ rc = os_mbuf_copydata ( om , 0 , sizeof ( struct my_hdr_1 ), &my_hdr1 ); if ( rc ) { /* error! */ return -1 ; } rc = os_mbuf_copydata ( om , sizeof ( struct my_hdr_1 ), sizeof ( struct my_hdr_2 ), &my_hdr2 ); if ( rc ) { /* error! */ return -1 ; }","title":"Example"},{"location":"os/core_os/mbuf/os_mbuf_copyinto/","text":"os_mbuf_copyinto int os_mbuf_copyinto ( struct os_mbuf *om , int off , const void *src , int len ); Copies the contents of a flat buffer into an mbuf chain, starting at the specified destination offset. If the mbuf is too small for the source data, it is extended as necessary. If the destination mbuf contains a packet header, the header length is updated. Arguments Arguments Description om Pointer to mbuf chain off Start copy offset, in bytes, from beginning of mbuf chain src Address from which bytes are copied len Number of bytes to copy from src Returned values 0: success. All other values indicate an error. Example int rc ; uint16_t pktlen ; struct os_mbuf *om ; struct my_data_struct my_data ; /* Get initial packet length */ pktlen = OS_MBUF_PKTLEN ( om ); /* Copy \"my_data\" into mbuf */ rc = os_mbuf_copyinto ( om , 0 , &my_data , sizeof ( struct my_data_struct )); if ( rc ) { os_mbuf_free_chain ( om ); return ; } /* Packet length should have increased by size of \"my_data\" */ pktlen += sizeof ( struct my_data_struct ); assert ( pktlen == OS_MBUF_PKTLEN ( om ));","title":"os_mbuf_copyinto"},{"location":"os/core_os/mbuf/os_mbuf_copyinto/#os_mbuf_copyinto","text":"int os_mbuf_copyinto ( struct os_mbuf *om , int off , const void *src , int len ); Copies the contents of a flat buffer into an mbuf chain, starting at the specified destination offset. If the mbuf is too small for the source data, it is extended as necessary. If the destination mbuf contains a packet header, the header length is updated.","title":" os_mbuf_copyinto"},{"location":"os/core_os/mbuf/os_mbuf_copyinto/#arguments","text":"Arguments Description om Pointer to mbuf chain off Start copy offset, in bytes, from beginning of mbuf chain src Address from which bytes are copied len Number of bytes to copy from src","title":"Arguments"},{"location":"os/core_os/mbuf/os_mbuf_copyinto/#returned-values","text":"0: success. All other values indicate an error.","title":"Returned values"},{"location":"os/core_os/mbuf/os_mbuf_copyinto/#example","text":"int rc ; uint16_t pktlen ; struct os_mbuf *om ; struct my_data_struct my_data ; /* Get initial packet length */ pktlen = OS_MBUF_PKTLEN ( om ); /* Copy \"my_data\" into mbuf */ rc = os_mbuf_copyinto ( om , 0 , &my_data , sizeof ( struct my_data_struct )); if ( rc ) { os_mbuf_free_chain ( om ); return ; } /* Packet length should have increased by size of \"my_data\" */ pktlen += sizeof ( struct my_data_struct ); assert ( pktlen == OS_MBUF_PKTLEN ( om ));","title":"Example"},{"location":"os/core_os/mbuf/os_mbuf_dup/","text":"os_mbuf_dup struct os_mbuf *os_mbuf_dup ( struct os_mbuf *om ) Duplicate a chain of mbufs. Return the start of the duplicated chain. Arguments Arguments Description om Pointer to mbuf chain to duplicate Returned values Pointer to the duplicated chain or NULL if not enough mbufs were available to duplicate the chain. Example struct os_mbuf *om ; struct os_mbuf *new_om ; /* Make a copy of om, returning -1 if not able to duplicate om */ new_om = os_mbuf_dup ( om ); if ( !new_om ) { return -1 ; }","title":"os_mbuf_dup"},{"location":"os/core_os/mbuf/os_mbuf_dup/#os_mbuf_dup","text":"struct os_mbuf *os_mbuf_dup ( struct os_mbuf *om ) Duplicate a chain of mbufs. Return the start of the duplicated chain.","title":" os_mbuf_dup"},{"location":"os/core_os/mbuf/os_mbuf_dup/#arguments","text":"Arguments Description om Pointer to mbuf chain to duplicate","title":"Arguments"},{"location":"os/core_os/mbuf/os_mbuf_dup/#returned-values","text":"Pointer to the duplicated chain or NULL if not enough mbufs were available to duplicate the chain.","title":"Returned values"},{"location":"os/core_os/mbuf/os_mbuf_dup/#example","text":"struct os_mbuf *om ; struct os_mbuf *new_om ; /* Make a copy of om, returning -1 if not able to duplicate om */ new_om = os_mbuf_dup ( om ); if ( !new_om ) { return -1 ; }","title":"Example"},{"location":"os/core_os/mbuf/os_mbuf_extend/","text":"os_mbuf_extend void *os_mbuf_extend ( struct os_mbuf *om , uint16_t len ); Increases the length of an mbuf chain by the specified amount. If there is not sufficient room in the last buffer, a new buffer is allocated and appended to the chain. It is an error to request more data than can fit in a single buffer. Arguments Arguments Description om Pointer to mbuf chain len Number of bytes to increase packet header Returned values Pointer to start of extended data. Caller is guaranteed that there are at least len bytes from this pointer to the end of the mbuf. Returns NULL if extension fails due to insufficient mbufs or len too large. Example uint8_t *dptr ; struct os_mbuf *om ; struct my_data_struct my_data ; /* Obtain enough room to add \"my_data\" to an mbuf chain */ dptr = os_mbuf_extend ( om , sizeof ( struct my_data_struct )); if ( dptr ) { memcpy ( dptr , &my_data , sizeof ( struct my_data_struct )); }","title":"os_mbuf_extend"},{"location":"os/core_os/mbuf/os_mbuf_extend/#os_mbuf_extend","text":"void *os_mbuf_extend ( struct os_mbuf *om , uint16_t len ); Increases the length of an mbuf chain by the specified amount. If there is not sufficient room in the last buffer, a new buffer is allocated and appended to the chain. It is an error to request more data than can fit in a single buffer.","title":" os_mbuf_extend"},{"location":"os/core_os/mbuf/os_mbuf_extend/#arguments","text":"Arguments Description om Pointer to mbuf chain len Number of bytes to increase packet header","title":"Arguments"},{"location":"os/core_os/mbuf/os_mbuf_extend/#returned-values","text":"Pointer to start of extended data. Caller is guaranteed that there are at least len bytes from this pointer to the end of the mbuf. Returns NULL if extension fails due to insufficient mbufs or len too large.","title":"Returned values"},{"location":"os/core_os/mbuf/os_mbuf_extend/#example","text":"uint8_t *dptr ; struct os_mbuf *om ; struct my_data_struct my_data ; /* Obtain enough room to add \"my_data\" to an mbuf chain */ dptr = os_mbuf_extend ( om , sizeof ( struct my_data_struct )); if ( dptr ) { memcpy ( dptr , &my_data , sizeof ( struct my_data_struct )); }","title":"Example"},{"location":"os/core_os/mbuf/os_mbuf_free_chain/","text":"os_mbuf_free_chain int os_mbuf_free_chain ( struct os_mbuf *om ); Frees a chain of mbufs Arguments Arguments Description om Pointer to mbuf chain Returned values 0: success Any other value indicates error Notes Note that for each mbuf in the chain, os_mbuf_free() is called. Example int rc ; struct os_mbuf *om ; /* Free mbuf chain */ rc = os_mbuf_free_chain ( om ); assert ( rc == 0 );","title":"os_mbuf_free_chain"},{"location":"os/core_os/mbuf/os_mbuf_free_chain/#os_mbuf_free_chain","text":"int os_mbuf_free_chain ( struct os_mbuf *om ); Frees a chain of mbufs","title":" os_mbuf_free_chain"},{"location":"os/core_os/mbuf/os_mbuf_free_chain/#arguments","text":"Arguments Description om Pointer to mbuf chain","title":"Arguments"},{"location":"os/core_os/mbuf/os_mbuf_free_chain/#returned-values","text":"0: success Any other value indicates error","title":"Returned values"},{"location":"os/core_os/mbuf/os_mbuf_free_chain/#notes","text":"Note that for each mbuf in the chain, os_mbuf_free() is called.","title":"Notes"},{"location":"os/core_os/mbuf/os_mbuf_free_chain/#example","text":"int rc ; struct os_mbuf *om ; /* Free mbuf chain */ rc = os_mbuf_free_chain ( om ); assert ( rc == 0 );","title":"Example"},{"location":"os/core_os/mbuf/os_mbuf_get/","text":"os_mbuf_get struct os_mbuf *os_mbuf_get ( struct os_mbuf_pool *omp , uint16_t leadingspace ) Get an mbuf from the mbuf pool. The mbuf is allocated, and initialized prior to being returned. The leadingspace parameter allows the user to specify the amount of leading space in the allocated mbuf. Arguments Arguments Description om Pointer to mbuf pool from which to allocate mbuf leadingspace Amount of leading space in allocated mbuf. Request cannot exceed the mbuf data buffer size. Returned values Returns a pointer to the allocated mbuf or NULL if there are no mbufs available or leadingspace was too large. Notes In most typical applications, the application developer does not need to call os_mbuf_get() ; the other API will do this automatically. However, this API is provided for convenience as mbufs can also be a simple way to allocate temporary chunks of memory. Example struct os_mbuf *om ; /* Get an mbuf */ om = os_mbuf_get ( &g_mbuf_pool , 0 ); if ( om ) { /* we have allocated an mbuf from the pool */ }","title":"os_mbuf_get"},{"location":"os/core_os/mbuf/os_mbuf_get/#os_mbuf_get","text":"struct os_mbuf *os_mbuf_get ( struct os_mbuf_pool *omp , uint16_t leadingspace ) Get an mbuf from the mbuf pool. The mbuf is allocated, and initialized prior to being returned. The leadingspace parameter allows the user to specify the amount of leading space in the allocated mbuf.","title":"os_mbuf_get"},{"location":"os/core_os/mbuf/os_mbuf_get/#arguments","text":"Arguments Description om Pointer to mbuf pool from which to allocate mbuf leadingspace Amount of leading space in allocated mbuf. Request cannot exceed the mbuf data buffer size.","title":"Arguments"},{"location":"os/core_os/mbuf/os_mbuf_get/#returned-values","text":"Returns a pointer to the allocated mbuf or NULL if there are no mbufs available or leadingspace was too large.","title":"Returned values"},{"location":"os/core_os/mbuf/os_mbuf_get/#notes","text":"In most typical applications, the application developer does not need to call os_mbuf_get() ; the other API will do this automatically. However, this API is provided for convenience as mbufs can also be a simple way to allocate temporary chunks of memory.","title":"Notes"},{"location":"os/core_os/mbuf/os_mbuf_get/#example","text":"struct os_mbuf *om ; /* Get an mbuf */ om = os_mbuf_get ( &g_mbuf_pool , 0 ); if ( om ) { /* we have allocated an mbuf from the pool */ }","title":"Example"},{"location":"os/core_os/mbuf/os_mbuf_get_pkthdr/","text":"os_mbuf_get_pkthdr struct os_mbuf *os_mbuf_get_pkthdr ( struct os_mbuf_pool *omp , uint8_t pkthdr_len ); Allocates a packet header mbuf from the mbuf pool pointed to by omp . Adds a user header of length pkthdr_len to packet header mbuf. Arguments Arguments Description om Pointer to mbuf pool from which to allocate mbuf pkthdr_len The user header packet length to allocate for the packet header mbuf Returned values Returns a pointer to the allocated mbuf or NULL if there are no mbufs available or the user packet header was too large. Notes The packet header mbuf returned will have its data pointer incremented by the sizeof(struct os_mbuf_pkthdr) as well as the amount of user header data (i.e. pkthdr_len ). In other words, the data pointer is offset from the start of the mbuf by: sizeof(struct os_mbuf) + sizeof(struct os_mbuf_pkthdr) + pkthdr_len. The om_pkthdr_len element in the allocated mbuf is set to: sizeof(struct os_mbuf_pkthdr) + pkthdr_len. Example struct os_mbuf *om ; struct my_user_header my_hdr ; /* Get a packet header mbuf with a user header in it */ om = os_mbuf_get_pkthdr ( &g_mbuf_pool , sizeof ( struct my_user_header )); if ( om ) { /* Packet header mbuf was allocated */ }","title":"os_mbuf_get_pkthdr"},{"location":"os/core_os/mbuf/os_mbuf_get_pkthdr/#os_mbuf_get_pkthdr","text":"struct os_mbuf *os_mbuf_get_pkthdr ( struct os_mbuf_pool *omp , uint8_t pkthdr_len ); Allocates a packet header mbuf from the mbuf pool pointed to by omp . Adds a user header of length pkthdr_len to packet header mbuf.","title":"os_mbuf_get_pkthdr"},{"location":"os/core_os/mbuf/os_mbuf_get_pkthdr/#arguments","text":"Arguments Description om Pointer to mbuf pool from which to allocate mbuf pkthdr_len The user header packet length to allocate for the packet header mbuf","title":"Arguments"},{"location":"os/core_os/mbuf/os_mbuf_get_pkthdr/#returned-values","text":"Returns a pointer to the allocated mbuf or NULL if there are no mbufs available or the user packet header was too large.","title":"Returned values"},{"location":"os/core_os/mbuf/os_mbuf_get_pkthdr/#notes","text":"The packet header mbuf returned will have its data pointer incremented by the sizeof(struct os_mbuf_pkthdr) as well as the amount of user header data (i.e. pkthdr_len ). In other words, the data pointer is offset from the start of the mbuf by: sizeof(struct os_mbuf) + sizeof(struct os_mbuf_pkthdr) + pkthdr_len. The om_pkthdr_len element in the allocated mbuf is set to: sizeof(struct os_mbuf_pkthdr) + pkthdr_len.","title":"Notes"},{"location":"os/core_os/mbuf/os_mbuf_get_pkthdr/#example","text":"struct os_mbuf *om ; struct my_user_header my_hdr ; /* Get a packet header mbuf with a user header in it */ om = os_mbuf_get_pkthdr ( &g_mbuf_pool , sizeof ( struct my_user_header )); if ( om ) { /* Packet header mbuf was allocated */ }","title":"Example"},{"location":"os/core_os/mbuf/os_mbuf_memcmp/","text":"os_mbuf_memcmp int os_mbuf_memcmp ( const struct os_mbuf *om , int off , const void *data , int len ) Performs a memory compare of the specified region of an mbuf chain against a flat buffer. Arguments Arguments Description om Pointer to mbuf off Offset, in bytes, from start of mbuf to start of comparison data Pointer to flat data buffer to compare len Number of bytes to compare Returned values A value of zero means the memory regions are identical; all other values represent either an error or a value returned from memcmp. Notes This function will compare bytes starting from off bytes from the start of the mbuf chain with a data buffer. Example int rc ; struct os_mbuf *om ; uint8_t my_data_buffer [ 32 ]; /* Get a packet header mbuf with a user header in it */ rc = os_mbuf_memcmp ( om , 0 , my_data_buffer , 32 ); if ( !rc ) { /* \"my_data_buffer\" and the data from offset 0 in the mbuf chain are identical! */ }","title":"os_mbuf_memcmp"},{"location":"os/core_os/mbuf/os_mbuf_memcmp/#os_mbuf_memcmp","text":"int os_mbuf_memcmp ( const struct os_mbuf *om , int off , const void *data , int len ) Performs a memory compare of the specified region of an mbuf chain against a flat buffer.","title":"os_mbuf_memcmp"},{"location":"os/core_os/mbuf/os_mbuf_memcmp/#arguments","text":"Arguments Description om Pointer to mbuf off Offset, in bytes, from start of mbuf to start of comparison data Pointer to flat data buffer to compare len Number of bytes to compare","title":"Arguments"},{"location":"os/core_os/mbuf/os_mbuf_memcmp/#returned-values","text":"A value of zero means the memory regions are identical; all other values represent either an error or a value returned from memcmp.","title":"Returned values"},{"location":"os/core_os/mbuf/os_mbuf_memcmp/#notes","text":"This function will compare bytes starting from off bytes from the start of the mbuf chain with a data buffer.","title":"Notes"},{"location":"os/core_os/mbuf/os_mbuf_memcmp/#example","text":"int rc ; struct os_mbuf *om ; uint8_t my_data_buffer [ 32 ]; /* Get a packet header mbuf with a user header in it */ rc = os_mbuf_memcmp ( om , 0 , my_data_buffer , 32 ); if ( !rc ) { /* \"my_data_buffer\" and the data from offset 0 in the mbuf chain are identical! */ }","title":"Example"},{"location":"os/core_os/mbuf/os_mbuf_off/","text":"os_mbuf_off struct os_mbuf *os_mbuf_off ( struct os_mbuf *om , int off , int *out_off ) Given an offset in the packet (i.e. user data byte offset in the mbuf chain), return the mbuf and the offset in that mbuf where byte 'off' is located. Note that the offset is 'returned' in out_off . Arguments Arguments Description om Pointer to mbuf off Location in mbuf chain of desired byte offset out_off Pointer to storage for the relative offset of the absolute location in the returned mbuf Returned values NULL if the offset is not within the mbuf chain or om points to NULL. Notes The user is allowed to call this function with the length of the mbuf chain but no greater. This allows the user to get the mbuf and offset (in that mbuf) where the next user data byte should be written. While this api is provided to the user, other API are expected to be used by the applciation developer (i.e. os_mbuf_append() or os_mbuf_copyinto() ). Example int relative_offset ; uint16_t pktlen ; struct os_mbuf *om ; struct os_mbuf *tmp ; /* Append a new line character to end of mbuf data */ pktlen = OS_MBUF_PKTLEN ( om ); relative_offset = 0 ; tmp = os_mbuf_off ( om , pktlen , &relative_offset ); if ( tmp ) { /* Offset found. */ tmp->om_data [ relative_offset ] = '\\n' ; } else { /* * This mbuf does not contain enough bytes so this is an invalid offset. * In other words, the mbuf is less than 62 bytes in length. */ }","title":"os_mbuf_off"},{"location":"os/core_os/mbuf/os_mbuf_off/#os_mbuf_off","text":"struct os_mbuf *os_mbuf_off ( struct os_mbuf *om , int off , int *out_off ) Given an offset in the packet (i.e. user data byte offset in the mbuf chain), return the mbuf and the offset in that mbuf where byte 'off' is located. Note that the offset is 'returned' in out_off .","title":"os_mbuf_off"},{"location":"os/core_os/mbuf/os_mbuf_off/#arguments","text":"Arguments Description om Pointer to mbuf off Location in mbuf chain of desired byte offset out_off Pointer to storage for the relative offset of the absolute location in the returned mbuf","title":"Arguments"},{"location":"os/core_os/mbuf/os_mbuf_off/#returned-values","text":"NULL if the offset is not within the mbuf chain or om points to NULL.","title":"Returned values"},{"location":"os/core_os/mbuf/os_mbuf_off/#notes","text":"The user is allowed to call this function with the length of the mbuf chain but no greater. This allows the user to get the mbuf and offset (in that mbuf) where the next user data byte should be written. While this api is provided to the user, other API are expected to be used by the applciation developer (i.e. os_mbuf_append() or os_mbuf_copyinto() ).","title":"Notes"},{"location":"os/core_os/mbuf/os_mbuf_off/#example","text":"int relative_offset ; uint16_t pktlen ; struct os_mbuf *om ; struct os_mbuf *tmp ; /* Append a new line character to end of mbuf data */ pktlen = OS_MBUF_PKTLEN ( om ); relative_offset = 0 ; tmp = os_mbuf_off ( om , pktlen , &relative_offset ); if ( tmp ) { /* Offset found. */ tmp->om_data [ relative_offset ] = '\\n' ; } else { /* * This mbuf does not contain enough bytes so this is an invalid offset. * In other words, the mbuf is less than 62 bytes in length. */ }","title":"Example"},{"location":"os/core_os/mbuf/os_mbuf_pool_init/","text":"os_mbuf_pool_init int os_mbuf_pool_init ( struct os_mbuf_pool *omp , struct os_mempool *mp , uint16_t buf_len , uint16_t nbufs ) Initialize an mbuf pool Arguments Arguments Description omp Pointer to mbuf pool to initialize mp Pointer to memory pool used by mbuf pool buf_len The size of the memory blocks in the memory pool used by the mbuf pool nbufs The number of mbufs in the pool Returned values 0 on success; all other values indicate an error. Notes The parameter buf_len is the total size of the memory block. This must accommodate the os_mbuf structure, the os_mbuf_pkthdr structure, any user headers plus the desired amount of user data. Example #define MBUF_PKTHDR_OVERHEAD sizeof(struct os_mbuf_pkthdr) + sizeof(struct user_hdr) #define MBUF_MEMBLOCK_OVERHEAD sizeof(struct os_mbuf) + MBUF_PKTHDR_OVERHEAD #define MBUF_NUM_MBUFS (32) #define MBUF_PAYLOAD_SIZE (64) #define MBUF_BUF_SIZE OS_ALIGN(MBUF_PAYLOAD_SIZE, 4) #define MBUF_MEMBLOCK_SIZE (MBUF_BUF_SIZE + MBUF_MEMBLOCK_OVERHEAD) #define MBUF_MEMPOOL_SIZE OS_MEMPOOL_SIZE(MBUF_NUM_MBUFS, MBUF_MEMBLOCK_SIZE) struct os_mbuf_pool g_mbuf_pool ; struct os_mempool g_mbuf_mempool ; os_membuf_t g_mbuf_buffer [ MBUF_MEMPOOL_SIZE ]; void create_mbuf_pool ( void ) { int rc ; rc = os_mempool_init ( &g_mbuf_mempool , MBUF_NUM_MBUFS , MBUF_MEMBLOCK_SIZE , &g_mbuf_buffer [ 0 ], \"mbuf_pool\" ); assert ( rc == 0 ); rc = os_mbuf_pool_init ( &g_mbuf_pool , &g_mbuf_mempool , MBUF_MEMBLOCK_SIZE , MBUF_NUM_MBUFS ); assert ( rc == 0 ); }","title":"os_mbuf_pool_init"},{"location":"os/core_os/mbuf/os_mbuf_pool_init/#os_mbuf_pool_init","text":"int os_mbuf_pool_init ( struct os_mbuf_pool *omp , struct os_mempool *mp , uint16_t buf_len , uint16_t nbufs ) Initialize an mbuf pool","title":"os_mbuf_pool_init"},{"location":"os/core_os/mbuf/os_mbuf_pool_init/#arguments","text":"Arguments Description omp Pointer to mbuf pool to initialize mp Pointer to memory pool used by mbuf pool buf_len The size of the memory blocks in the memory pool used by the mbuf pool nbufs The number of mbufs in the pool","title":"Arguments"},{"location":"os/core_os/mbuf/os_mbuf_pool_init/#returned-values","text":"0 on success; all other values indicate an error.","title":"Returned values"},{"location":"os/core_os/mbuf/os_mbuf_pool_init/#notes","text":"The parameter buf_len is the total size of the memory block. This must accommodate the os_mbuf structure, the os_mbuf_pkthdr structure, any user headers plus the desired amount of user data.","title":"Notes"},{"location":"os/core_os/mbuf/os_mbuf_pool_init/#example","text":"#define MBUF_PKTHDR_OVERHEAD sizeof(struct os_mbuf_pkthdr) + sizeof(struct user_hdr) #define MBUF_MEMBLOCK_OVERHEAD sizeof(struct os_mbuf) + MBUF_PKTHDR_OVERHEAD #define MBUF_NUM_MBUFS (32) #define MBUF_PAYLOAD_SIZE (64) #define MBUF_BUF_SIZE OS_ALIGN(MBUF_PAYLOAD_SIZE, 4) #define MBUF_MEMBLOCK_SIZE (MBUF_BUF_SIZE + MBUF_MEMBLOCK_OVERHEAD) #define MBUF_MEMPOOL_SIZE OS_MEMPOOL_SIZE(MBUF_NUM_MBUFS, MBUF_MEMBLOCK_SIZE) struct os_mbuf_pool g_mbuf_pool ; struct os_mempool g_mbuf_mempool ; os_membuf_t g_mbuf_buffer [ MBUF_MEMPOOL_SIZE ]; void create_mbuf_pool ( void ) { int rc ; rc = os_mempool_init ( &g_mbuf_mempool , MBUF_NUM_MBUFS , MBUF_MEMBLOCK_SIZE , &g_mbuf_buffer [ 0 ], \"mbuf_pool\" ); assert ( rc == 0 ); rc = os_mbuf_pool_init ( &g_mbuf_pool , &g_mbuf_mempool , MBUF_MEMBLOCK_SIZE , MBUF_NUM_MBUFS ); assert ( rc == 0 ); }","title":"Example"},{"location":"os/core_os/mbuf/os_mbuf_prepend/","text":"os_mbuf_prepend struct os_mbuf *os_mbuf_prepend ( struct os_mbuf *om , int len ) Increases the length of an mbuf chain by adding data to the front. If there is insufficient room in the leading mbuf, additional mbufs are allocated and prepended as necessary. If this function fails to allocate an mbuf, the entire chain is freed. Arguments Arguments Description om Pointer to mbuf len Length, in bytes, to prepend Returned values Pointer to mbuf at head of chain; NULL if not enough mbufs were available to accommodate len . Notes If om is a packet header mbuf, the total length of the packet is adjusted by len . Note that the returned mbuf may not point to om if insufficient leading space was available in om . Example uint16_t pktlen ; struct os_mbuf *om ; struct os_mbuf *tmp ; /* Get initial packet length before prepend */ pktlen = OS_MBUF_PKTLEN ( om ); tmp = os_mbuf_prepend ( om , 32 ); if ( !tmp ) { /* Not able to prepend. The chain pointed to by *om has been freed */ return -1 ; } /* The packet length should equal the original length plus what we prepended */ assert (( pktlen + 32 ) == OS_MBUF_PKTLEN ( tmp ));","title":"os_mbuf_prepend"},{"location":"os/core_os/mbuf/os_mbuf_prepend/#os_mbuf_prepend","text":"struct os_mbuf *os_mbuf_prepend ( struct os_mbuf *om , int len ) Increases the length of an mbuf chain by adding data to the front. If there is insufficient room in the leading mbuf, additional mbufs are allocated and prepended as necessary. If this function fails to allocate an mbuf, the entire chain is freed.","title":"os_mbuf_prepend"},{"location":"os/core_os/mbuf/os_mbuf_prepend/#arguments","text":"Arguments Description om Pointer to mbuf len Length, in bytes, to prepend","title":"Arguments"},{"location":"os/core_os/mbuf/os_mbuf_prepend/#returned-values","text":"Pointer to mbuf at head of chain; NULL if not enough mbufs were available to accommodate len .","title":"Returned values"},{"location":"os/core_os/mbuf/os_mbuf_prepend/#notes","text":"If om is a packet header mbuf, the total length of the packet is adjusted by len . Note that the returned mbuf may not point to om if insufficient leading space was available in om .","title":"Notes"},{"location":"os/core_os/mbuf/os_mbuf_prepend/#example","text":"uint16_t pktlen ; struct os_mbuf *om ; struct os_mbuf *tmp ; /* Get initial packet length before prepend */ pktlen = OS_MBUF_PKTLEN ( om ); tmp = os_mbuf_prepend ( om , 32 ); if ( !tmp ) { /* Not able to prepend. The chain pointed to by *om has been freed */ return -1 ; } /* The packet length should equal the original length plus what we prepended */ assert (( pktlen + 32 ) == OS_MBUF_PKTLEN ( tmp ));","title":"Example"},{"location":"os/core_os/mbuf/os_mbuf_pullup/","text":"os_mbuf_pullup struct os_mbuf *os_mbuf_pullup ( struct os_mbuf *om , uint16_t len ) Rearrange an mbuf chain so that len bytes are contiguous, and in the data area of an mbuf (so that OS_MBUF_DATA() will work on a structure of size len.) Returns the resulting mbuf chain on success, free's it and returns NULL on failure. Arguments Arguments Description om Pointer to mbuf len Length, in bytes, to pullup (make contiguous in mbuf) Returned values Pointer to mbuf at head of chain; NULL if not enough mbufs were available to accommodate len or if the requested pullup size was too large. Notes Hopefully it is apparent to the user that you cannot pullup more bytes than the mbuf can accommodate. Pullup does not allocate more than one mbuf; the entire pullup length must be contained within a single mbuf. The mbuf that is being pulled up into does not need to be a packet header mbuf; it can be a normal mbuf. The user should note that the maximum pullup length does depend on the type of mbuf being pulled up into (a packet header or normal mbuf). Example struct os_mbuf *om ; struct os_mbuf *tmp ; struct my_header_struct my_header ; /* Make sure \"my_header\" is contiguous in the mbuf */ tmp = os_mbuf_pullup ( om , sizeof ( my_header_struct )); if ( !tmp ) { /* Pullup failed. The chain pointed to by *om has been freed */ return -1 ; } /* copy data from mbuf into header structure */ memcpy ( &my_header , tmp->om_data , sizeof ( struct my_header_struct ));","title":"os_mbuf_pullup"},{"location":"os/core_os/mbuf/os_mbuf_pullup/#os_mbuf_pullup","text":"struct os_mbuf *os_mbuf_pullup ( struct os_mbuf *om , uint16_t len ) Rearrange an mbuf chain so that len bytes are contiguous, and in the data area of an mbuf (so that OS_MBUF_DATA() will work on a structure of size len.) Returns the resulting mbuf chain on success, free's it and returns NULL on failure.","title":"os_mbuf_pullup"},{"location":"os/core_os/mbuf/os_mbuf_pullup/#arguments","text":"Arguments Description om Pointer to mbuf len Length, in bytes, to pullup (make contiguous in mbuf)","title":"Arguments"},{"location":"os/core_os/mbuf/os_mbuf_pullup/#returned-values","text":"Pointer to mbuf at head of chain; NULL if not enough mbufs were available to accommodate len or if the requested pullup size was too large.","title":"Returned values"},{"location":"os/core_os/mbuf/os_mbuf_pullup/#notes","text":"Hopefully it is apparent to the user that you cannot pullup more bytes than the mbuf can accommodate. Pullup does not allocate more than one mbuf; the entire pullup length must be contained within a single mbuf. The mbuf that is being pulled up into does not need to be a packet header mbuf; it can be a normal mbuf. The user should note that the maximum pullup length does depend on the type of mbuf being pulled up into (a packet header or normal mbuf).","title":"Notes"},{"location":"os/core_os/mbuf/os_mbuf_pullup/#example","text":"struct os_mbuf *om ; struct os_mbuf *tmp ; struct my_header_struct my_header ; /* Make sure \"my_header\" is contiguous in the mbuf */ tmp = os_mbuf_pullup ( om , sizeof ( my_header_struct )); if ( !tmp ) { /* Pullup failed. The chain pointed to by *om has been freed */ return -1 ; } /* copy data from mbuf into header structure */ memcpy ( &my_header , tmp->om_data , sizeof ( struct my_header_struct ));","title":"Example"},{"location":"os/core_os/memory_pool/OS_MEMPOOL_BYTES/","text":"OS_MEMPOOL_BYTES OS_MEMPOOL_BYTES ( n , blksize ) Calculates how many bytes of memory is used by n number of elements, when individual element size is blksize bytes. Arguments Arguments Description n Number of elements blksize Size of an element is number of bytes Returned values The number of bytes used by the memory pool. Notes OS_MEMPOOL_BYTES is a macro and not a function. Example Here we allocate memory to be used as a pool. void *nffs_file_mem ; nffs_file_mem = malloc ( OS_MEMPOOL_BYTES ( nffs_config . nc_num_files , sizeof ( struct nffs_file ))); if ( nffs_file_mem == NULL ) { return FS_ENOMEM ; }","title":"OS_MEMPOOL_BYTES"},{"location":"os/core_os/memory_pool/OS_MEMPOOL_BYTES/#os_mempool_bytes","text":"OS_MEMPOOL_BYTES ( n , blksize ) Calculates how many bytes of memory is used by n number of elements, when individual element size is blksize bytes.","title":"OS_MEMPOOL_BYTES"},{"location":"os/core_os/memory_pool/OS_MEMPOOL_BYTES/#arguments","text":"Arguments Description n Number of elements blksize Size of an element is number of bytes","title":"Arguments"},{"location":"os/core_os/memory_pool/OS_MEMPOOL_BYTES/#returned-values","text":"The number of bytes used by the memory pool.","title":"Returned values"},{"location":"os/core_os/memory_pool/OS_MEMPOOL_BYTES/#notes","text":"OS_MEMPOOL_BYTES is a macro and not a function.","title":"Notes"},{"location":"os/core_os/memory_pool/OS_MEMPOOL_BYTES/#example","text":"Here we allocate memory to be used as a pool. void *nffs_file_mem ; nffs_file_mem = malloc ( OS_MEMPOOL_BYTES ( nffs_config . nc_num_files , sizeof ( struct nffs_file ))); if ( nffs_file_mem == NULL ) { return FS_ENOMEM ; }","title":"Example"},{"location":"os/core_os/memory_pool/OS_MEMPOOL_SIZE/","text":"OS_MEMPOOL_SIZE OS_MEMPOOL_SIZE ( n , blksize ) Calculates the number of os_membuf_t elements used by n blocks of size blksize bytes. Note that os_membuf_t is used so that memory blocks are aligned on OS_ALIGNMENT boundaries. The blksize variable is the minimum number of bytes required for each block; the actual block size is padded so that each block is aligned on OS_ALIGNMENT boundaries. Arguments Arguments Description n Number of elements blksize Size of an element is number of bytes Returned values The number of os_membuf_t elements used by the memory pool. Note that os_membuf_t is defined to be a unsigned, 32-bit integer when OS_ALIGNMENT is 4 and an unsigned, 64-bit integer when OS_ALIGNMENT is 8. Notes OS_MEMPOOL_SIZE is a macro and not a function. Example Here we define a memory buffer to be used by a memory pool using OS_MEMPOOL_SIZE #define NUM_BLOCKS (16) #define BLOCK_SIZE (32) os_membuf_t my_pool_memory [ OS_MEMPOOL_SIZE ( NUM_BLOCKS , BLOCK_SIZE )]","title":"OS_MEMPOOL_SIZE"},{"location":"os/core_os/memory_pool/OS_MEMPOOL_SIZE/#os_mempool_size","text":"OS_MEMPOOL_SIZE ( n , blksize ) Calculates the number of os_membuf_t elements used by n blocks of size blksize bytes. Note that os_membuf_t is used so that memory blocks are aligned on OS_ALIGNMENT boundaries. The blksize variable is the minimum number of bytes required for each block; the actual block size is padded so that each block is aligned on OS_ALIGNMENT boundaries.","title":"OS_MEMPOOL_SIZE"},{"location":"os/core_os/memory_pool/OS_MEMPOOL_SIZE/#arguments","text":"Arguments Description n Number of elements blksize Size of an element is number of bytes","title":"Arguments"},{"location":"os/core_os/memory_pool/OS_MEMPOOL_SIZE/#returned-values","text":"The number of os_membuf_t elements used by the memory pool. Note that os_membuf_t is defined to be a unsigned, 32-bit integer when OS_ALIGNMENT is 4 and an unsigned, 64-bit integer when OS_ALIGNMENT is 8.","title":"Returned values"},{"location":"os/core_os/memory_pool/OS_MEMPOOL_SIZE/#notes","text":"OS_MEMPOOL_SIZE is a macro and not a function.","title":"Notes"},{"location":"os/core_os/memory_pool/OS_MEMPOOL_SIZE/#example","text":"Here we define a memory buffer to be used by a memory pool using OS_MEMPOOL_SIZE #define NUM_BLOCKS (16) #define BLOCK_SIZE (32) os_membuf_t my_pool_memory [ OS_MEMPOOL_SIZE ( NUM_BLOCKS , BLOCK_SIZE )]","title":"Example"},{"location":"os/core_os/memory_pool/memory_pool/","text":"Memory Pools A memory pool is a collection of fixed sized elements called memory blocks. Generally, memory pools are used when the developer wants to allocate a certain amount of memory to a given feature. Unlike the heap, where a code module is at the mercy of other code modules to insure there is sufficient memory, memory pools can insure sufficient memory allocation. Description In order to create a memory pool the developer needs to do a few things. The first task is to define the memory pool itself. This is a data structure which contains information about the pool itself (i.e. number of blocks, size of the blocks, etc). struct os_mempool my_pool ; The next order of business is to allocate the memory used by the memory pool. This memory can either be statically allocated (i.e. a global variable) or dynamically allocated (i.e. from the heap). When determining the amount of memory required for the memory pool, simply multiplying the number of blocks by the size of each block is not sufficient as the OS may have alignment requirements. The alignment size definition is named OS_ALIGNMENT and can be found in os_arch.h as it is architecture specific. The memory block alignment is usually for efficiency but may be due to other reasons. Generally, blocks are aligned on 32-bit boundaries. Note that memory blocks must also be of sufficient size to hold a list pointer as this is needed to chain memory blocks on the free list. In order to simplify this for the user two macros have been provided: OS_MEMPOOL_BYTES(n, blksize) and OS_MEMPOOL_SIZE(n, blksize) . The first macro returns the number of bytes needed for the memory pool while the second returns the number of os_membuf_t elements required by the memory pool. The os_membuf_t type is used to guarantee that the memory buffer used by the memory pool is aligned on the correct boundary. Here are some examples. Note that if a custom malloc implementation is used it must guarantee that the memory buffer used by the pool is allocated on the correct boundary (i.e. OS_ALIGNMENT). void *my_memory_buffer ; my_memory_buffer = malloc ( OS_MEMPOOL_BYTES ( NUM_BLOCKS , BLOCK_SIZE )); os_membuf_t my_memory_buffer [ OS_MEMPOOL_SIZE ( NUM_BLOCKS , BLOCK_SIZE )]; Now that the memory pool has been defined as well as the memory required for the memory blocks which make up the pool the user needs to initialize the memory pool by calling os_mempool_init . os_mempool_init ( &my_pool , NUM_BLOCKS , BLOCK_SIZE , my_memory_buffer , \"MyPool\" ); Once the memory pool has been initialized the developer can allocate memory blocks from the pool by calling os_memblock_get . When the memory block is no longer needed the memory can be freed by calling os_memblock_put . Data structures struct os_mempool { int mp_block_size ; int mp_num_blocks ; int mp_num_free ; uint32_t mp_membuf_addr ; STAILQ_ENTRY ( os_mempool ) mp_list ; SLIST_HEAD (, os_memblock ); char *name ; }; Element Description mp_block_size Size of the memory blocks, in bytes. This is not the actual number of bytes used by each block; it is the requested size of each block. The actual memory block size will be aligned to OS_ALIGNMENT bytes mp_num_blocks Number of memory blocks in the pool mp_num_free Number of free blocks left mp_membuf_addr The address of the memory block. This is used to check that a valid memory block is being freed. mp_list List pointer to chain memory pools so they can be displayed by newt tools SLIST_HEAD(,os_memblock) List pointer to chain free memory blocks name Name for the memory block List of Functions/Macros The functions/macros available in mem_pool are: Function Description os_memblock_get Allocate an element from the memory pool. os_mempool_init Initializes the memory pool. os_memblock_put Releases previously allocated element back to the pool. OS_MEMPOOL_BYTES Calculates how many bytes of memory is used by n number of elements, when individual element size is blksize bytes. OS_MEMPOOL_SIZE Calculates the number of os_membuf_t elements used by n blocks of size blksize bytes.","title":"toc"},{"location":"os/core_os/memory_pool/memory_pool/#memory-pools","text":"A memory pool is a collection of fixed sized elements called memory blocks. Generally, memory pools are used when the developer wants to allocate a certain amount of memory to a given feature. Unlike the heap, where a code module is at the mercy of other code modules to insure there is sufficient memory, memory pools can insure sufficient memory allocation.","title":"Memory Pools"},{"location":"os/core_os/memory_pool/memory_pool/#description","text":"In order to create a memory pool the developer needs to do a few things. The first task is to define the memory pool itself. This is a data structure which contains information about the pool itself (i.e. number of blocks, size of the blocks, etc). struct os_mempool my_pool ; The next order of business is to allocate the memory used by the memory pool. This memory can either be statically allocated (i.e. a global variable) or dynamically allocated (i.e. from the heap). When determining the amount of memory required for the memory pool, simply multiplying the number of blocks by the size of each block is not sufficient as the OS may have alignment requirements. The alignment size definition is named OS_ALIGNMENT and can be found in os_arch.h as it is architecture specific. The memory block alignment is usually for efficiency but may be due to other reasons. Generally, blocks are aligned on 32-bit boundaries. Note that memory blocks must also be of sufficient size to hold a list pointer as this is needed to chain memory blocks on the free list. In order to simplify this for the user two macros have been provided: OS_MEMPOOL_BYTES(n, blksize) and OS_MEMPOOL_SIZE(n, blksize) . The first macro returns the number of bytes needed for the memory pool while the second returns the number of os_membuf_t elements required by the memory pool. The os_membuf_t type is used to guarantee that the memory buffer used by the memory pool is aligned on the correct boundary. Here are some examples. Note that if a custom malloc implementation is used it must guarantee that the memory buffer used by the pool is allocated on the correct boundary (i.e. OS_ALIGNMENT). void *my_memory_buffer ; my_memory_buffer = malloc ( OS_MEMPOOL_BYTES ( NUM_BLOCKS , BLOCK_SIZE )); os_membuf_t my_memory_buffer [ OS_MEMPOOL_SIZE ( NUM_BLOCKS , BLOCK_SIZE )]; Now that the memory pool has been defined as well as the memory required for the memory blocks which make up the pool the user needs to initialize the memory pool by calling os_mempool_init . os_mempool_init ( &my_pool , NUM_BLOCKS , BLOCK_SIZE , my_memory_buffer , \"MyPool\" ); Once the memory pool has been initialized the developer can allocate memory blocks from the pool by calling os_memblock_get . When the memory block is no longer needed the memory can be freed by calling os_memblock_put .","title":"Description"},{"location":"os/core_os/memory_pool/memory_pool/#data-structures","text":"struct os_mempool { int mp_block_size ; int mp_num_blocks ; int mp_num_free ; uint32_t mp_membuf_addr ; STAILQ_ENTRY ( os_mempool ) mp_list ; SLIST_HEAD (, os_memblock ); char *name ; }; Element Description mp_block_size Size of the memory blocks, in bytes. This is not the actual number of bytes used by each block; it is the requested size of each block. The actual memory block size will be aligned to OS_ALIGNMENT bytes mp_num_blocks Number of memory blocks in the pool mp_num_free Number of free blocks left mp_membuf_addr The address of the memory block. This is used to check that a valid memory block is being freed. mp_list List pointer to chain memory pools so they can be displayed by newt tools SLIST_HEAD(,os_memblock) List pointer to chain free memory blocks name Name for the memory block","title":"Data structures"},{"location":"os/core_os/memory_pool/memory_pool/#list-of-functionsmacros","text":"The functions/macros available in mem_pool are: Function Description os_memblock_get Allocate an element from the memory pool. os_mempool_init Initializes the memory pool. os_memblock_put Releases previously allocated element back to the pool. OS_MEMPOOL_BYTES Calculates how many bytes of memory is used by n number of elements, when individual element size is blksize bytes. OS_MEMPOOL_SIZE Calculates the number of os_membuf_t elements used by n blocks of size blksize bytes.","title":"List of Functions/Macros"},{"location":"os/core_os/memory_pool/os_memblock_get/","text":"os_memblock_get void *os_memblock_get ( struct os_mempool *mp ) Allocate an element from the memory pool. If successful, you'll get a pointer to allocated element. If there are no elements available, you'll get NULL as response. Arguments Arguments Description mp Pool where element is getting allocated from Returned values NULL: no elements available. : pointer to allocated element. Notes Example struct nffs_file *file ; file = os_memblock_get ( &nffs_file_pool ); if ( file != NULL ) { memset ( file , 0 , sizeof *file ); }","title":"os_memblock_get"},{"location":"os/core_os/memory_pool/os_memblock_get/#os_memblock_get","text":"void *os_memblock_get ( struct os_mempool *mp ) Allocate an element from the memory pool. If successful, you'll get a pointer to allocated element. If there are no elements available, you'll get NULL as response.","title":" os_memblock_get"},{"location":"os/core_os/memory_pool/os_memblock_get/#arguments","text":"Arguments Description mp Pool where element is getting allocated from","title":"Arguments"},{"location":"os/core_os/memory_pool/os_memblock_get/#returned-values","text":"NULL: no elements available. : pointer to allocated element.","title":"Returned values"},{"location":"os/core_os/memory_pool/os_memblock_get/#notes","text":"","title":"Notes"},{"location":"os/core_os/memory_pool/os_memblock_get/#example","text":"struct nffs_file *file ; file = os_memblock_get ( &nffs_file_pool ); if ( file != NULL ) { memset ( file , 0 , sizeof *file ); }","title":"Example"},{"location":"os/core_os/memory_pool/os_memblock_put/","text":"os_memblock_put os_error_t os_memblock_put ( struct os_mempool *mp , void *block_addr ) Releases previously allocated element back to the pool. Arguments Arguments Description mp Pointer to memory pool from which block was allocated block_addr Pointer to element getting freed Returned values OS_OK: operation was a success: OS_INVALID_PARAM: If either mp or block_addr were NULL, or the block being freed was outside the range of the memory buffer or not on a true block size boundary. Example if ( file != NULL ) { rc = os_memblock_put ( &nffs_file_pool , file ); if ( rc != 0 ) { /* Error freeing memory block */ } }","title":"os_memblock_put"},{"location":"os/core_os/memory_pool/os_memblock_put/#os_memblock_put","text":"os_error_t os_memblock_put ( struct os_mempool *mp , void *block_addr ) Releases previously allocated element back to the pool.","title":"os_memblock_put"},{"location":"os/core_os/memory_pool/os_memblock_put/#arguments","text":"Arguments Description mp Pointer to memory pool from which block was allocated block_addr Pointer to element getting freed","title":"Arguments"},{"location":"os/core_os/memory_pool/os_memblock_put/#returned-values","text":"OS_OK: operation was a success: OS_INVALID_PARAM: If either mp or block_addr were NULL, or the block being freed was outside the range of the memory buffer or not on a true block size boundary.","title":"Returned values"},{"location":"os/core_os/memory_pool/os_memblock_put/#example","text":"if ( file != NULL ) { rc = os_memblock_put ( &nffs_file_pool , file ); if ( rc != 0 ) { /* Error freeing memory block */ } }","title":"Example"},{"location":"os/core_os/memory_pool/os_mempool_init/","text":"os_mempool_init os_error_t os_mempool_init ( struct os_mempool *mp , int blocks , int block_size , void *membuf , char *name ) Initializes the memory pool. Memory pointed to by membuf is divided into blocks number of elements of size OS_ALIGN( block_size ). The name is optional, and names the memory pool. It is assumed that the amount of memory pointed by membuf has at least OS_MEMPOOL_BYTES(blocks, block_size) number of bytes. name is not copied, so caller should make sure that the memory does not get reused. Arguments Arguments Description mp Memory pool being initialized blocks Number of elements in the pool block_size Minimum size of an individual element in pool membuf Backing store for the memory pool elements name Name of the memory pool Returned values OS_OK: operation was successful. OS_INVALID_PARAM: invalid parameters. Block count or block size was negative, or membuf or mp was NULL. OS_MEM_NOT_ALIGNED: membuf was not aligned on correct byte boundary. Notes Note that os_mempool_init() does not allocate backing storage; membuf has to be allocated by the caller. It's recommended that you use OS_MEMPOOL_BYTES() or OS_MEMPOOL_SIZE() to figure out how much memory to allocate for the pool. Example void *nffs_file_mem ; nffs_file_mem = malloc ( OS_MEMPOOL_BYTES ( nffs_config . nc_num_files , sizeof ( struct nffs_file ))); rc = os_mempool_init ( &nffs_file_pool , nffs_config . nc_num_files , sizeof ( struct nffs_file ), nffs_file_mem , \"nffs_file_pool\" ); if ( rc != 0 ) { /* Memory pool initialization failure */ }","title":"os_mempool_init"},{"location":"os/core_os/memory_pool/os_mempool_init/#os_mempool_init","text":"os_error_t os_mempool_init ( struct os_mempool *mp , int blocks , int block_size , void *membuf , char *name ) Initializes the memory pool. Memory pointed to by membuf is divided into blocks number of elements of size OS_ALIGN( block_size ). The name is optional, and names the memory pool. It is assumed that the amount of memory pointed by membuf has at least OS_MEMPOOL_BYTES(blocks, block_size) number of bytes. name is not copied, so caller should make sure that the memory does not get reused.","title":" os_mempool_init"},{"location":"os/core_os/memory_pool/os_mempool_init/#arguments","text":"Arguments Description mp Memory pool being initialized blocks Number of elements in the pool block_size Minimum size of an individual element in pool membuf Backing store for the memory pool elements name Name of the memory pool","title":"Arguments"},{"location":"os/core_os/memory_pool/os_mempool_init/#returned-values","text":"OS_OK: operation was successful. OS_INVALID_PARAM: invalid parameters. Block count or block size was negative, or membuf or mp was NULL. OS_MEM_NOT_ALIGNED: membuf was not aligned on correct byte boundary.","title":"Returned values"},{"location":"os/core_os/memory_pool/os_mempool_init/#notes","text":"Note that os_mempool_init() does not allocate backing storage; membuf has to be allocated by the caller. It's recommended that you use OS_MEMPOOL_BYTES() or OS_MEMPOOL_SIZE() to figure out how much memory to allocate for the pool.","title":"Notes"},{"location":"os/core_os/memory_pool/os_mempool_init/#example","text":"void *nffs_file_mem ; nffs_file_mem = malloc ( OS_MEMPOOL_BYTES ( nffs_config . nc_num_files , sizeof ( struct nffs_file ))); rc = os_mempool_init ( &nffs_file_pool , nffs_config . nc_num_files , sizeof ( struct nffs_file ), nffs_file_mem , \"nffs_file_pool\" ); if ( rc != 0 ) { /* Memory pool initialization failure */ }","title":"Example"},{"location":"os/core_os/mqueue/mqueue/","text":"Mqueue Mqueue (Mbuf event queue) is a set of API built on top of the mbuf and event queue code. A typical networking stack operation is to put a packet on a queue and post an event to the task handling that queue. Mqueue was designed to provide a common API so that individual packages would not each have to create similar code. The mqueue data structure consists of a queue head pointer (a \"stailq\" queue; a singly linked list with head structure having a pointer to the start and end of the list) and an os event structure. Packets (packet header mbufs) are added to the queue using the omp_next pointer in the os_mbuf_pkthdr structure of the mbuf. The event is used to post to the task an event of type OS_EVENT_T_MQUEUE_DATA. Using Mqueue The following code sample will demonstrate how to use an mqueue. This is a simple example where packets are put on a \"receive queue\" and a task processes that \"receive queue\" by incrementing the total number of packet received and then freeing the packet. Not shown in the code example is a call my_task_rx_data_func. Presumably, some other code will call this API. uint32_t pkts_rxd ; struct os_mqueue rxpkt_q ; struct os_eventq my_task_evq ; void process_rx_data_queue ( void ) { struct os_mbuf *om ; /* Drain all packets off queue and process them */ while (( om = os_mqueue_get ( &rxpkt_q )) != NULL ) { ++pkts_rxd ; os_mbuf_free_chain ( om ); } } int my_task_rx_data_func ( struct os_mbuf *om ) { int rc ; rc = os_mqueue_put ( &rxpkt_q , &my_task_evq , om ); if ( rc != 0 ) { return -1 ; } return 0 ; } void my_task_handler ( void *arg ) { struct os_event *ev ; struct os_callout_func *cf ; int rc ; /* Initialize eventq */ os_eventq_init ( &my_task_evq ); /* Initialize mqueue */ os_mqueue_init ( &rxpkt_q , NULL ); while ( 1 ) { ev = os_eventq_get ( &my_task_evq ); switch ( ev->ev_type ) { case OS_EVENT_T_MQUEUE_DATA : process_rx_data_queue (); break ; default : assert ( 0 ); break ; } } } Data Structures struct os_mqueue { STAILQ_HEAD (, os_mbuf_pkthdr ) mq_head ; struct os_event mq_ev ; }; List of Functions The functions available in Mqueue are: Function Description os_mqueue_init Initializes an mqueue. os_mqueue_get Retrieves a packet off an Mqueue. os_mqueue_put Adds a packet (i.e. packet header mbuf) to an mqueue.","title":"toc"},{"location":"os/core_os/mqueue/mqueue/#mqueue","text":"Mqueue (Mbuf event queue) is a set of API built on top of the mbuf and event queue code. A typical networking stack operation is to put a packet on a queue and post an event to the task handling that queue. Mqueue was designed to provide a common API so that individual packages would not each have to create similar code. The mqueue data structure consists of a queue head pointer (a \"stailq\" queue; a singly linked list with head structure having a pointer to the start and end of the list) and an os event structure. Packets (packet header mbufs) are added to the queue using the omp_next pointer in the os_mbuf_pkthdr structure of the mbuf. The event is used to post to the task an event of type OS_EVENT_T_MQUEUE_DATA.","title":"Mqueue"},{"location":"os/core_os/mqueue/mqueue/#using-mqueue","text":"The following code sample will demonstrate how to use an mqueue. This is a simple example where packets are put on a \"receive queue\" and a task processes that \"receive queue\" by incrementing the total number of packet received and then freeing the packet. Not shown in the code example is a call my_task_rx_data_func. Presumably, some other code will call this API. uint32_t pkts_rxd ; struct os_mqueue rxpkt_q ; struct os_eventq my_task_evq ; void process_rx_data_queue ( void ) { struct os_mbuf *om ; /* Drain all packets off queue and process them */ while (( om = os_mqueue_get ( &rxpkt_q )) != NULL ) { ++pkts_rxd ; os_mbuf_free_chain ( om ); } } int my_task_rx_data_func ( struct os_mbuf *om ) { int rc ; rc = os_mqueue_put ( &rxpkt_q , &my_task_evq , om ); if ( rc != 0 ) { return -1 ; } return 0 ; } void my_task_handler ( void *arg ) { struct os_event *ev ; struct os_callout_func *cf ; int rc ; /* Initialize eventq */ os_eventq_init ( &my_task_evq ); /* Initialize mqueue */ os_mqueue_init ( &rxpkt_q , NULL ); while ( 1 ) { ev = os_eventq_get ( &my_task_evq ); switch ( ev->ev_type ) { case OS_EVENT_T_MQUEUE_DATA : process_rx_data_queue (); break ; default : assert ( 0 ); break ; } } }","title":"Using Mqueue"},{"location":"os/core_os/mqueue/mqueue/#data-structures","text":"struct os_mqueue { STAILQ_HEAD (, os_mbuf_pkthdr ) mq_head ; struct os_event mq_ev ; };","title":"Data Structures"},{"location":"os/core_os/mqueue/mqueue/#list-of-functions","text":"The functions available in Mqueue are: Function Description os_mqueue_init Initializes an mqueue. os_mqueue_get Retrieves a packet off an Mqueue. os_mqueue_put Adds a packet (i.e. packet header mbuf) to an mqueue.","title":"List of Functions"},{"location":"os/core_os/mqueue/os_mqueue_get/","text":"os_mqueue_get struct os_mbuf *os_mqueue_get ( struct os_mqueue *mq ) Retrieves a packet off an Mqueue. Returns a pointer to the mbuf at the head of the mbuf chain. NULL if no packets are on the queue. Arguments Arguments Description mq Pointer to Mqueue structure Returned values The packet at the head of the queue or NULL if no packets are on the queue. Example uint32_t pkts_rxd ; struct os_mqueue rxpkt_q ; void process_rx_data_queue ( void ) { struct os_mbuf *om ; /* Drain all packets off queue and process them */ while (( om = os_mqueue_get ( &rxpkt_q )) != NULL ) { ++pkts_rxd ; os_mbuf_free_chain ( om ); } }","title":"os_mqueue_get"},{"location":"os/core_os/mqueue/os_mqueue_get/#os_mqueue_get","text":"struct os_mbuf *os_mqueue_get ( struct os_mqueue *mq ) Retrieves a packet off an Mqueue. Returns a pointer to the mbuf at the head of the mbuf chain. NULL if no packets are on the queue.","title":"os_mqueue_get"},{"location":"os/core_os/mqueue/os_mqueue_get/#arguments","text":"Arguments Description mq Pointer to Mqueue structure","title":"Arguments"},{"location":"os/core_os/mqueue/os_mqueue_get/#returned-values","text":"The packet at the head of the queue or NULL if no packets are on the queue.","title":"Returned values"},{"location":"os/core_os/mqueue/os_mqueue_get/#example","text":"uint32_t pkts_rxd ; struct os_mqueue rxpkt_q ; void process_rx_data_queue ( void ) { struct os_mbuf *om ; /* Drain all packets off queue and process them */ while (( om = os_mqueue_get ( &rxpkt_q )) != NULL ) { ++pkts_rxd ; os_mbuf_free_chain ( om ); } }","title":"Example"},{"location":"os/core_os/mqueue/os_mqueue_init/","text":"os_mqueue_init int os_mqueue_init ( struct os_mqueue *mq , void *arg ) Initializes an queue. Sets the event argument in the os event of the mqueue to arg . Sets type of event to OS_EVENT_T_MQUEUE_DATA. Arguments Arguments Description mq Pointer to a mqueue structure arg Event argument Returned values 0: success. All other values indicate an error Example /* Declare mqueue */ struct os_mqueue rxpkt_q ; /* Initialize mqueue */ os_mqueue_init ( &rxpkt_q , NULL );","title":"os_mqueue_init"},{"location":"os/core_os/mqueue/os_mqueue_init/#os_mqueue_init","text":"int os_mqueue_init ( struct os_mqueue *mq , void *arg ) Initializes an queue. Sets the event argument in the os event of the mqueue to arg . Sets type of event to OS_EVENT_T_MQUEUE_DATA.","title":"os_mqueue_init"},{"location":"os/core_os/mqueue/os_mqueue_init/#arguments","text":"Arguments Description mq Pointer to a mqueue structure arg Event argument","title":"Arguments"},{"location":"os/core_os/mqueue/os_mqueue_init/#returned-values","text":"0: success. All other values indicate an error","title":"Returned values"},{"location":"os/core_os/mqueue/os_mqueue_init/#example","text":"/* Declare mqueue */ struct os_mqueue rxpkt_q ; /* Initialize mqueue */ os_mqueue_init ( &rxpkt_q , NULL );","title":"Example"},{"location":"os/core_os/mqueue/os_mqueue_put/","text":"os_mqueue_put int os_mqueue_put ( struct os_mqueue *mq , struct os_eventq *evq , struct os_mbuf *m ) Adds a packet (i.e. packet header mbuf) to an mqueue. Post event to evq . Arguments Arguments Description mq Pointer to mqueue evq Pointer to event queue where mqueue event should get posted m Pointer to packet header mbuf Returned values 0: success OS_EINVAL: the mbuf is not a packet header mbuf. Example int my_task_rx_data_func ( struct os_mbuf *om ) { int rc ; rc = os_mqueue_put ( &rxpkt_q , &my_task_evq , om ); if ( rc != 0 ) { return -1 ; } return 0 ; }","title":"os_mqueue_put"},{"location":"os/core_os/mqueue/os_mqueue_put/#os_mqueue_put","text":"int os_mqueue_put ( struct os_mqueue *mq , struct os_eventq *evq , struct os_mbuf *m ) Adds a packet (i.e. packet header mbuf) to an mqueue. Post event to evq .","title":"os_mqueue_put"},{"location":"os/core_os/mqueue/os_mqueue_put/#arguments","text":"Arguments Description mq Pointer to mqueue evq Pointer to event queue where mqueue event should get posted m Pointer to packet header mbuf","title":"Arguments"},{"location":"os/core_os/mqueue/os_mqueue_put/#returned-values","text":"0: success OS_EINVAL: the mbuf is not a packet header mbuf.","title":"Returned values"},{"location":"os/core_os/mqueue/os_mqueue_put/#example","text":"int my_task_rx_data_func ( struct os_mbuf *om ) { int rc ; rc = os_mqueue_put ( &rxpkt_q , &my_task_evq , om ); if ( rc != 0 ) { return -1 ; } return 0 ; }","title":"Example"},{"location":"os/core_os/msys/msys/","text":"Msys Msys stands for \"system mbufs\" and is a set of API built on top of the mbuf code. The basic idea behind msys is the following. The developer can create different size mbuf pools and register them with msys. The application then allocates mbufs using the msys API (as opposed to the mbuf API). The msys code will choose the mbuf pool with the smallest mbufs that can accommodate the requested size. Let us walk through an example where the user registers three mbuf pools with msys: one with 32 byte mbufs, one with 256 and one with 2048. If the user requests an mbuf with 10 bytes, the 32-byte mbuf pool is used. If the request is for 33 bytes the 256 byte mbuf pool is used. If an mbuf data size is requested that is larger than any of the pools (say, 4000 bytes) the largest pool is used. While this behaviour may not be optimal in all cases that is the currently implemented behaviour. All this means is that the user is not guaranteed that a single mbuf can hold the requested data. The msys code will not allocate an mbuf from a larger pool if the chosen mbuf pool is empty. Similarly, the msys code will not chain together a number of smaller mbufs to accommodate the requested size. While this behaviour may change in future implementations the current code will simply return NULL. Using the above example, say the user requests 250 bytes. The msys code chooses the appropriate pool (i.e. the 256 byte mbuf pool) and attempts to allocate an mbuf from that pool. If that pool is empty, NULL is returned even though the 32 and 2048 byte pools are not empty. Note that no added descriptions on how to use the msys API are presented here (other than in the API descriptions themselves) as the msys API is used in exactly the same manner as the mbuf API. The only difference is that mbuf pools are added to msys by calling os_msys_register(). List of Functions The functions available in msys are: Function Description os_msys_get Retrieve an mbuf from the system mbuf pools with the given number of bytes available in the mbuf. os_msys_get_pkthdr Retrieve a packet header mbuf from the system mbuf pools with the given number of bytes available for the user header in the mbuf. os_msys_register Register an mbuf pool for use as a system mbuf pool. os_msys_reset Resets msys module.","title":"toc"},{"location":"os/core_os/msys/msys/#msys","text":"Msys stands for \"system mbufs\" and is a set of API built on top of the mbuf code. The basic idea behind msys is the following. The developer can create different size mbuf pools and register them with msys. The application then allocates mbufs using the msys API (as opposed to the mbuf API). The msys code will choose the mbuf pool with the smallest mbufs that can accommodate the requested size. Let us walk through an example where the user registers three mbuf pools with msys: one with 32 byte mbufs, one with 256 and one with 2048. If the user requests an mbuf with 10 bytes, the 32-byte mbuf pool is used. If the request is for 33 bytes the 256 byte mbuf pool is used. If an mbuf data size is requested that is larger than any of the pools (say, 4000 bytes) the largest pool is used. While this behaviour may not be optimal in all cases that is the currently implemented behaviour. All this means is that the user is not guaranteed that a single mbuf can hold the requested data. The msys code will not allocate an mbuf from a larger pool if the chosen mbuf pool is empty. Similarly, the msys code will not chain together a number of smaller mbufs to accommodate the requested size. While this behaviour may change in future implementations the current code will simply return NULL. Using the above example, say the user requests 250 bytes. The msys code chooses the appropriate pool (i.e. the 256 byte mbuf pool) and attempts to allocate an mbuf from that pool. If that pool is empty, NULL is returned even though the 32 and 2048 byte pools are not empty. Note that no added descriptions on how to use the msys API are presented here (other than in the API descriptions themselves) as the msys API is used in exactly the same manner as the mbuf API. The only difference is that mbuf pools are added to msys by calling os_msys_register().","title":"Msys"},{"location":"os/core_os/msys/msys/#list-of-functions","text":"The functions available in msys are: Function Description os_msys_get Retrieve an mbuf from the system mbuf pools with the given number of bytes available in the mbuf. os_msys_get_pkthdr Retrieve a packet header mbuf from the system mbuf pools with the given number of bytes available for the user header in the mbuf. os_msys_register Register an mbuf pool for use as a system mbuf pool. os_msys_reset Resets msys module.","title":"List of Functions"},{"location":"os/core_os/msys/os_msys_get/","text":"os_msys_get struct os_mbuf *os_msys_get ( uint16_t dsize , uint16_t leadingspace ) Retrieve an mbuf from the system mbuf pools with leadingspace bytes available in the mbuf. Arguments Arguments Description dsize Minimum requested size of mbuf. Actual mbuf allocated may not accommodate dsize leadingspace Number of bytes for leading space in mbuf (space at start of mbuf) Returned values Pointer to mbuf or NULL if no mbufs were available. Notes As described in the overview section, os_msys_get() may return an mbuf that is smaller than dsize, meaning that the mbuf user data buffer does not have enough contiguous space to hold dsize bytes. This API will not return an mbuf from a larger mbuf pool if the appropriate msys mbuf pool is empty. See the overview for more information. Example struct os_mbuf *om ; /* Allocate an mbuf with hopefully at least 100 bytes in its user data buffer */ om = os_msys_get ( 100 , 0 ); if ( !om ) { /* No mbufs available. */ return -1 ; } }","title":"os_msys_get"},{"location":"os/core_os/msys/os_msys_get/#os_msys_get","text":"struct os_mbuf *os_msys_get ( uint16_t dsize , uint16_t leadingspace ) Retrieve an mbuf from the system mbuf pools with leadingspace bytes available in the mbuf.","title":"os_msys_get"},{"location":"os/core_os/msys/os_msys_get/#arguments","text":"Arguments Description dsize Minimum requested size of mbuf. Actual mbuf allocated may not accommodate dsize leadingspace Number of bytes for leading space in mbuf (space at start of mbuf)","title":"Arguments"},{"location":"os/core_os/msys/os_msys_get/#returned-values","text":"Pointer to mbuf or NULL if no mbufs were available.","title":"Returned values"},{"location":"os/core_os/msys/os_msys_get/#notes","text":"As described in the overview section, os_msys_get() may return an mbuf that is smaller than dsize, meaning that the mbuf user data buffer does not have enough contiguous space to hold dsize bytes. This API will not return an mbuf from a larger mbuf pool if the appropriate msys mbuf pool is empty. See the overview for more information.","title":"Notes"},{"location":"os/core_os/msys/os_msys_get/#example","text":"struct os_mbuf *om ; /* Allocate an mbuf with hopefully at least 100 bytes in its user data buffer */ om = os_msys_get ( 100 , 0 ); if ( !om ) { /* No mbufs available. */ return -1 ; } }","title":"Example"},{"location":"os/core_os/msys/os_msys_get_pkthdr/","text":"os_msys_get_pkthdr struct os_mbuf *os_msys_get_pkthdr ( uint16_t dsize , uint16_t user_hdr_len ) Retrieve a packet header mbuf from the system mbuf pools with user_hdr_len bytes available for the user header in the mbuf. Arguments Arguments Description dsize Minimum requested size of mbuf. Actual mbuf allocated may not accommodate dsize user_hdr_len Size, in of bytes, of user header in the mbuf Returned values Pointer to mbuf or NULL if no mbufs were available. Notes The same notes apply to this API as to os_msys_get() . Example struct os_mbuf *om ; struct my_user_hdr_struct my_usr_hdr ; /* * Allocate an mbuf with hopefully at least 100 bytes in its user data buffer * and that has a user header of size sizeof(struct my_user_hdr_struct) */ om = os_msys_get_pkthdr ( 100 , sizeof ( struct my_user_hdr_struct )); if ( !om ) { /* No mbufs available. */ return -1 ; } }","title":"os_msys_get_pkthdr"},{"location":"os/core_os/msys/os_msys_get_pkthdr/#os_msys_get_pkthdr","text":"struct os_mbuf *os_msys_get_pkthdr ( uint16_t dsize , uint16_t user_hdr_len ) Retrieve a packet header mbuf from the system mbuf pools with user_hdr_len bytes available for the user header in the mbuf.","title":"os_msys_get_pkthdr"},{"location":"os/core_os/msys/os_msys_get_pkthdr/#arguments","text":"Arguments Description dsize Minimum requested size of mbuf. Actual mbuf allocated may not accommodate dsize user_hdr_len Size, in of bytes, of user header in the mbuf","title":"Arguments"},{"location":"os/core_os/msys/os_msys_get_pkthdr/#returned-values","text":"Pointer to mbuf or NULL if no mbufs were available.","title":"Returned values"},{"location":"os/core_os/msys/os_msys_get_pkthdr/#notes","text":"The same notes apply to this API as to os_msys_get() .","title":"Notes"},{"location":"os/core_os/msys/os_msys_get_pkthdr/#example","text":"struct os_mbuf *om ; struct my_user_hdr_struct my_usr_hdr ; /* * Allocate an mbuf with hopefully at least 100 bytes in its user data buffer * and that has a user header of size sizeof(struct my_user_hdr_struct) */ om = os_msys_get_pkthdr ( 100 , sizeof ( struct my_user_hdr_struct )); if ( !om ) { /* No mbufs available. */ return -1 ; } }","title":"Example"},{"location":"os/core_os/msys/os_msys_register/","text":"os_msys_register int os_msys_register ( struct os_mbuf_pool *new_pool ) Register an mbuf pool for use as a system mbuf pool. The pool should be initialized prior to registration. Arguments Arguments Description new_pool Pointer to mbuf pool to add to system mbuf pools Returned values 0 on success; all other values indicate an error. Example rc = os_msys_register ( &g_mbuf_pool ); assert ( rc == 0 );","title":"os_msys_register"},{"location":"os/core_os/msys/os_msys_register/#os_msys_register","text":"int os_msys_register ( struct os_mbuf_pool *new_pool ) Register an mbuf pool for use as a system mbuf pool. The pool should be initialized prior to registration.","title":"os_msys_register"},{"location":"os/core_os/msys/os_msys_register/#arguments","text":"Arguments Description new_pool Pointer to mbuf pool to add to system mbuf pools","title":"Arguments"},{"location":"os/core_os/msys/os_msys_register/#returned-values","text":"0 on success; all other values indicate an error.","title":"Returned values"},{"location":"os/core_os/msys/os_msys_register/#example","text":"rc = os_msys_register ( &g_mbuf_pool ); assert ( rc == 0 );","title":"Example"},{"location":"os/core_os/msys/os_msys_reset/","text":"os_msys_reset void os_msys_reset ( void ) Resets msys module. This de-registers all pools from msys but does nothing to the pools themselves (they still exist as mbuf pools). Arguments None Returned values None Example os_msys_reset ();","title":"os_msys_reset"},{"location":"os/core_os/msys/os_msys_reset/#os_msys_reset","text":"void os_msys_reset ( void ) Resets msys module. This de-registers all pools from msys but does nothing to the pools themselves (they still exist as mbuf pools).","title":"os_msys_reset"},{"location":"os/core_os/msys/os_msys_reset/#arguments","text":"None","title":"Arguments"},{"location":"os/core_os/msys/os_msys_reset/#returned-values","text":"None","title":"Returned values"},{"location":"os/core_os/msys/os_msys_reset/#example","text":"os_msys_reset ();","title":"Example"},{"location":"os/core_os/mutex/mutex/","text":"Mutex Mutex is short for \"mutual exclusion\"; a mutex provides mutually exclusive access to a shared resource. A mutex provides priority inheritance in order to prevent priority inversion . Priority inversion occurs when a higher priority task is waiting on a resource owned by a lower priority task. Using a mutex, the lower priority task will inherit the highest priority of any task waiting on the mutex. Description The first order of business when using a mutex is to declare the mutex globally. The mutex needs to be initialized before it is used (see the examples). It is generally a good idea to initialize the mutex before tasks start running in order to avoid a task possibly using the mutex before it is initialized. When a task wants exclusive access to a shared resource it needs to obtain the mutex by calling os_mutex_pend . If the mutex is currently owned by a different task (a lower priority task), the requesting task will be put to sleep and the owners priority will be elevated to the priority of the requesting task. Note that multiple tasks can request ownership and the current owner is elevated to the highest priority of any task waitin on the mutex. When the task is done using the shared resource, it needs to release the mutex by called os_mutex_release . There needs to be one release per call to pend. Note that nested calls to os_mutex_pend are allowed but there needs to be one release per pend. The following example will illustrate how priority inheritance works. In this example, the task number is the same as its priority. Remember that the lower the number, the higher the priority (i.e. priority 0 is higher priority than priority 1). Suppose that task 5 gets ownership of a mutex but is preempted by task 4. Task 4 attempts to gain ownership of the mutex but cannot as it is owned by task 5. Task 4 is put to sleep and task 5 is temporarily raised to priority 4. Before task 5 can release the mutex, task 3 runs and attempts to acquire the mutex. At this point, both task 3 and task 4 are waiting on the mutex (sleeping). Task 5 now runs at priority 3 (the highest priority of all the tasks waiting on the mutex). When task 5 finally releases the mutex it will be preempted as two higher priority tasks are waiting for it. Note that when multiple tasks are waiting on a mutex owned by another task, once the mutex is released the highest priority task waiting on the mutex is run. Data structures struct os_mutex { SLIST_HEAD (, os_task ) mu_head ; uint8_t _pad ; uint8_t mu_prio ; uint16_t mu_level ; struct os_task *mu_owner ; }; Element Description mu_head Queue head for list of tasks waiting on mutex _pad Padding mu_prio Default priority of owner of mutex. Used to reset priority of task when mutex released mu_level Call nesting level (for nested calls) mu_owner Pointer to task structure which owns mutex List of Functions The functions available in this OS feature are: Function Description os_mutex_init Initialize the mutex. Must be called before the mutex can be used. os_mutex_pend Acquire ownership of a mutex. os_mutex_release Release ownership of a mutex.","title":"toc"},{"location":"os/core_os/mutex/mutex/#mutex","text":"Mutex is short for \"mutual exclusion\"; a mutex provides mutually exclusive access to a shared resource. A mutex provides priority inheritance in order to prevent priority inversion . Priority inversion occurs when a higher priority task is waiting on a resource owned by a lower priority task. Using a mutex, the lower priority task will inherit the highest priority of any task waiting on the mutex.","title":"Mutex"},{"location":"os/core_os/mutex/mutex/#description","text":"The first order of business when using a mutex is to declare the mutex globally. The mutex needs to be initialized before it is used (see the examples). It is generally a good idea to initialize the mutex before tasks start running in order to avoid a task possibly using the mutex before it is initialized. When a task wants exclusive access to a shared resource it needs to obtain the mutex by calling os_mutex_pend . If the mutex is currently owned by a different task (a lower priority task), the requesting task will be put to sleep and the owners priority will be elevated to the priority of the requesting task. Note that multiple tasks can request ownership and the current owner is elevated to the highest priority of any task waitin on the mutex. When the task is done using the shared resource, it needs to release the mutex by called os_mutex_release . There needs to be one release per call to pend. Note that nested calls to os_mutex_pend are allowed but there needs to be one release per pend. The following example will illustrate how priority inheritance works. In this example, the task number is the same as its priority. Remember that the lower the number, the higher the priority (i.e. priority 0 is higher priority than priority 1). Suppose that task 5 gets ownership of a mutex but is preempted by task 4. Task 4 attempts to gain ownership of the mutex but cannot as it is owned by task 5. Task 4 is put to sleep and task 5 is temporarily raised to priority 4. Before task 5 can release the mutex, task 3 runs and attempts to acquire the mutex. At this point, both task 3 and task 4 are waiting on the mutex (sleeping). Task 5 now runs at priority 3 (the highest priority of all the tasks waiting on the mutex). When task 5 finally releases the mutex it will be preempted as two higher priority tasks are waiting for it. Note that when multiple tasks are waiting on a mutex owned by another task, once the mutex is released the highest priority task waiting on the mutex is run.","title":"Description"},{"location":"os/core_os/mutex/mutex/#data-structures","text":"struct os_mutex { SLIST_HEAD (, os_task ) mu_head ; uint8_t _pad ; uint8_t mu_prio ; uint16_t mu_level ; struct os_task *mu_owner ; }; Element Description mu_head Queue head for list of tasks waiting on mutex _pad Padding mu_prio Default priority of owner of mutex. Used to reset priority of task when mutex released mu_level Call nesting level (for nested calls) mu_owner Pointer to task structure which owns mutex","title":"Data structures"},{"location":"os/core_os/mutex/mutex/#list-of-functions","text":"The functions available in this OS feature are: Function Description os_mutex_init Initialize the mutex. Must be called before the mutex can be used. os_mutex_pend Acquire ownership of a mutex. os_mutex_release Release ownership of a mutex.","title":"List of Functions"},{"location":"os/core_os/mutex/os_mutex_init/","text":"os_mutex_init os_error_t os_mutex_init ( struct os_mutex *mu ) Initialize the mutex. Must be called before the mutex can be used. Arguments Arguments Description *mu Pointer to mutex Returned values OS_INVALID_PARM: returned when *mu is NULL on entry. OS_OK: mutex initialized successfully. Notes Example struct os_mutex g_mutex1 ; os_error_t err ; err = os_mutex_init ( &g_mutex1 ); assert ( err == OS_OK );","title":"os_mutex_init"},{"location":"os/core_os/mutex/os_mutex_init/#os_mutex_init","text":"os_error_t os_mutex_init ( struct os_mutex *mu ) Initialize the mutex. Must be called before the mutex can be used.","title":"os_mutex_init"},{"location":"os/core_os/mutex/os_mutex_init/#arguments","text":"Arguments Description *mu Pointer to mutex","title":"Arguments"},{"location":"os/core_os/mutex/os_mutex_init/#returned-values","text":"OS_INVALID_PARM: returned when *mu is NULL on entry. OS_OK: mutex initialized successfully.","title":"Returned values"},{"location":"os/core_os/mutex/os_mutex_init/#notes","text":"","title":"Notes"},{"location":"os/core_os/mutex/os_mutex_init/#example","text":"struct os_mutex g_mutex1 ; os_error_t err ; err = os_mutex_init ( &g_mutex1 ); assert ( err == OS_OK );","title":"Example"},{"location":"os/core_os/mutex/os_mutex_pend/","text":"os_mutex_pend os_error_t os_mutex_pend ( struct os_mutex *mu , uint32_t timeout ) Acquire ownership of a mutex. Arguments Arguments Description *mu Pointer to mutex timeout Timeout, in os ticks. A value of 0 means no timeout. A value of 0xFFFFFFFF means to wait forever. Returned values OS_INVALID_PARM: returned when *mu is NULL on entry. OS_OK: mutex was successfully acquired. OS_TIMEOUT: the mutex was not available within the timeout specified. OS_NOT_STARTED: Attempt to release a mutex before the os has been started. Notes If the mutex is owned by another task and the timeout is 0 the function returns immediately with the error code OS_TIMEOUT. The calling task does not own the mutex when this occurs. Example struct os_mutex g_mutex1 ; os_error_t err ; err = os_mutex_pend ( &g_mutex1 , 0 ); assert ( err == OS_OK ); /* Perform operations requiring exclusive access */ err = os_mutex_release ( &g_mutex1 ); assert ( err == OS_OK );","title":"os_mutex_pend"},{"location":"os/core_os/mutex/os_mutex_pend/#os_mutex_pend","text":"os_error_t os_mutex_pend ( struct os_mutex *mu , uint32_t timeout ) Acquire ownership of a mutex.","title":"os_mutex_pend "},{"location":"os/core_os/mutex/os_mutex_pend/#arguments","text":"Arguments Description *mu Pointer to mutex timeout Timeout, in os ticks. A value of 0 means no timeout. A value of 0xFFFFFFFF means to wait forever.","title":"Arguments"},{"location":"os/core_os/mutex/os_mutex_pend/#returned-values","text":"OS_INVALID_PARM: returned when *mu is NULL on entry. OS_OK: mutex was successfully acquired. OS_TIMEOUT: the mutex was not available within the timeout specified. OS_NOT_STARTED: Attempt to release a mutex before the os has been started.","title":"Returned values"},{"location":"os/core_os/mutex/os_mutex_pend/#notes","text":"If the mutex is owned by another task and the timeout is 0 the function returns immediately with the error code OS_TIMEOUT. The calling task does not own the mutex when this occurs.","title":"Notes"},{"location":"os/core_os/mutex/os_mutex_pend/#example","text":"struct os_mutex g_mutex1 ; os_error_t err ; err = os_mutex_pend ( &g_mutex1 , 0 ); assert ( err == OS_OK ); /* Perform operations requiring exclusive access */ err = os_mutex_release ( &g_mutex1 ); assert ( err == OS_OK );","title":"Example"},{"location":"os/core_os/mutex/os_mutex_release/","text":"os_mutex_release os_error_t os_mutex_release ( struct os_mutex *mu ) Release ownership of a mutex Arguments Arguments Description *mu Pointer to mutex Returned values OS_INVALID_PARM: returned when *mu is NULL on entry. OS_OK: mutex initialized successfully. OS_BAD_MUTEX: The mutex was not owned by the task attempting to release it. OS_NOT_STARTED: Attempt to release a mutex before the os has been started. Example struct os_mutex g_mutex1 ; os_error_t err ; err = os_mutex_pend ( &g_mutex1 , 0 ); assert ( err == OS_OK ); /* Perform operations requiring exclusive access */ err = os_mutex_release ( &g_mutex1 ); assert ( err == OS_OK );","title":"os_mutex_release"},{"location":"os/core_os/mutex/os_mutex_release/#os_mutex_release","text":"os_error_t os_mutex_release ( struct os_mutex *mu ) Release ownership of a mutex","title":"os_mutex_release"},{"location":"os/core_os/mutex/os_mutex_release/#arguments","text":"Arguments Description *mu Pointer to mutex","title":"Arguments"},{"location":"os/core_os/mutex/os_mutex_release/#returned-values","text":"OS_INVALID_PARM: returned when *mu is NULL on entry. OS_OK: mutex initialized successfully. OS_BAD_MUTEX: The mutex was not owned by the task attempting to release it. OS_NOT_STARTED: Attempt to release a mutex before the os has been started.","title":"Returned values"},{"location":"os/core_os/mutex/os_mutex_release/#example","text":"struct os_mutex g_mutex1 ; os_error_t err ; err = os_mutex_pend ( &g_mutex1 , 0 ); assert ( err == OS_OK ); /* Perform operations requiring exclusive access */ err = os_mutex_release ( &g_mutex1 ); assert ( err == OS_OK );","title":"Example"},{"location":"os/core_os/porting/port_bsp/","text":"Create a BSP for your Target Introduction If you are using a board or system not currently supported by Mynewt, you will need to create a BSP for the new target. If another similar BSP exists it is recommended to copy that BSP as a starting point. For example, if another BSP exists using the same MCU, start with a copy of that BSP. Either way, this document describes the steps necessary to create a new BSP from scratch. Keep your Reference Documents handy To build a proper BSP, you will typically need the following: The datasheet for the MCU you have chosen The schematic of your board The information on the CPU core within your MCU if it is not included in your MCU documentation This Mynewt documentation Name your BSP Select a name for your BSP. For the remainder of this document, we'll assume the bsp is named myboard . In general its best to select a name that describes the board/system you are creating. Create a BSP directory Create a directory hw/bsp/myboard using the name chosen above. Within this BSP directory, create the following subdirectories: Select a name for your BSP. For the remainder of this document, well assume the bsp is named myboard . In general its best to select a name that describes the board/system you are creating. include include/bsp src Create a Target using Mynewt Create a newt target for your test project for the BSP. To learn how to create a target, see this howto Tutorial . Once you are familiar with creating targets, move on below to create a target to use to test your BSP. It is recommended that you use a simple project like blinky to minimize time to get a working Mynewt system. For this document, we will assume the target is called myboard_blinky and uses project blinky . Set the bsp of the project to /hw/bsp/myboard . While creating your target, you will need to specify your arch and compiler . If your platform requires an architecture or compiler that are not defined in Mynewt, you will need to add them first. To add a CPU architecture see CPU Porting . When you are complete, your target may look similar to this. $newt target show myboard_blinky arch=cortex_m0 bsp=hw/bsp/myboard compiler=arm-none-eabi-m0 compiler_def=debug name=myboard_blinky project=blinky Create Required Files For Compilation Create the following files within the BSP directory tree. For now, they can be empty files. We will fill them out one at a time. File Path Name Description LICENSE A File to present the source license for your BSP README.md A markdown file to write documentation for your BSP pkg.yml A package file to describe your BSP contents include/bsp/bsp.h A header file to include definitions required by system from the BSP include/bsp/bsp_sysid.h A header file to enumerate the devices in your BSP src/os_bsp.c A C source file to provide functions required by the OS from your BSP src/sbrk.c A C source file to memory from your heap to the OS src/libc_stubs.c A C source file to provide stubs/methods required by libc myboard.ld A linker script to provide the memory map for your linked code Optionally, create these files as necessary to provide all functionality from Mynewt. File Path Name Description myboard_boot.ld A linker script to provide the memory map for your bootloader myboard_download.sh A bash script to download code into your platform myboard_debug.sh A bash script to intiate a gdb session with your platform src/hal_bsp.c A C source file to provide functions required by the HAL from your BSP Fill Out your Package File Edit the package file to describe your BSP. The package file must contain: pkg . name: \"hw/bsp/myboard\" pkg . linkerscript: \"myboard.ld\" Attribute Description pkg.name The name of your bsp package pkg.linkerscript The linker script that controls the memory placement of the compiled code sections from the Mynewt OS and your applications. The linker script is a key component of the BSP and specifies where each section of code and data are stored within your CPU which can vary with the BSP depending on your chosen memory layout. For a tutorial on writing linker scripts, see Create or Copy Linker Script(s) . The package file typically contains: pkg . linkerscript . bootloader . OVERWRITE: \"myboard_boot.ld\" pkg . downloadscript: \"myboard_download.sh\" pkg . debugscript: \"myboard_debug.sh\" pkg . deps: - hw/mcu/mymcu/variant where mymcu/variant should be replaced with the specific MCU and variant used in your design. The following table describes additional attributes relevant to the BSP pkg.yml file. Attribute Description pkg.linkerscript.bootloader.OVERWRITE A special linker for creating a bootloader for Mynewt pkg.downloadscript A script that can download a flash image into your target platform pkg.debugscript A script that can run the GDB debugger on your board pkg.deps Any dependencies on your BSP The BSP will invariably depend upon an MCU ( in this sample it's hw/mcu/mymcu/variant ) since the Mynewt OS runs on an MCU within your target. If your MCU is not supported by Mynewt, see MCU Porting for details on how to create an MCU in Mynewt. The package file may also contain: pkg . cflags: -D__MY_SPECIAL_BSP_OPTIONS_ pkg . deps: - libs/cmsis-core Attribute Description pkg.cflags Any specific compiler flags for your bsp pkg.deps Any other libraries that may be required. Some architectures (like ARM) have special libraries to make BSP creation easier. Create or Copy Linker Script It's probably best to start with a linker script from another BSP using the same MCU. If this is not available, consult your MCU documentation and library samples to find a linker script to start with. Typically, a linker script has to specify the following sections for code: .text -- the location and alignment of the memory section to store your code .data -- the location and alignment of the memory section to store initialized data .bss -- the location and alignment of the memory section to store uninitialized data .heap -- the location and alignment of the memory section to provide system memory The linker script should specify the location and size of the different memory regions in your BSP and map the code sections described above into these regions. The linker script should also include an ENTRY point. This is used by the debugger to know where to start the program counter when the target is debugged. There may be additional requirements from the MCU or OS that you may find easiest to place in the linker script. Some specific variables that the OS and MCU depends on are : Variable Description __bss_start__ a variable located at the start of the BSS section __bss_end__ a variable located at the end of the BSS section __isr_vector Some CPUs map their interrupt vectors. They may need to be specified in the linker _user_heap_start the start of the heap for unallocated memory _user_heap_end the end of the heap for unallocated memory Create an alternate linker script for the bootloader since it is typically linked to use different addresses to boot the main image. Add Functions and Defines At this point, it will be possible to run the newt tool to build your target. You may run into complaints from the linker script that a few Mynewt specific functions are missing. We will describe these below. Function Description os_bsp_init() code to initialize the bsp os_bsp_systick_init() code to setup the system tick for the OS There are also several libc definitions that can be stubbed in your first BSP. Examples are _write , _read , etc. that can be found in libc_stubs.c . But you must implement the following function to provide memory to the OS and system. Function Description _sbrk Returns memory from heap (used by malloc) Implement _sbrk() sbrk() is required by libc to get memory from the heap for things like malloc. Although not strongly BSP dependent, this is currently in the BSP to allow flexibility in providing system memory. See other BSPs for providing sbrk functionality. Implement os_bsp_init() os_bsp_init should initialize anything required by the OS by the BSP. Typically this is a very small set. NOTE: Currently we are making calls to _sbrk() and close(0) from os_bsp_init to get around a linker issue where some of libc is not getting included. Please include this in your os_bsp_init . /* * XXX these references are here to keep the functions in for libc to find. */ _sbrk ( 0 ); _close ( 0 ); Other Unresolved Defines or Functions There may be other unresolved defines or functions that are required by the specific MCU within your BSP. Below lists some sample defines. Undefined Variable Description CONSOLE_UART_PORT Which communications port on your target runs the console LED_BLINK_PIN which pin on your target runs the blinky LED The set of missing functionality depends upon the libraries and dependencies you have included in the project. That's why its best to keep your first project pretty simple then add incrementally. For example, if you include Newtron file system, you will need to define a file system map for your BSP. Missing functionality may take the form of #define items required to compile, or they may take the form of missing functions. cmsis_nvic.h If you are using an ARM cortex architecture, you need to define the number of interrupts supported by your system. If you are not using ARM Cortex architecture this may not be required (but something else might be). Add Debug Script The debug script in the bsp directory allows the newt tool to automatically connect to the debugger, and create a debug session with the target. This requires knowledge of your target debug interface. Most of the Mynewt BSP targets use openocd to perform debugging. This script typically creates an openocd connection to the target and then connects a gdb instance to this openocd connection. There are several examples in existing BSPs to follow. The script must take a single argument which is the name of the image file minus the '.elf' suffix. The BSP is complete without this file, but newt will be unable to establish a debug session without it. Add Download Script Similar to the debug script, the download script is a hook for newt to download the image to the target system. The download script also typically uses openocd interface to erase flash, and progam the code into the device. NOTE: The download script needs to command openocd to program the image into the appropriate location, which is typically called FLASH_OFFSET in these scripts. This location has to match the linker script location of the image link address. For example, if your linker links the code to be run at 0xC000 your download script should download the image to the same address in the correct flash. Add License and Documentation The LICENSE file is an ASCII text file that describes the source license for this package. The README.md is a markdown file that contains any documentation you want to provide for the BSP.","title":"BSP Porting"},{"location":"os/core_os/porting/port_bsp/#create-a-bsp-for-your-target","text":"","title":"Create a BSP for your Target"},{"location":"os/core_os/porting/port_bsp/#introduction","text":"If you are using a board or system not currently supported by Mynewt, you will need to create a BSP for the new target. If another similar BSP exists it is recommended to copy that BSP as a starting point. For example, if another BSP exists using the same MCU, start with a copy of that BSP. Either way, this document describes the steps necessary to create a new BSP from scratch.","title":"Introduction"},{"location":"os/core_os/porting/port_bsp/#keep-your-reference-documents-handy","text":"To build a proper BSP, you will typically need the following: The datasheet for the MCU you have chosen The schematic of your board The information on the CPU core within your MCU if it is not included in your MCU documentation This Mynewt documentation","title":"Keep your Reference Documents handy"},{"location":"os/core_os/porting/port_bsp/#name-your-bsp","text":"Select a name for your BSP. For the remainder of this document, we'll assume the bsp is named myboard . In general its best to select a name that describes the board/system you are creating.","title":"Name your BSP"},{"location":"os/core_os/porting/port_bsp/#create-a-bsp-directory","text":"Create a directory hw/bsp/myboard using the name chosen above. Within this BSP directory, create the following subdirectories: Select a name for your BSP. For the remainder of this document, well assume the bsp is named myboard . In general its best to select a name that describes the board/system you are creating. include include/bsp src","title":"Create a BSP directory"},{"location":"os/core_os/porting/port_bsp/#create-a-target-using-mynewt","text":"Create a newt target for your test project for the BSP. To learn how to create a target, see this howto Tutorial . Once you are familiar with creating targets, move on below to create a target to use to test your BSP. It is recommended that you use a simple project like blinky to minimize time to get a working Mynewt system. For this document, we will assume the target is called myboard_blinky and uses project blinky . Set the bsp of the project to /hw/bsp/myboard . While creating your target, you will need to specify your arch and compiler . If your platform requires an architecture or compiler that are not defined in Mynewt, you will need to add them first. To add a CPU architecture see CPU Porting . When you are complete, your target may look similar to this. $newt target show myboard_blinky arch=cortex_m0 bsp=hw/bsp/myboard compiler=arm-none-eabi-m0 compiler_def=debug name=myboard_blinky project=blinky","title":"Create a Target using Mynewt"},{"location":"os/core_os/porting/port_bsp/#create-required-files-for-compilation","text":"Create the following files within the BSP directory tree. For now, they can be empty files. We will fill them out one at a time. File Path Name Description LICENSE A File to present the source license for your BSP README.md A markdown file to write documentation for your BSP pkg.yml A package file to describe your BSP contents include/bsp/bsp.h A header file to include definitions required by system from the BSP include/bsp/bsp_sysid.h A header file to enumerate the devices in your BSP src/os_bsp.c A C source file to provide functions required by the OS from your BSP src/sbrk.c A C source file to memory from your heap to the OS src/libc_stubs.c A C source file to provide stubs/methods required by libc myboard.ld A linker script to provide the memory map for your linked code Optionally, create these files as necessary to provide all functionality from Mynewt. File Path Name Description myboard_boot.ld A linker script to provide the memory map for your bootloader myboard_download.sh A bash script to download code into your platform myboard_debug.sh A bash script to intiate a gdb session with your platform src/hal_bsp.c A C source file to provide functions required by the HAL from your BSP","title":"Create Required Files For Compilation"},{"location":"os/core_os/porting/port_bsp/#fill-out-your-package-file","text":"Edit the package file to describe your BSP. The package file must contain: pkg . name: \"hw/bsp/myboard\" pkg . linkerscript: \"myboard.ld\" Attribute Description pkg.name The name of your bsp package pkg.linkerscript The linker script that controls the memory placement of the compiled code sections from the Mynewt OS and your applications. The linker script is a key component of the BSP and specifies where each section of code and data are stored within your CPU which can vary with the BSP depending on your chosen memory layout. For a tutorial on writing linker scripts, see Create or Copy Linker Script(s) . The package file typically contains: pkg . linkerscript . bootloader . OVERWRITE: \"myboard_boot.ld\" pkg . downloadscript: \"myboard_download.sh\" pkg . debugscript: \"myboard_debug.sh\" pkg . deps: - hw/mcu/mymcu/variant where mymcu/variant should be replaced with the specific MCU and variant used in your design. The following table describes additional attributes relevant to the BSP pkg.yml file. Attribute Description pkg.linkerscript.bootloader.OVERWRITE A special linker for creating a bootloader for Mynewt pkg.downloadscript A script that can download a flash image into your target platform pkg.debugscript A script that can run the GDB debugger on your board pkg.deps Any dependencies on your BSP The BSP will invariably depend upon an MCU ( in this sample it's hw/mcu/mymcu/variant ) since the Mynewt OS runs on an MCU within your target. If your MCU is not supported by Mynewt, see MCU Porting for details on how to create an MCU in Mynewt. The package file may also contain: pkg . cflags: -D__MY_SPECIAL_BSP_OPTIONS_ pkg . deps: - libs/cmsis-core Attribute Description pkg.cflags Any specific compiler flags for your bsp pkg.deps Any other libraries that may be required. Some architectures (like ARM) have special libraries to make BSP creation easier.","title":"Fill Out your Package File"},{"location":"os/core_os/porting/port_bsp/#create-or-copy-linker-script","text":"It's probably best to start with a linker script from another BSP using the same MCU. If this is not available, consult your MCU documentation and library samples to find a linker script to start with. Typically, a linker script has to specify the following sections for code: .text -- the location and alignment of the memory section to store your code .data -- the location and alignment of the memory section to store initialized data .bss -- the location and alignment of the memory section to store uninitialized data .heap -- the location and alignment of the memory section to provide system memory The linker script should specify the location and size of the different memory regions in your BSP and map the code sections described above into these regions. The linker script should also include an ENTRY point. This is used by the debugger to know where to start the program counter when the target is debugged. There may be additional requirements from the MCU or OS that you may find easiest to place in the linker script. Some specific variables that the OS and MCU depends on are : Variable Description __bss_start__ a variable located at the start of the BSS section __bss_end__ a variable located at the end of the BSS section __isr_vector Some CPUs map their interrupt vectors. They may need to be specified in the linker _user_heap_start the start of the heap for unallocated memory _user_heap_end the end of the heap for unallocated memory Create an alternate linker script for the bootloader since it is typically linked to use different addresses to boot the main image.","title":"Create or Copy Linker Script"},{"location":"os/core_os/porting/port_bsp/#add-functions-and-defines","text":"At this point, it will be possible to run the newt tool to build your target. You may run into complaints from the linker script that a few Mynewt specific functions are missing. We will describe these below. Function Description os_bsp_init() code to initialize the bsp os_bsp_systick_init() code to setup the system tick for the OS There are also several libc definitions that can be stubbed in your first BSP. Examples are _write , _read , etc. that can be found in libc_stubs.c . But you must implement the following function to provide memory to the OS and system. Function Description _sbrk Returns memory from heap (used by malloc) Implement _sbrk() sbrk() is required by libc to get memory from the heap for things like malloc. Although not strongly BSP dependent, this is currently in the BSP to allow flexibility in providing system memory. See other BSPs for providing sbrk functionality. Implement os_bsp_init() os_bsp_init should initialize anything required by the OS by the BSP. Typically this is a very small set. NOTE: Currently we are making calls to _sbrk() and close(0) from os_bsp_init to get around a linker issue where some of libc is not getting included. Please include this in your os_bsp_init . /* * XXX these references are here to keep the functions in for libc to find. */ _sbrk ( 0 ); _close ( 0 ); Other Unresolved Defines or Functions There may be other unresolved defines or functions that are required by the specific MCU within your BSP. Below lists some sample defines. Undefined Variable Description CONSOLE_UART_PORT Which communications port on your target runs the console LED_BLINK_PIN which pin on your target runs the blinky LED The set of missing functionality depends upon the libraries and dependencies you have included in the project. That's why its best to keep your first project pretty simple then add incrementally. For example, if you include Newtron file system, you will need to define a file system map for your BSP. Missing functionality may take the form of #define items required to compile, or they may take the form of missing functions. cmsis_nvic.h If you are using an ARM cortex architecture, you need to define the number of interrupts supported by your system. If you are not using ARM Cortex architecture this may not be required (but something else might be).","title":"Add Functions and Defines"},{"location":"os/core_os/porting/port_bsp/#add-debug-script","text":"The debug script in the bsp directory allows the newt tool to automatically connect to the debugger, and create a debug session with the target. This requires knowledge of your target debug interface. Most of the Mynewt BSP targets use openocd to perform debugging. This script typically creates an openocd connection to the target and then connects a gdb instance to this openocd connection. There are several examples in existing BSPs to follow. The script must take a single argument which is the name of the image file minus the '.elf' suffix. The BSP is complete without this file, but newt will be unable to establish a debug session without it.","title":"Add Debug Script"},{"location":"os/core_os/porting/port_bsp/#add-download-script","text":"Similar to the debug script, the download script is a hook for newt to download the image to the target system. The download script also typically uses openocd interface to erase flash, and progam the code into the device. NOTE: The download script needs to command openocd to program the image into the appropriate location, which is typically called FLASH_OFFSET in these scripts. This location has to match the linker script location of the image link address. For example, if your linker links the code to be run at 0xC000 your download script should download the image to the same address in the correct flash.","title":"Add Download Script"},{"location":"os/core_os/porting/port_bsp/#add-license-and-documentation","text":"The LICENSE file is an ASCII text file that describes the source license for this package. The README.md is a markdown file that contains any documentation you want to provide for the BSP.","title":"Add License and Documentation"},{"location":"os/core_os/porting/port_cpu/","text":"Porting Mynewt to a new CPU Architecture A new CPU architecture typically requires the following: A new compiler New architecture-specific code for the OS Helper libraries to help others porting to the same architecture These are discussed below: Create A New Compiler NOTE: Newt does not automatically install the compilers require to build all platforms. Its up to the user using their local machines package manager to install the compilers. The step described here just registers the compiler with newt. Create a new directory (named after the compiler you are adding). Copy the pkg.yml file from another compiler. Edit the pkg.yml file and change the configuration attributes to match your compiler. Most are self-explanatory paths to different compiler and linker tools. There are a few configuration attributes worth noting. Configuration Attributes Description pkg.keywords Specific keywords to help others search for this using newt compiler.flags.default default compiler flags for this architecture compiler.flags.optimized additional flags when the newt tool builds an optimized image compiler.flags.debug additional flags when the newt tool builds a debug image Implement architecture-specific OS code There are several architecture-specific code functions that are required when implementing a new architecture. You can find examples in the sim architecture within Mynewt. When porting to a new CPU architecture, use the existing architectures as samples when writing your implementation. Please contact the Mynewt development list for help and advice portingto new MCU.","title":"CPU Porting"},{"location":"os/core_os/porting/port_cpu/#porting-mynewt-to-a-new-cpu-architecture","text":"A new CPU architecture typically requires the following: A new compiler New architecture-specific code for the OS Helper libraries to help others porting to the same architecture These are discussed below:","title":"Porting Mynewt to a new CPU Architecture"},{"location":"os/core_os/porting/port_cpu/#create-a-new-compiler","text":"NOTE: Newt does not automatically install the compilers require to build all platforms. Its up to the user using their local machines package manager to install the compilers. The step described here just registers the compiler with newt. Create a new directory (named after the compiler you are adding). Copy the pkg.yml file from another compiler. Edit the pkg.yml file and change the configuration attributes to match your compiler. Most are self-explanatory paths to different compiler and linker tools. There are a few configuration attributes worth noting. Configuration Attributes Description pkg.keywords Specific keywords to help others search for this using newt compiler.flags.default default compiler flags for this architecture compiler.flags.optimized additional flags when the newt tool builds an optimized image compiler.flags.debug additional flags when the newt tool builds a debug image","title":"Create A New Compiler"},{"location":"os/core_os/porting/port_cpu/#implement-architecture-specific-os-code","text":"There are several architecture-specific code functions that are required when implementing a new architecture. You can find examples in the sim architecture within Mynewt. When porting to a new CPU architecture, use the existing architectures as samples when writing your implementation. Please contact the Mynewt development list for help and advice portingto new MCU.","title":"Implement architecture-specific OS code"},{"location":"os/core_os/porting/port_mcu/","text":"Porting Mynewt to a new MCU Porting Mynewt to a new MCU is not a difficult task if the core CPU architectures is already supported. The depth of work depends on the amount of HAL (Hardware Abstraction Layer) support you need and provide in your port. To get started: Create a hw/mcu/mymcu directory where mymcu is the MCU you are porting to. Replace the name mymcu with a description of the MCU you are using. Create a hw/mcu/mymcu/variant directory where the variant is the specific variant of the part you are usuing. Many MCU parts have variants with different capabilities (RAM, FLASH etc) or different pinouts. Replace variant with a description of the variant of the part you are using. Create a hw/mcu/mymcu/variant/pkg.yml file. Copy from another mcu and fill out the relevant information Create hw/mcu/mymcu/variant/include , hw/mcu/mymcu/variant/include/mcu , and hw/mcu/mymcu/variant/src directories to contain the code for your mcu. At this point there are two main tasks to complete. Implement any OS-specific code required by the OS Implement the HAL functionality that you are looking for Please contact the Mynewt development list for help and advice porting to new MCU.","title":"MCU Porting"},{"location":"os/core_os/porting/port_mcu/#porting-mynewt-to-a-new-mcu","text":"Porting Mynewt to a new MCU is not a difficult task if the core CPU architectures is already supported. The depth of work depends on the amount of HAL (Hardware Abstraction Layer) support you need and provide in your port. To get started: Create a hw/mcu/mymcu directory where mymcu is the MCU you are porting to. Replace the name mymcu with a description of the MCU you are using. Create a hw/mcu/mymcu/variant directory where the variant is the specific variant of the part you are usuing. Many MCU parts have variants with different capabilities (RAM, FLASH etc) or different pinouts. Replace variant with a description of the variant of the part you are using. Create a hw/mcu/mymcu/variant/pkg.yml file. Copy from another mcu and fill out the relevant information Create hw/mcu/mymcu/variant/include , hw/mcu/mymcu/variant/include/mcu , and hw/mcu/mymcu/variant/src directories to contain the code for your mcu. At this point there are two main tasks to complete. Implement any OS-specific code required by the OS Implement the HAL functionality that you are looking for Please contact the Mynewt development list for help and advice porting to new MCU.","title":"Porting Mynewt to a new MCU"},{"location":"os/core_os/porting/port_os/","text":"Porting Mynewt OS This chapter describes how to adapt the Mynewt OS to different platforms. Description The Mynewt OS is a complete multi-tasking environment with scheduler, time control, buffer management, and synchronization objects. it also includes libraries and services like console, command shell, image manager, bootloader, and file systems etc. Thee majority of this software is platform independent and requires no intervention to run on your platform, but some of the components require support from the underlying platform. The platform dependency of these components can fall into several categories: CPU Core Dependencies -- Specific code or configuration to operate the CPU core within your target platform MCU Dependencies -- Specific code or configuration to operate the MCU or SoC within your target platform BSP Dependencies -- Specific code or configuration to accommodate the specific layout and functionality of your target platform BSP Dependency With all of the functionality provided by the core, MCU, and MCU HAL (Hardware Abstraction Layer), there are still some things that must be specified for your particular system. This is provided in Mynewt to allow you the flexibility to design for the exact functionality, peripherals and features that you require in your product. In Mynewt, these settings/components are included in a Board Support Package (BSP). The BSP contains the information specific to running Mynewt on a target platform or hardware board. Mynewt supports some common open source hardware as well as the development boards for some common MCUs. These development systems might be enough for you to get your prototype up and running, but when building a product you are likely going to have your own board which is slightly different from those already supported by Mynewt. For example, you might decide on your system that 16 Kilobytes of flash space in one flash device is reserved for a flash file system. Or on your system you may decide that GPIO pin 5 of the MCU is connected to the system LED. Or you may decide that the OS Tick (the underlying time source for the OS) should run slower than the defaults to conserve battery power. These types of behaviors are specified in the BSP. The information provided in the BSP (what you need to specify to get a complete executable) can vary depending on the MCU and its underlying core architecture. For example, some MCUs have dedicated pins for UART, SPI etc, so there is no configuration required in the BSP when using these peripherals. However some MCUs have a pin multiplexor that allows the UART to be mapped to several different pins. For these MCUs, the BSP must specify if and where the UART pins should appear to match the hardware layout of your system. If your BSP is already supported my Mynewt, there is no additional BSP work involved in porting to your platform. You need only to set the bsp attribute in your Mynewt target using the newt command tool . If your BSP is not yet supported by Mynewt, you can add support following the instructions on how to add BSP support to Mynewt MCU Dependency Some OS code depends on the MCU or SoC that the system contains. For example, the MCU may specify the potential memory map of the system - where code and data can reside. If your MCU is already supported my Mynewt, there is no additional MCU work involved in porting to your platform. You need only to set the arch attribute in your Mynewt target using the newt command tool . If your MCU is not yet supported by Mynewt, you can add support following the instructions on how to add MCU support to Mynewt MCU HAL Mynewt's architecture supports a hardware abstraction layer (HAL) for common on or off-chip MCU peripherals such as GPIO, UARTs, flash memory etc. Even if your MCU is supported for the core OS, you may find that you need to implement the HAL functionality for a new peripheral. For a description of the HAL abstraction and implementation information, see the HAL API CPU Core Dependency Some OS code depends on the CPU core that your system is using. For example, a given CPU core has a specific assembly language instruction set, and may require special cross compiler or compiler settings to use the appropriate instruction set. If your CPU architecture is already supported my Mynewt, there is no CPU core work involved in porting to your platform. You need only to set the arch and compiler attributes in your Mynewt target using the newt command tool . If your CPU architecture is not supported by Mynewt, you can add support following the instructions on how to add CPU architecture support to Mynewt","title":"toc"},{"location":"os/core_os/porting/port_os/#porting-mynewt-os","text":"This chapter describes how to adapt the Mynewt OS to different platforms.","title":"Porting Mynewt OS"},{"location":"os/core_os/porting/port_os/#description","text":"The Mynewt OS is a complete multi-tasking environment with scheduler, time control, buffer management, and synchronization objects. it also includes libraries and services like console, command shell, image manager, bootloader, and file systems etc. Thee majority of this software is platform independent and requires no intervention to run on your platform, but some of the components require support from the underlying platform. The platform dependency of these components can fall into several categories: CPU Core Dependencies -- Specific code or configuration to operate the CPU core within your target platform MCU Dependencies -- Specific code or configuration to operate the MCU or SoC within your target platform BSP Dependencies -- Specific code or configuration to accommodate the specific layout and functionality of your target platform","title":"Description"},{"location":"os/core_os/porting/port_os/#bsp-dependency","text":"With all of the functionality provided by the core, MCU, and MCU HAL (Hardware Abstraction Layer), there are still some things that must be specified for your particular system. This is provided in Mynewt to allow you the flexibility to design for the exact functionality, peripherals and features that you require in your product. In Mynewt, these settings/components are included in a Board Support Package (BSP). The BSP contains the information specific to running Mynewt on a target platform or hardware board. Mynewt supports some common open source hardware as well as the development boards for some common MCUs. These development systems might be enough for you to get your prototype up and running, but when building a product you are likely going to have your own board which is slightly different from those already supported by Mynewt. For example, you might decide on your system that 16 Kilobytes of flash space in one flash device is reserved for a flash file system. Or on your system you may decide that GPIO pin 5 of the MCU is connected to the system LED. Or you may decide that the OS Tick (the underlying time source for the OS) should run slower than the defaults to conserve battery power. These types of behaviors are specified in the BSP. The information provided in the BSP (what you need to specify to get a complete executable) can vary depending on the MCU and its underlying core architecture. For example, some MCUs have dedicated pins for UART, SPI etc, so there is no configuration required in the BSP when using these peripherals. However some MCUs have a pin multiplexor that allows the UART to be mapped to several different pins. For these MCUs, the BSP must specify if and where the UART pins should appear to match the hardware layout of your system. If your BSP is already supported my Mynewt, there is no additional BSP work involved in porting to your platform. You need only to set the bsp attribute in your Mynewt target using the newt command tool . If your BSP is not yet supported by Mynewt, you can add support following the instructions on how to add BSP support to Mynewt","title":"BSP Dependency"},{"location":"os/core_os/porting/port_os/#mcu-dependency","text":"Some OS code depends on the MCU or SoC that the system contains. For example, the MCU may specify the potential memory map of the system - where code and data can reside. If your MCU is already supported my Mynewt, there is no additional MCU work involved in porting to your platform. You need only to set the arch attribute in your Mynewt target using the newt command tool . If your MCU is not yet supported by Mynewt, you can add support following the instructions on how to add MCU support to Mynewt","title":"MCU Dependency"},{"location":"os/core_os/porting/port_os/#mcu-hal","text":"Mynewt's architecture supports a hardware abstraction layer (HAL) for common on or off-chip MCU peripherals such as GPIO, UARTs, flash memory etc. Even if your MCU is supported for the core OS, you may find that you need to implement the HAL functionality for a new peripheral. For a description of the HAL abstraction and implementation information, see the HAL API","title":"MCU HAL"},{"location":"os/core_os/porting/port_os/#cpu-core-dependency","text":"Some OS code depends on the CPU core that your system is using. For example, a given CPU core has a specific assembly language instruction set, and may require special cross compiler or compiler settings to use the appropriate instruction set. If your CPU architecture is already supported my Mynewt, there is no CPU core work involved in porting to your platform. You need only to set the arch and compiler attributes in your Mynewt target using the newt command tool . If your CPU architecture is not supported by Mynewt, you can add support following the instructions on how to add CPU architecture support to Mynewt","title":"CPU Core Dependency"},{"location":"os/core_os/sanity/os_sanity_check_init/","text":"os_sanity_check_init int os_sanity_check_init ( struct os_sanity_check *sc ) Initialize the sanity check pointed to by sc . Sets default values, and ensures memory is cleared out. Arguments Arguments Description sc Pointer to sanity check Returned values OS_OK : sanity check initialization is successful All other error codes indicate an error. Example int rc ; rc = os_sanity_task_check_init ( &my_sanity_check ); assert ( rc == OS_OK );","title":"os_sanity_check_init"},{"location":"os/core_os/sanity/os_sanity_check_init/#os_sanity_check_init","text":"int os_sanity_check_init ( struct os_sanity_check *sc ) Initialize the sanity check pointed to by sc . Sets default values, and ensures memory is cleared out.","title":" os_sanity_check_init"},{"location":"os/core_os/sanity/os_sanity_check_init/#arguments","text":"Arguments Description sc Pointer to sanity check","title":"Arguments"},{"location":"os/core_os/sanity/os_sanity_check_init/#returned-values","text":"OS_OK : sanity check initialization is successful All other error codes indicate an error.","title":"Returned values"},{"location":"os/core_os/sanity/os_sanity_check_init/#example","text":"int rc ; rc = os_sanity_task_check_init ( &my_sanity_check ); assert ( rc == OS_OK );","title":"Example"},{"location":"os/core_os/sanity/os_sanity_check_register/","text":"os_sanity_check_register int os_sanity_check_register ( struct os_sanity_check *sc ) Register the sanity check pointed to by sc with the sanity task. After registration the sanity task will check this sanity check with every run of the sanity task. Arguments Arguments Description sc Pointer to sanity check Returned values OS_OK : sanity check successfully registered All other error codes indicate an error. Example int rc ; rc = os_sanity_check_register ( &my_sc ); assert ( rc == OS_OK );","title":"os_sanity_check_register"},{"location":"os/core_os/sanity/os_sanity_check_register/#os_sanity_check_register","text":"int os_sanity_check_register ( struct os_sanity_check *sc ) Register the sanity check pointed to by sc with the sanity task. After registration the sanity task will check this sanity check with every run of the sanity task.","title":" os_sanity_check_register"},{"location":"os/core_os/sanity/os_sanity_check_register/#arguments","text":"Arguments Description sc Pointer to sanity check","title":"Arguments"},{"location":"os/core_os/sanity/os_sanity_check_register/#returned-values","text":"OS_OK : sanity check successfully registered All other error codes indicate an error.","title":"Returned values"},{"location":"os/core_os/sanity/os_sanity_check_register/#example","text":"int rc ; rc = os_sanity_check_register ( &my_sc ); assert ( rc == OS_OK );","title":"Example"},{"location":"os/core_os/sanity/os_sanity_check_reset/","text":"os_sanity_check_reset int os_sanity_check_reset ( struct os_sanity_check *sc ) Reset the sanity check pointed to by sc. This tells the sanity task that this sanity check is considered valid for another sc_checkin_itvl time ticks. Arguments Arguments Description sc Pointer to sanity check Returned values OS_OK : sanity check reset successful All other error codes indicate an error. Example int rc ; rc = os_sanity_check_reset ( &my_sc ); assert ( rc == OS_OK );","title":"os_sanity_check_reset"},{"location":"os/core_os/sanity/os_sanity_check_reset/#os_sanity_check_reset","text":"int os_sanity_check_reset ( struct os_sanity_check *sc ) Reset the sanity check pointed to by sc. This tells the sanity task that this sanity check is considered valid for another sc_checkin_itvl time ticks.","title":" os_sanity_check_reset"},{"location":"os/core_os/sanity/os_sanity_check_reset/#arguments","text":"Arguments Description sc Pointer to sanity check","title":"Arguments"},{"location":"os/core_os/sanity/os_sanity_check_reset/#returned-values","text":"OS_OK : sanity check reset successful All other error codes indicate an error.","title":"Returned values"},{"location":"os/core_os/sanity/os_sanity_check_reset/#example","text":"int rc ; rc = os_sanity_check_reset ( &my_sc ); assert ( rc == OS_OK );","title":"Example"},{"location":"os/core_os/sanity/os_sanity_task_checkin/","text":"os_sanity_task_checkin int os_sanity_task_checkin ( struct os_task *t ) Used by a task to check in to the sanity task. This informs the sanity task that task is still alive and working normally. Arguments Arguments Description t Pointer to task Returned values OS_OK : sanity check-in successful All other error codes indicate an error. Example int rc ; rc = os_sanity_task_checkin ( &my_task ); assert ( rc == OS_OK );","title":"os_sanity_task_checkin"},{"location":"os/core_os/sanity/os_sanity_task_checkin/#os_sanity_task_checkin","text":"int os_sanity_task_checkin ( struct os_task *t ) Used by a task to check in to the sanity task. This informs the sanity task that task is still alive and working normally.","title":" os_sanity_task_checkin"},{"location":"os/core_os/sanity/os_sanity_task_checkin/#arguments","text":"Arguments Description t Pointer to task","title":"Arguments"},{"location":"os/core_os/sanity/os_sanity_task_checkin/#returned-values","text":"OS_OK : sanity check-in successful All other error codes indicate an error.","title":"Returned values"},{"location":"os/core_os/sanity/os_sanity_task_checkin/#example","text":"int rc ; rc = os_sanity_task_checkin ( &my_task ); assert ( rc == OS_OK );","title":"Example"},{"location":"os/core_os/sanity/os_sanity_task_init/","text":"os_sanity_task_init int os_sanity_task_init ( int num_secs ); Initialize the os sanity task. num_secs is the number of seconds to wait in between runs of the sanity task. Arguments Arguments Description num_secs Number of seconds to wait in between running sanity checks. Returned values OS_OK : Sanity task was successfully created. All other error codes indicate an error. Example /* Run sanity checks every 50 seconds */ #define SANITY_TASK_INTERVAL (50) int rc ; rc = os_sanity_task_init ( SANITY_TASK_INTERVAL ); assert ( rc == OS_OK );","title":"os_sanity_task_init"},{"location":"os/core_os/sanity/os_sanity_task_init/#os_sanity_task_init","text":"int os_sanity_task_init ( int num_secs ); Initialize the os sanity task. num_secs is the number of seconds to wait in between runs of the sanity task.","title":" os_sanity_task_init"},{"location":"os/core_os/sanity/os_sanity_task_init/#arguments","text":"Arguments Description num_secs Number of seconds to wait in between running sanity checks.","title":"Arguments"},{"location":"os/core_os/sanity/os_sanity_task_init/#returned-values","text":"OS_OK : Sanity task was successfully created. All other error codes indicate an error.","title":"Returned values"},{"location":"os/core_os/sanity/os_sanity_task_init/#example","text":"/* Run sanity checks every 50 seconds */ #define SANITY_TASK_INTERVAL (50) int rc ; rc = os_sanity_task_init ( SANITY_TASK_INTERVAL ); assert ( rc == OS_OK );","title":"Example"},{"location":"os/core_os/sanity/sanity/","text":"Sanity The Sanity task is a software watchdog task, which runs periodically to check system state, and ensure that everything is still operating properly. In a typical system design, there are multiple stages of watchdog: Internal Watchdog External Watchdog Sanity Watchdog The Internal Watchdog is typically an MCU watchdog, which is tickled in the core of the OS. The internal watchdog is tickled frequently, and is meant to be an indicator the OS is running. The External Watchdog is a watchdog that's typically run slower. The purpose of an external watchdog is to provide the system with a hard reset when it has lost its mind. The Sanity Watchdog is the least frequently run watchdog, and is meant as an application watchdog. This document is about the operation of the Mynewt Sanity Watchdog. Description Initializing the Sanity Task The Sanity Watchdog is a task in the Mynewt OS, which when enabled, runs every sanity_seconds . In order to enable the Sanity Watchdog task, call the os_sanity_task_init() function. int os_sanity_task_init ( int sanity_seconds ); By default, every operating system task provides the frequency it will check in with the sanity task, with the sanity_itvl parameter in the os_task_init() function: int os_task_init ( struct os_task *t , char *name , os_task_func_t func , void *arg , uint8_t prio , os_time_t sanity_itvl , os_stack_t *bottom , uint16_t stack_size ); sanity_itvl is the time in OS time ticks that the task being created must register in with the sanity task. Checking in with Sanity Task The task must then register in with the sanity task every sanity_itvl seconds. In order to do that, the task should call the os_sanity_task_checkin function, which will reset the sanity check associated with this task. Here is an example of a task that uses a callout to checkin with the sanity task every 50 seconds: #define TASK1_SANITY_CHECKIN_ITVL (50 * OS_TICKS_PER_SEC) struct os_eventq task1_evq ; static void task1 ( void *arg ) { struct os_task *t ; struct os_event *ev ; struct os_callout c ; /* Get current OS task */ t = os_sched_get_current_task (); /* Initialize the event queue. */ os_eventq_init ( &task1_evq ); /* Initialize the callout */ os_callout_init ( &c , &task1_evq , NULL ); /* reset the callout to checkin with the sanity task * in 50 seconds to kick off timing. */ os_callout_reset ( &c , TASK1_SANITY_CHECKIN_ITVL ); while ( 1 ) { ev = os_eventq_get ( &task1_evq ); /* The sanity timer has reset */ if ( ev->ev_arg == &c ) { os_sanity_task_checkin ( t ); } else { /* not expecting any other events */ assert ( 0 ); } } /* Should never reach */ assert ( 0 ); } Registering a Custom Sanity Check If a particular task wants to further hook into the sanity framework to perform other checks during the sanity task's operation, it can do so by registering a struct os_sanity_check using the os_sanity_check_register function. static int mymodule_perform_sanity_check ( struct os_sanity_check *sc , void *arg ) { /* Perform your checking here. In this case, we check if there * are available buffers in mymodule, and return 0 (all good) * if true, and -1 (error) if not. */ if ( mymodule_has_buffers ()) { return ( 0 ); } else { return ( -1 ); } } static int mymodule_register_sanity_check ( void ) { struct os_sanity_check sc ; os_sanity_check_init ( &sc ); /* Only assert() if mymodule_perform_sanity_check() fails 50 * times. SANITY_TASK_INTERVAL is defined by the user, and * is the frequency at which the sanity_task runs in seconds. */ OS_SANITY_CHECK_SETFUNC ( &sc , mymodule_perform_sanity_check , NULL , 50 * SANITY_TASK_INTERVAL ); rc = os_sanity_check_register ( &sc ); if ( rc != 0 ) { goto err ; } return ( 0 ); err : return ( rc ); } In the above example, every time the custom sanity check mymodule_perform_sanity_check returns successfully (0), the sanity check is reset. In the OS_SANITY_CHECK_SETFUNC macro, the sanity checkin interval is specified as 50 * SANITY_TASK_INTERVAL (which is the interval at which the sanity task runs.) This means that the mymodule_perform_sanity_check() function needs to fail 50 times consecutively before the sanity task will crash the system. TIP: When checking things like memory buffers, which can be temporarily be exhausted, it's a good idea to have the sanity check fail multiple consecutive times before crashing the system. This will avoid crashing for temporary failures. Data structures OS Sanity Check struct os_sanity_check { os_time_t sc_checkin_last ; os_time_t sc_checkin_itvl ; os_sanity_check_func_t sc_func ; void *sc_arg ; SLIST_ENTRY ( os_sanity_check ) sc_next ; }; Element Description sc_checkin_last The last time this sanity check checked in with the sanity task, in OS time ticks. sc_checkin_itvl How frequently the sanity check is supposed to check in with the sanity task, in OS time ticks. sc_func If not NULL , call this function when running the sanity task. If the function returns 0, reset the sanity check. sc_arg Argument to pass to sc_func when calling it. sc_next Sanity checks are chained in the sanity task when os_sanity_check_register() is called. List of Functions The functions available in sanity are: Function Description os_sanity_check_init Initialize the given sanity check. os_sanity_check_register Register the given sanity check with the sanity task. os_sanity_check_reset Reset the given sanity check. os_sanity_task_checkin Informs the sanity task that the given task is still alive and working normally. os_sanity_task_init Initialize the os sanity task.","title":"toc"},{"location":"os/core_os/sanity/sanity/#sanity","text":"The Sanity task is a software watchdog task, which runs periodically to check system state, and ensure that everything is still operating properly. In a typical system design, there are multiple stages of watchdog: Internal Watchdog External Watchdog Sanity Watchdog The Internal Watchdog is typically an MCU watchdog, which is tickled in the core of the OS. The internal watchdog is tickled frequently, and is meant to be an indicator the OS is running. The External Watchdog is a watchdog that's typically run slower. The purpose of an external watchdog is to provide the system with a hard reset when it has lost its mind. The Sanity Watchdog is the least frequently run watchdog, and is meant as an application watchdog. This document is about the operation of the Mynewt Sanity Watchdog.","title":"Sanity"},{"location":"os/core_os/sanity/sanity/#description","text":"","title":"Description"},{"location":"os/core_os/sanity/sanity/#initializing-the-sanity-task","text":"The Sanity Watchdog is a task in the Mynewt OS, which when enabled, runs every sanity_seconds . In order to enable the Sanity Watchdog task, call the os_sanity_task_init() function. int os_sanity_task_init ( int sanity_seconds ); By default, every operating system task provides the frequency it will check in with the sanity task, with the sanity_itvl parameter in the os_task_init() function: int os_task_init ( struct os_task *t , char *name , os_task_func_t func , void *arg , uint8_t prio , os_time_t sanity_itvl , os_stack_t *bottom , uint16_t stack_size ); sanity_itvl is the time in OS time ticks that the task being created must register in with the sanity task.","title":"Initializing the Sanity Task"},{"location":"os/core_os/sanity/sanity/#checking-in-with-sanity-task","text":"The task must then register in with the sanity task every sanity_itvl seconds. In order to do that, the task should call the os_sanity_task_checkin function, which will reset the sanity check associated with this task. Here is an example of a task that uses a callout to checkin with the sanity task every 50 seconds: #define TASK1_SANITY_CHECKIN_ITVL (50 * OS_TICKS_PER_SEC) struct os_eventq task1_evq ; static void task1 ( void *arg ) { struct os_task *t ; struct os_event *ev ; struct os_callout c ; /* Get current OS task */ t = os_sched_get_current_task (); /* Initialize the event queue. */ os_eventq_init ( &task1_evq ); /* Initialize the callout */ os_callout_init ( &c , &task1_evq , NULL ); /* reset the callout to checkin with the sanity task * in 50 seconds to kick off timing. */ os_callout_reset ( &c , TASK1_SANITY_CHECKIN_ITVL ); while ( 1 ) { ev = os_eventq_get ( &task1_evq ); /* The sanity timer has reset */ if ( ev->ev_arg == &c ) { os_sanity_task_checkin ( t ); } else { /* not expecting any other events */ assert ( 0 ); } } /* Should never reach */ assert ( 0 ); }","title":"Checking in with Sanity Task"},{"location":"os/core_os/sanity/sanity/#registering-a-custom-sanity-check","text":"If a particular task wants to further hook into the sanity framework to perform other checks during the sanity task's operation, it can do so by registering a struct os_sanity_check using the os_sanity_check_register function. static int mymodule_perform_sanity_check ( struct os_sanity_check *sc , void *arg ) { /* Perform your checking here. In this case, we check if there * are available buffers in mymodule, and return 0 (all good) * if true, and -1 (error) if not. */ if ( mymodule_has_buffers ()) { return ( 0 ); } else { return ( -1 ); } } static int mymodule_register_sanity_check ( void ) { struct os_sanity_check sc ; os_sanity_check_init ( &sc ); /* Only assert() if mymodule_perform_sanity_check() fails 50 * times. SANITY_TASK_INTERVAL is defined by the user, and * is the frequency at which the sanity_task runs in seconds. */ OS_SANITY_CHECK_SETFUNC ( &sc , mymodule_perform_sanity_check , NULL , 50 * SANITY_TASK_INTERVAL ); rc = os_sanity_check_register ( &sc ); if ( rc != 0 ) { goto err ; } return ( 0 ); err : return ( rc ); } In the above example, every time the custom sanity check mymodule_perform_sanity_check returns successfully (0), the sanity check is reset. In the OS_SANITY_CHECK_SETFUNC macro, the sanity checkin interval is specified as 50 * SANITY_TASK_INTERVAL (which is the interval at which the sanity task runs.) This means that the mymodule_perform_sanity_check() function needs to fail 50 times consecutively before the sanity task will crash the system. TIP: When checking things like memory buffers, which can be temporarily be exhausted, it's a good idea to have the sanity check fail multiple consecutive times before crashing the system. This will avoid crashing for temporary failures.","title":"Registering a Custom Sanity Check"},{"location":"os/core_os/sanity/sanity/#data-structures","text":"","title":"Data structures"},{"location":"os/core_os/sanity/sanity/#os-sanity-check","text":"struct os_sanity_check { os_time_t sc_checkin_last ; os_time_t sc_checkin_itvl ; os_sanity_check_func_t sc_func ; void *sc_arg ; SLIST_ENTRY ( os_sanity_check ) sc_next ; }; Element Description sc_checkin_last The last time this sanity check checked in with the sanity task, in OS time ticks. sc_checkin_itvl How frequently the sanity check is supposed to check in with the sanity task, in OS time ticks. sc_func If not NULL , call this function when running the sanity task. If the function returns 0, reset the sanity check. sc_arg Argument to pass to sc_func when calling it. sc_next Sanity checks are chained in the sanity task when os_sanity_check_register() is called.","title":"OS Sanity Check"},{"location":"os/core_os/sanity/sanity/#list-of-functions","text":"The functions available in sanity are: Function Description os_sanity_check_init Initialize the given sanity check. os_sanity_check_register Register the given sanity check with the sanity task. os_sanity_check_reset Reset the given sanity check. os_sanity_task_checkin Informs the sanity task that the given task is still alive and working normally. os_sanity_task_init Initialize the os sanity task.","title":"List of Functions"},{"location":"os/core_os/semaphore/os_sem_init/","text":"os_sem_init os_error_t os_sem_init ( struct os_sem *sem , uint16_t tokens ) Initialize a semaphore with a given number of tokens. Should be called before the semaphore is used. Arguments Arguments Description *sem Pointer to semaphore tokens Initial number of tokens allocated to semaphore Returned values OS_INVALID_PARM: returned when *sem is NULL on entry. OS_OK: semaphore initialized successfully. Notes Example The following example shows how to initialize a semaphore used for exclusive access. struct os_mutex g_os_sem ; os_error_t err ; err = os_sem_init ( &g_os_sem , 1 ); assert ( err == OS_OK );","title":"os_sem_init"},{"location":"os/core_os/semaphore/os_sem_init/#os_sem_init","text":"os_error_t os_sem_init ( struct os_sem *sem , uint16_t tokens ) Initialize a semaphore with a given number of tokens. Should be called before the semaphore is used.","title":" os_sem_init"},{"location":"os/core_os/semaphore/os_sem_init/#arguments","text":"Arguments Description *sem Pointer to semaphore tokens Initial number of tokens allocated to semaphore","title":"Arguments"},{"location":"os/core_os/semaphore/os_sem_init/#returned-values","text":"OS_INVALID_PARM: returned when *sem is NULL on entry. OS_OK: semaphore initialized successfully.","title":"Returned values"},{"location":"os/core_os/semaphore/os_sem_init/#notes","text":"","title":"Notes"},{"location":"os/core_os/semaphore/os_sem_init/#example","text":"The following example shows how to initialize a semaphore used for exclusive access. struct os_mutex g_os_sem ; os_error_t err ; err = os_sem_init ( &g_os_sem , 1 ); assert ( err == OS_OK );","title":"Example"},{"location":"os/core_os/semaphore/os_sem_pend/","text":"os_sem_pend os_error_t os_sem_pend ( struct os_sem *sem , uint32_t timeout ) Wait for a semaphore for a given amount of time. Arguments Arguments Description *sem Pointer to semaphore timeout Amount of time, in os ticks, to wait for semaphore. A value of 0 means no wait. A value of 0xFFFFFFFF means wait forever. Returned values OS_INVALID_PARM: returned when *sem is NULL on entry. OS_OK: semaphore acquired successfully. OS_TIMEOUT: the semaphore was not available within the timeout specified. OS_NOT_STARTED: Attempt to release a semaphore before os started. Notes If a timeout of 0 is used and the function returns OS_TIMEOUT, the semaphore was not available and was not acquired. No release of the semaphore should occur and the calling task does not own the semaphore. Example struct os_sem g_os_sem ; os_error_t err ; err = os_sem_pend ( &g_os_sem , OS_TIMEOUT_NEVER ); assert ( err == OS_OK ); /* Perform operations requiring semaphore lock */ err = os_sem_release ( &g_os_sem ); assert ( err == OS_OK );","title":"os_sem_pend"},{"location":"os/core_os/semaphore/os_sem_pend/#os_sem_pend","text":"os_error_t os_sem_pend ( struct os_sem *sem , uint32_t timeout ) Wait for a semaphore for a given amount of time.","title":" os_sem_pend "},{"location":"os/core_os/semaphore/os_sem_pend/#arguments","text":"Arguments Description *sem Pointer to semaphore timeout Amount of time, in os ticks, to wait for semaphore. A value of 0 means no wait. A value of 0xFFFFFFFF means wait forever.","title":"Arguments"},{"location":"os/core_os/semaphore/os_sem_pend/#returned-values","text":"OS_INVALID_PARM: returned when *sem is NULL on entry. OS_OK: semaphore acquired successfully. OS_TIMEOUT: the semaphore was not available within the timeout specified. OS_NOT_STARTED: Attempt to release a semaphore before os started.","title":"Returned values"},{"location":"os/core_os/semaphore/os_sem_pend/#notes","text":"If a timeout of 0 is used and the function returns OS_TIMEOUT, the semaphore was not available and was not acquired. No release of the semaphore should occur and the calling task does not own the semaphore.","title":"Notes"},{"location":"os/core_os/semaphore/os_sem_pend/#example","text":"struct os_sem g_os_sem ; os_error_t err ; err = os_sem_pend ( &g_os_sem , OS_TIMEOUT_NEVER ); assert ( err == OS_OK ); /* Perform operations requiring semaphore lock */ err = os_sem_release ( &g_os_sem ); assert ( err == OS_OK );","title":"Example"},{"location":"os/core_os/semaphore/os_sem_release/","text":"os_sem_release os_error_t os_sem_release ( struct os_sem *sem ) Release a semaphore that you are holding. This adds a token to the semaphore. Arguments Arguments Description *sem Pointer to semaphore Returned values OS_NOT_STARTED: Called before os has been started. OS_INVALID_PARM: returned when *sem is NULL on entry. OS_OK: semaphore released successfully. Notes Example struct os_sem g_os_sem ; os_error_t err ; err = os_sem_pend ( &g_os_sem , OS_TIMEOUT_NEVER ); assert ( err == OS_OK ); /* Perform operations requiring semaphore lock */ err = os_sem_release ( &g_os_sem ); assert ( err == OS_OK );","title":"os_sem_release"},{"location":"os/core_os/semaphore/os_sem_release/#os_sem_release","text":"os_error_t os_sem_release ( struct os_sem *sem ) Release a semaphore that you are holding. This adds a token to the semaphore.","title":" os_sem_release "},{"location":"os/core_os/semaphore/os_sem_release/#arguments","text":"Arguments Description *sem Pointer to semaphore","title":"Arguments"},{"location":"os/core_os/semaphore/os_sem_release/#returned-values","text":"OS_NOT_STARTED: Called before os has been started. OS_INVALID_PARM: returned when *sem is NULL on entry. OS_OK: semaphore released successfully.","title":"Returned values"},{"location":"os/core_os/semaphore/os_sem_release/#notes","text":"","title":"Notes"},{"location":"os/core_os/semaphore/os_sem_release/#example","text":"struct os_sem g_os_sem ; os_error_t err ; err = os_sem_pend ( &g_os_sem , OS_TIMEOUT_NEVER ); assert ( err == OS_OK ); /* Perform operations requiring semaphore lock */ err = os_sem_release ( &g_os_sem ); assert ( err == OS_OK );","title":"Example"},{"location":"os/core_os/semaphore/semaphore/","text":"Semaphore A semaphore is a structure used for gaining exclusive access (much like a mutex), synchronizing task operations and/or use in a \"producer/consumer\" roles. Semaphores like the ones used by the myNewt OS are called \"counting\" semaphores as they are allowed to have more than one token (explained below). Description A semaphore is a fairly simple construct consisting of a queue for waiting tasks and the number of tokens currently owned by the semaphore. A semaphore can be obtained as long as there are tokens in the semaphore. Any task can add tokens to the semaphore and any task can request the semaphore, thereby removing tokens. When creating the semaphore, the initial number of tokens can be set as well. When used for exclusive access to a shared resource the semaphore only needs a single token. In this case, a single task \"creates\" the semaphore by calling os_sem_init with a value of one (1) for the token. When a task desires exclusive access to the shared resource it requests the semaphore by calling os_sem_pend . If there is a token the requesting task will acquire the semaphore and continue operation. If no tokens are available the task will be put to sleep until there is a token. A common \"problem\" with using a semaphore for exclusive access is called priority inversion . Consider the following scenario: a high and low priority task both share a resource which is locked using a semaphore. If the low priority task obtains the semaphore and then the high priority task requests the semaphore, the high priority task is now blocked until the low priority task releases the semaphore. Now suppose that there are tasks between the low priority task and the high priority task that want to run. These tasks will preempt the low priority task which owns the semaphore. Thus, the high priority task is blocked waiting for the low priority task to finish using the semaphore but the low priority task cannot run since other tasks are running. Thus, the high priority tasks is \"inverted\" in priority; in effect running at a much lower priority as normally it would preempt the other (lower priority) tasks. If this is an issue a mutex should be used instead of a semaphore. Semaphores can also be used for task synchronization. A simple example of this would be the following. A task creates a semaphore and initializes it with no tokens. The task then waits on the semaphore, and since there are no tokens, the task is put to sleep. When other tasks want to wake up the sleeping task they simply add a token by calling os_sem_release . This will cause the sleeping task to wake up (instantly if no other higher priority tasks want to run). The other common use of a counting semaphore is in what is commonly called a \"producer/consumer\" relationship. The producer adds tokens (by calling os_sem_release ) and the consumer consumes them by calling os_sem_pend . In this relationship, the producer has work for the consumer to do. Each token added to the semaphore will cause the consumer to do whatever work is required. A simple example could be the following: every time a button is pressed there is some work to do (ring a bell). Each button press causes the producer to add a token. Each token consumed rings the bell. There will exactly the same number of bell rings as there are button presses. In other words, each call to os_sem_pend subtracts exactly one token and each call to os_sem_release adds exactly one token. Data structures struct os_sem { SLIST_HEAD (, os_task ) sem_head ; /* chain of waiting tasks */ uint16_t _pad ; uint16_t sem_tokens ; /* # of tokens */ }; Element Description sem_head Queue head for list of tasks waiting on semaphore _pad Padding for alignment sem_tokens Current number of tokens List of Functions The functions available in semaphore are: Function Description os_sem_init Initialize a semaphore with a given number of tokens. os_sem_pend Wait for a semaphore for a given amount of time. os_sem_release Release a semaphore that you are holding. This adds a token to the semaphore.","title":"toc"},{"location":"os/core_os/semaphore/semaphore/#semaphore","text":"A semaphore is a structure used for gaining exclusive access (much like a mutex), synchronizing task operations and/or use in a \"producer/consumer\" roles. Semaphores like the ones used by the myNewt OS are called \"counting\" semaphores as they are allowed to have more than one token (explained below).","title":"Semaphore"},{"location":"os/core_os/semaphore/semaphore/#description","text":"A semaphore is a fairly simple construct consisting of a queue for waiting tasks and the number of tokens currently owned by the semaphore. A semaphore can be obtained as long as there are tokens in the semaphore. Any task can add tokens to the semaphore and any task can request the semaphore, thereby removing tokens. When creating the semaphore, the initial number of tokens can be set as well. When used for exclusive access to a shared resource the semaphore only needs a single token. In this case, a single task \"creates\" the semaphore by calling os_sem_init with a value of one (1) for the token. When a task desires exclusive access to the shared resource it requests the semaphore by calling os_sem_pend . If there is a token the requesting task will acquire the semaphore and continue operation. If no tokens are available the task will be put to sleep until there is a token. A common \"problem\" with using a semaphore for exclusive access is called priority inversion . Consider the following scenario: a high and low priority task both share a resource which is locked using a semaphore. If the low priority task obtains the semaphore and then the high priority task requests the semaphore, the high priority task is now blocked until the low priority task releases the semaphore. Now suppose that there are tasks between the low priority task and the high priority task that want to run. These tasks will preempt the low priority task which owns the semaphore. Thus, the high priority task is blocked waiting for the low priority task to finish using the semaphore but the low priority task cannot run since other tasks are running. Thus, the high priority tasks is \"inverted\" in priority; in effect running at a much lower priority as normally it would preempt the other (lower priority) tasks. If this is an issue a mutex should be used instead of a semaphore. Semaphores can also be used for task synchronization. A simple example of this would be the following. A task creates a semaphore and initializes it with no tokens. The task then waits on the semaphore, and since there are no tokens, the task is put to sleep. When other tasks want to wake up the sleeping task they simply add a token by calling os_sem_release . This will cause the sleeping task to wake up (instantly if no other higher priority tasks want to run). The other common use of a counting semaphore is in what is commonly called a \"producer/consumer\" relationship. The producer adds tokens (by calling os_sem_release ) and the consumer consumes them by calling os_sem_pend . In this relationship, the producer has work for the consumer to do. Each token added to the semaphore will cause the consumer to do whatever work is required. A simple example could be the following: every time a button is pressed there is some work to do (ring a bell). Each button press causes the producer to add a token. Each token consumed rings the bell. There will exactly the same number of bell rings as there are button presses. In other words, each call to os_sem_pend subtracts exactly one token and each call to os_sem_release adds exactly one token.","title":"Description"},{"location":"os/core_os/semaphore/semaphore/#data-structures","text":"struct os_sem { SLIST_HEAD (, os_task ) sem_head ; /* chain of waiting tasks */ uint16_t _pad ; uint16_t sem_tokens ; /* # of tokens */ }; Element Description sem_head Queue head for list of tasks waiting on semaphore _pad Padding for alignment sem_tokens Current number of tokens","title":"Data structures"},{"location":"os/core_os/semaphore/semaphore/#list-of-functions","text":"The functions available in semaphore are: Function Description os_sem_init Initialize a semaphore with a given number of tokens. os_sem_pend Wait for a semaphore for a given amount of time. os_sem_release Release a semaphore that you are holding. This adds a token to the semaphore.","title":"List of Functions"},{"location":"os/core_os/task/os_task_count/","text":"os_task_count uint8_t os_task_count ( void ); Returns the number of tasks that have been created. Arguments None Returned values unsigned 8-bit integer representing number of tasks created Example uint8_t num_tasks ; num_tasks = os_task_count ();","title":"os_task_count"},{"location":"os/core_os/task/os_task_count/#os_task_count","text":"uint8_t os_task_count ( void ); Returns the number of tasks that have been created.","title":" os_task_count"},{"location":"os/core_os/task/os_task_count/#arguments","text":"None","title":"Arguments"},{"location":"os/core_os/task/os_task_count/#returned-values","text":"unsigned 8-bit integer representing number of tasks created","title":"Returned values"},{"location":"os/core_os/task/os_task_count/#example","text":"uint8_t num_tasks ; num_tasks = os_task_count ();","title":"Example"},{"location":"os/core_os/task/os_task_info_get_next/","text":"os_task_info_get_next struct os_task *os_task_info_get_next ( const struct os_task *prev , struct os_task_info *oti ); Populates the os task info structure pointed to by oti with task information. The task populating the oti structure is either the first task on the task list if prev is NULL, or the next task in the task list (the next pointer of prev ). If there are no tasks initialized, NULL is returned. Otherwise, the task structure used to populate oti is returned. Arguments Arguments Description prev Pointer to previous task in task list. If NULL, use first task on list oti Pointer to os_task_info structure where task information will be stored Returned values Returns a pointer to the os task structure that was used to populate the task information structure. NULL means that no tasks were created. Example void get_task_info ( void ) { struct os_task *prev_task ; struct os_task_info oti ; console_printf ( \"Tasks: \\n\" ); prev_task = NULL ; while ( 1 ) { prev_task = os_task_info_get_next ( prev_task , &oti ); if ( prev_task == NULL ) { break ; } console_printf ( \" %s (prio: %u, tid: %u, lcheck: %lu, ncheck: %lu, \" \"flags: 0x%x, ssize: %u, susage: %u, cswcnt: %lu, \" \"tot_run_time: %lums)\\n\" , oti . oti_name , oti . oti_prio , oti . oti_taskid , ( unsigned long ) oti . oti_last_checkin , ( unsigned long ) oti . oti_next_checkin , oti . oti_flags , oti . oti_stksize , oti . oti_stkusage , ( unsigned long ) oti . oti_cswcnt , ( unsigned long ) oti . oti_runtime ); } }","title":"os_task_info_get_next"},{"location":"os/core_os/task/os_task_info_get_next/#os_task_info_get_next","text":"struct os_task *os_task_info_get_next ( const struct os_task *prev , struct os_task_info *oti ); Populates the os task info structure pointed to by oti with task information. The task populating the oti structure is either the first task on the task list if prev is NULL, or the next task in the task list (the next pointer of prev ). If there are no tasks initialized, NULL is returned. Otherwise, the task structure used to populate oti is returned.","title":" os_task_info_get_next"},{"location":"os/core_os/task/os_task_info_get_next/#arguments","text":"Arguments Description prev Pointer to previous task in task list. If NULL, use first task on list oti Pointer to os_task_info structure where task information will be stored","title":"Arguments"},{"location":"os/core_os/task/os_task_info_get_next/#returned-values","text":"Returns a pointer to the os task structure that was used to populate the task information structure. NULL means that no tasks were created.","title":"Returned values"},{"location":"os/core_os/task/os_task_info_get_next/#example","text":"void get_task_info ( void ) { struct os_task *prev_task ; struct os_task_info oti ; console_printf ( \"Tasks: \\n\" ); prev_task = NULL ; while ( 1 ) { prev_task = os_task_info_get_next ( prev_task , &oti ); if ( prev_task == NULL ) { break ; } console_printf ( \" %s (prio: %u, tid: %u, lcheck: %lu, ncheck: %lu, \" \"flags: 0x%x, ssize: %u, susage: %u, cswcnt: %lu, \" \"tot_run_time: %lums)\\n\" , oti . oti_name , oti . oti_prio , oti . oti_taskid , ( unsigned long ) oti . oti_last_checkin , ( unsigned long ) oti . oti_next_checkin , oti . oti_flags , oti . oti_stksize , oti . oti_stkusage , ( unsigned long ) oti . oti_cswcnt , ( unsigned long ) oti . oti_runtime ); } }","title":"Example"},{"location":"os/core_os/task/os_task_init/","text":"os_task_init int os_task_init ( struct os_task *t , char *name , os_task_func_t func , void *arg , uint8_t prio , os_time_t sanity_itvl , os_stack_t *stack_bottom , uint16_t stack_size ) Called to create a task. This adds the task object to the list of ready to run tasks. Arguments Arguments Description t Pointer to task name Task name func Task function arg Generic argument to pass to task prio Priority of task sanity_itvl The interval at which the sanity task will check to see if this task is sill alive stack_bottom Pointer to bottom of stack. stack_size The size of the stack. NOTE: this is not in bytes! It is the number of os_stack_t elements allocated (generally 32-bits each) Returned values OS_OK: task initialization successful. All other error codes indicate an internal error. Example /* Create the task */ int rc ; os_stack_t my_task_stack [ MY_STACK_SIZE ]; rc = os_task_init ( &my_task , \"my_task\" , my_task_func , NULL , MY_TASK_PRIO , OS_WAIT_FOREVER , my_task_stack , MY_STACK_SIZE ); assert ( rc == OS_OK );","title":"os_task_init"},{"location":"os/core_os/task/os_task_init/#os_task_init","text":"int os_task_init ( struct os_task *t , char *name , os_task_func_t func , void *arg , uint8_t prio , os_time_t sanity_itvl , os_stack_t *stack_bottom , uint16_t stack_size ) Called to create a task. This adds the task object to the list of ready to run tasks.","title":" os_task_init"},{"location":"os/core_os/task/os_task_init/#arguments","text":"Arguments Description t Pointer to task name Task name func Task function arg Generic argument to pass to task prio Priority of task sanity_itvl The interval at which the sanity task will check to see if this task is sill alive stack_bottom Pointer to bottom of stack. stack_size The size of the stack. NOTE: this is not in bytes! It is the number of os_stack_t elements allocated (generally 32-bits each)","title":"Arguments"},{"location":"os/core_os/task/os_task_init/#returned-values","text":"OS_OK: task initialization successful. All other error codes indicate an internal error.","title":"Returned values"},{"location":"os/core_os/task/os_task_init/#example","text":"/* Create the task */ int rc ; os_stack_t my_task_stack [ MY_STACK_SIZE ]; rc = os_task_init ( &my_task , \"my_task\" , my_task_func , NULL , MY_TASK_PRIO , OS_WAIT_FOREVER , my_task_stack , MY_STACK_SIZE ); assert ( rc == OS_OK );","title":"Example"},{"location":"os/core_os/task/task/","text":"Task A task, along with the scheduler, forms the basis of the Mynewt OS. A task consists of two basic elements: a task stack and a task function. The task function is basically a forever loop, waiting for some \"event\" to wake it up. There are two methods used to signal a task that it has work to do: event queues and semaphores (see the appropriate manual sections for descriptions of these features). The Mynewt OS is a multi-tasking, preemptive OS. Every task is assigned a task priority (from 0 to 255), with 0 being the highest priority task. If a higher priority task than the current task wants to run, the scheduler preempts the currently running task and switches context to the higher priority task. This is just a fancy way of saying that the processor stack pointer now points to the stack of the higher priority task and the task resumes execution where it left off. Tasks run to completion unless they are preempted by a higher priority task. The developer must insure that tasks eventually \"sleep\"; otherwise lower priority tasks will never get a chance to run (actually, any task lower in priority than the task that never sleeps). A task will be put to sleep in the following cases: it puts itself to sleep using os_time_delay() , it waits on an event queue which is empty or attempts to obtain a mutex or a semaphore that is currently owned by another task. Note that other sections of the manual describe these OS features in more detail. Description In order to create a task two data structures need to be defined: the task object (struct os_task) and its associated stack. Determining the stack size can be a bit tricky; generally developers should not declare large local variables on the stack so that task stacks can be of limited size. However, all applications are different and the developer must choose the stack size accordingly. NOTE: be careful when declaring your stack! The stack is in units of os_stack_t sized elements (generally 32-bits). Looking at the example given below and assuming os_stack_t is defined to be a 32-bit unsigned value, \"my_task_stack\" will use 256 bytes. A task must also have an associated \"task function\". This is the function that will be called when the task is first run. This task function should never return! In order to inform the Mynewt OS of the new task and to have it added to the scheduler, the os_task_init() function is called. Once os_task_init() is called, the task is made ready to run and is added to the active task list. Note that a task can be initialized (started) before or after the os has started (i.e. before os_start() is called) but must be initialized after the os has been initialized (i.e. 'os_init' has been called). In most of the examples and current Mynewt projects, the os is initialized, tasks are initialized, and the the os is started. Once the os has started, the highest priority task will be the first task set to run. Information about a task can be obtained using the os_task_info_get_next() API. Developers can walk the list of tasks to obtain information on all created tasks. This information is of type os_task_info and is described below. The following is a very simple example showing a single application task. This task simply toggles an LED at a one second interval. /* Create a simple \"project\" with a task that blinks a LED every second */ /* Define task stack and task object */ #define MY_TASK_PRI (OS_TASK_PRI_HIGHEST) #define MY_STACK_SIZE (64) struct os_task my_task ; os_stack_t my_task_stack [ MY_STACK_SIZE ]; /* This is the task function */ void my_task_func ( void *arg ) { /* Set the led pin as an output */ hal_gpio_init_out ( LED_BLINK_PIN , 1 ); /* The task is a forever loop that does not return */ while ( 1 ) { /* Wait one second */ os_time_delay ( 1000 ); /* Toggle the LED */ hal_gpio_toggle ( LED_BLINK_PIN ); } } /* This is the main function for the project */ int main ( void ) { int rc ; /* Initialize OS */ os_init (); /* Initialize the task */ os_task_init ( &my_task , \"my_task\" , my_task_func , NULL , MY_TASK_PRIO , OS_WAIT_FOREVER , my_task_stack , MY_STACK_SIZE ); /* Start the OS */ os_start (); /* os start should never return. If it does, this should be an error */ assert ( 0 ); return rc ; } Data structures /* The highest and lowest task priorities */ #define OS_TASK_PRI_HIGHEST (0) #define OS_TASK_PRI_LOWEST (0xff) /* Task states */ typedef enum os_task_state { OS_TASK_READY = 1 , OS_TASK_SLEEP = 2 } os_task_state_t ; /* Task flags */ #define OS_TASK_FLAG_NO_TIMEOUT (0x0001U) #define OS_TASK_FLAG_SEM_WAIT (0x0002U) #define OS_TASK_FLAG_MUTEX_WAIT (0x0004U) typedef void ( *os_task_func_t )( void * ); #define OS_TASK_MAX_NAME_LEN (32) struct os_task { os_stack_t *t_stackptr ; os_stack_t *t_stacktop ; uint16_t t_stacksize ; uint16_t t_flags ; uint8_t t_taskid ; uint8_t t_prio ; uint8_t t_state ; uint8_t t_pad ; char *t_name ; os_task_func_t t_func ; void *t_arg ; void *t_obj ; struct os_sanity_check t_sanity_check ; os_time_t t_next_wakeup ; os_time_t t_run_time ; uint32_t t_ctx_sw_cnt ; /* Global list of all tasks, irrespective of run or sleep lists */ STAILQ_ENTRY ( os_task ) t_os_task_list ; /* Used to chain task to either the run or sleep list */ TAILQ_ENTRY ( os_task ) t_os_list ; /* Used to chain task to an object such as a semaphore or mutex */ SLIST_ENTRY ( os_task ) t_obj_list ; }; Element Description t_stackptr Current stack pointer t_stacktop The address of the top of the task stack. The stack grows downward t_stacksize The size of the stack, in units of os_stack_t (not bytes!) t_flags Task flags (see flag definitions) t_taskid A numeric id assigned to each task t_prio The priority of the task. The lower the number, the higher the priority t_state The task state (see state definitions) t_pad padding (for alignment) t_name Name of task t_func Pointer to task function t_obj Generic object used by mutexes and semaphores when the task is waiting on a mutex or semaphore t_sanity_check Sanity task data structure t_next_wakeup OS time when task is next scheduled to wake up t_run_time The amount of os time ticks this task has been running t_ctx_sw_cnt The number of times that this task has been run t_os_task_list List pointer for global task list. All tasks are placed on this list t_os_list List pointer used by either the active task list or the sleeping task list t_obj_list List pointer for tasks waiting on a semaphore or mutex struct os_task_info { uint8_t oti_prio ; uint8_t oti_taskid ; uint8_t oti_state ; uint8_t oti_flags ; uint16_t oti_stkusage ; uint16_t oti_stksize ; uint32_t oti_cswcnt ; uint32_t oti_runtime ; os_time_t oti_last_checkin ; os_time_t oti_next_checkin ; char oti_name [ OS_TASK_MAX_NAME_LEN ]; }; Element Description oti_prio Task priority oti_taskid Task id oti_state Task state oti_flags Task flags oti_stkusage Amount of stack used by the task (in os_stack_t units) oti_stksize The size of the stack (in os_stack_t units) oti_cswcnt The context switch count oti_runtime The amount of time that the task has run (in os time ticks) oti_last_checkin The time (os time) at which this task last checked in to the sanity task oti_next_checkin The time (os time) at which this task last checked in to the sanity task oti_name Name of the task List of Functions The functions available in task are: Function Description os_task_init Called to create a task. This adds the task object to the list of ready to run tasks. os_task_count Returns the number of tasks that have been created. os_task_info_get_next Populates the os task info structure given with task information.","title":"toc"},{"location":"os/core_os/task/task/#task","text":"A task, along with the scheduler, forms the basis of the Mynewt OS. A task consists of two basic elements: a task stack and a task function. The task function is basically a forever loop, waiting for some \"event\" to wake it up. There are two methods used to signal a task that it has work to do: event queues and semaphores (see the appropriate manual sections for descriptions of these features). The Mynewt OS is a multi-tasking, preemptive OS. Every task is assigned a task priority (from 0 to 255), with 0 being the highest priority task. If a higher priority task than the current task wants to run, the scheduler preempts the currently running task and switches context to the higher priority task. This is just a fancy way of saying that the processor stack pointer now points to the stack of the higher priority task and the task resumes execution where it left off. Tasks run to completion unless they are preempted by a higher priority task. The developer must insure that tasks eventually \"sleep\"; otherwise lower priority tasks will never get a chance to run (actually, any task lower in priority than the task that never sleeps). A task will be put to sleep in the following cases: it puts itself to sleep using os_time_delay() , it waits on an event queue which is empty or attempts to obtain a mutex or a semaphore that is currently owned by another task. Note that other sections of the manual describe these OS features in more detail.","title":"Task"},{"location":"os/core_os/task/task/#description","text":"In order to create a task two data structures need to be defined: the task object (struct os_task) and its associated stack. Determining the stack size can be a bit tricky; generally developers should not declare large local variables on the stack so that task stacks can be of limited size. However, all applications are different and the developer must choose the stack size accordingly. NOTE: be careful when declaring your stack! The stack is in units of os_stack_t sized elements (generally 32-bits). Looking at the example given below and assuming os_stack_t is defined to be a 32-bit unsigned value, \"my_task_stack\" will use 256 bytes. A task must also have an associated \"task function\". This is the function that will be called when the task is first run. This task function should never return! In order to inform the Mynewt OS of the new task and to have it added to the scheduler, the os_task_init() function is called. Once os_task_init() is called, the task is made ready to run and is added to the active task list. Note that a task can be initialized (started) before or after the os has started (i.e. before os_start() is called) but must be initialized after the os has been initialized (i.e. 'os_init' has been called). In most of the examples and current Mynewt projects, the os is initialized, tasks are initialized, and the the os is started. Once the os has started, the highest priority task will be the first task set to run. Information about a task can be obtained using the os_task_info_get_next() API. Developers can walk the list of tasks to obtain information on all created tasks. This information is of type os_task_info and is described below. The following is a very simple example showing a single application task. This task simply toggles an LED at a one second interval. /* Create a simple \"project\" with a task that blinks a LED every second */ /* Define task stack and task object */ #define MY_TASK_PRI (OS_TASK_PRI_HIGHEST) #define MY_STACK_SIZE (64) struct os_task my_task ; os_stack_t my_task_stack [ MY_STACK_SIZE ]; /* This is the task function */ void my_task_func ( void *arg ) { /* Set the led pin as an output */ hal_gpio_init_out ( LED_BLINK_PIN , 1 ); /* The task is a forever loop that does not return */ while ( 1 ) { /* Wait one second */ os_time_delay ( 1000 ); /* Toggle the LED */ hal_gpio_toggle ( LED_BLINK_PIN ); } } /* This is the main function for the project */ int main ( void ) { int rc ; /* Initialize OS */ os_init (); /* Initialize the task */ os_task_init ( &my_task , \"my_task\" , my_task_func , NULL , MY_TASK_PRIO , OS_WAIT_FOREVER , my_task_stack , MY_STACK_SIZE ); /* Start the OS */ os_start (); /* os start should never return. If it does, this should be an error */ assert ( 0 ); return rc ; }","title":"Description"},{"location":"os/core_os/task/task/#data-structures","text":"/* The highest and lowest task priorities */ #define OS_TASK_PRI_HIGHEST (0) #define OS_TASK_PRI_LOWEST (0xff) /* Task states */ typedef enum os_task_state { OS_TASK_READY = 1 , OS_TASK_SLEEP = 2 } os_task_state_t ; /* Task flags */ #define OS_TASK_FLAG_NO_TIMEOUT (0x0001U) #define OS_TASK_FLAG_SEM_WAIT (0x0002U) #define OS_TASK_FLAG_MUTEX_WAIT (0x0004U) typedef void ( *os_task_func_t )( void * ); #define OS_TASK_MAX_NAME_LEN (32) struct os_task { os_stack_t *t_stackptr ; os_stack_t *t_stacktop ; uint16_t t_stacksize ; uint16_t t_flags ; uint8_t t_taskid ; uint8_t t_prio ; uint8_t t_state ; uint8_t t_pad ; char *t_name ; os_task_func_t t_func ; void *t_arg ; void *t_obj ; struct os_sanity_check t_sanity_check ; os_time_t t_next_wakeup ; os_time_t t_run_time ; uint32_t t_ctx_sw_cnt ; /* Global list of all tasks, irrespective of run or sleep lists */ STAILQ_ENTRY ( os_task ) t_os_task_list ; /* Used to chain task to either the run or sleep list */ TAILQ_ENTRY ( os_task ) t_os_list ; /* Used to chain task to an object such as a semaphore or mutex */ SLIST_ENTRY ( os_task ) t_obj_list ; }; Element Description t_stackptr Current stack pointer t_stacktop The address of the top of the task stack. The stack grows downward t_stacksize The size of the stack, in units of os_stack_t (not bytes!) t_flags Task flags (see flag definitions) t_taskid A numeric id assigned to each task t_prio The priority of the task. The lower the number, the higher the priority t_state The task state (see state definitions) t_pad padding (for alignment) t_name Name of task t_func Pointer to task function t_obj Generic object used by mutexes and semaphores when the task is waiting on a mutex or semaphore t_sanity_check Sanity task data structure t_next_wakeup OS time when task is next scheduled to wake up t_run_time The amount of os time ticks this task has been running t_ctx_sw_cnt The number of times that this task has been run t_os_task_list List pointer for global task list. All tasks are placed on this list t_os_list List pointer used by either the active task list or the sleeping task list t_obj_list List pointer for tasks waiting on a semaphore or mutex struct os_task_info { uint8_t oti_prio ; uint8_t oti_taskid ; uint8_t oti_state ; uint8_t oti_flags ; uint16_t oti_stkusage ; uint16_t oti_stksize ; uint32_t oti_cswcnt ; uint32_t oti_runtime ; os_time_t oti_last_checkin ; os_time_t oti_next_checkin ; char oti_name [ OS_TASK_MAX_NAME_LEN ]; }; Element Description oti_prio Task priority oti_taskid Task id oti_state Task state oti_flags Task flags oti_stkusage Amount of stack used by the task (in os_stack_t units) oti_stksize The size of the stack (in os_stack_t units) oti_cswcnt The context switch count oti_runtime The amount of time that the task has run (in os time ticks) oti_last_checkin The time (os time) at which this task last checked in to the sanity task oti_next_checkin The time (os time) at which this task last checked in to the sanity task oti_name Name of the task","title":"Data structures"},{"location":"os/core_os/task/task/#list-of-functions","text":"The functions available in task are: Function Description os_task_init Called to create a task. This adds the task object to the list of ready to run tasks. os_task_count Returns the number of tasks that have been created. os_task_info_get_next Populates the os task info structure given with task information.","title":"List of Functions"},{"location":"os/core_os/time/os_gettimeofday/","text":"os_gettimeofday int os_gettimeofday ( struct os_timeval *utctime , struct os_timezone *timezone ); Arguments Arguments Description utctime UTC time corresponding to wallclock time timezone Timezone to convert UTC time to wallclock time Returned values Returns 0 on success and non-zero on failure. Notes utctime or timezone may be NULL. The function is a no-op if both utctime and timezone are NULL. Example /* * Display wallclock time on the console. */ int rc ; struct os_timeval utc ; struct os_timezone tz ; char buf [ DATETIME_BUFSIZE ]; rc = os_gettimeofday ( &utc , &tz ); if ( rc == 0 ) { format_datetime ( &utc , &tz , buf , sizeof ( buf )); console_printf ( \"%s\\n\" , buf ); }","title":"os_gettimeofday"},{"location":"os/core_os/time/os_gettimeofday/#os_gettimeofday","text":"int os_gettimeofday ( struct os_timeval *utctime , struct os_timezone *timezone );","title":"os_gettimeofday"},{"location":"os/core_os/time/os_gettimeofday/#arguments","text":"Arguments Description utctime UTC time corresponding to wallclock time timezone Timezone to convert UTC time to wallclock time","title":"Arguments"},{"location":"os/core_os/time/os_gettimeofday/#returned-values","text":"Returns 0 on success and non-zero on failure.","title":"Returned values"},{"location":"os/core_os/time/os_gettimeofday/#notes","text":"utctime or timezone may be NULL. The function is a no-op if both utctime and timezone are NULL.","title":"Notes"},{"location":"os/core_os/time/os_gettimeofday/#example","text":"/* * Display wallclock time on the console. */ int rc ; struct os_timeval utc ; struct os_timezone tz ; char buf [ DATETIME_BUFSIZE ]; rc = os_gettimeofday ( &utc , &tz ); if ( rc == 0 ) { format_datetime ( &utc , &tz , buf , sizeof ( buf )); console_printf ( \"%s\\n\" , buf ); }","title":"Example"},{"location":"os/core_os/time/os_settimeofday/","text":"os_settimeofday int os_settimeofday ( struct os_timeval *utctime , struct os_timezone *timezone ); Arguments Arguments Description utctime UTC time corresponding to the wallclock time timezone Timezone associated with the wallclock time Returned values Returns 0 on success and non-zero on failure. Notes utctime may be NULL if only the timezone needs to be changed. This is useful when adjusting the timezone to account for daylight savings. timezone may be NULL if only the UTC time needs to be changed. This is useful when synchronizing Mynewt's time with an external time source like NTP. The function is a no-op if both utctime and timezone are NULL. Example int rc ; parse_datetime ( datestr , &utctime , &tz ); rc = os_settimeofday ( &utctime , &tz ); if ( rc == 0 ) { /* success */ }","title":"os_settimeofday"},{"location":"os/core_os/time/os_settimeofday/#os_settimeofday","text":"int os_settimeofday ( struct os_timeval *utctime , struct os_timezone *timezone );","title":"os_settimeofday"},{"location":"os/core_os/time/os_settimeofday/#arguments","text":"Arguments Description utctime UTC time corresponding to the wallclock time timezone Timezone associated with the wallclock time","title":"Arguments"},{"location":"os/core_os/time/os_settimeofday/#returned-values","text":"Returns 0 on success and non-zero on failure.","title":"Returned values"},{"location":"os/core_os/time/os_settimeofday/#notes","text":"utctime may be NULL if only the timezone needs to be changed. This is useful when adjusting the timezone to account for daylight savings. timezone may be NULL if only the UTC time needs to be changed. This is useful when synchronizing Mynewt's time with an external time source like NTP. The function is a no-op if both utctime and timezone are NULL.","title":"Notes"},{"location":"os/core_os/time/os_settimeofday/#example","text":"int rc ; parse_datetime ( datestr , &utctime , &tz ); rc = os_settimeofday ( &utctime , &tz ); if ( rc == 0 ) { /* success */ }","title":"Example"},{"location":"os/core_os/time/os_time/","text":"OS_Time The system time for the Mynewt OS. Description The Mynewt OS contains an incrementing time that drives the OS scheduler and time delays. The time is a fixed size (e.g. 32 bits) and will eventually wrap back to zero. The time to wrap from zero back to zero is called the OS time epoch . The frequency of the OS time tick is specified in the architecture-specific OS code os_arch.h and is named OS_TICKS_PER_SEC . The Mynewt OS also provides APIs for setting and retrieving the wallclock time (also known as local time or time-of-day in other operating systems). Data Structures Time is stored in Mynewt as an os_time_t value. Wallclock time is represented using the struct os_timeval and struct os_timezone tuple. struct os_timeval represents the number of seconds elapsed since 00:00:00 Jan 1, 1970 UTC. struct os_timeval { int64_t tv_sec; /* seconds since Jan 1 1970 UTC */ int32_t tv_usec; /* fractional seconds */ }; struct os_timeval tv = { 1457400000, 0 }; /* 01:20:00 Mar 8 2016 UTC */ struct os_timezone is used to specify the offset of local time from UTC and whether daylight savings is in effect. Note that tz_minuteswest is a positive number if the local time is behind UTC and a negative number if the local time is ahead of UTC. struct os_timezone { int16_t tz_minuteswest; int16_t tz_dsttime; }; /* Pacific Standard Time is 08:00 hours west of UTC */ struct os_timezone PST = { 480, 0 }; struct os_timezone PDT = { 480, 1 }; /* Indian Standard Time is 05:30 hours east of UTC */ struct os_timezone IST = { -330, 0 }; List of Functions The functions available in time are: Function Description os_time_delay Put the current task to sleep for the given number of ticks. os_time_get Get the current value of OS time. os_time_tick Increments the OS time tick for the system. os_settimeofday Set the current time of day to the given time structs. os_gettimeofday Populate the given timeval and timezone structs with current time data. List of Macros Several macros help with the evalution of times with respect to each other. OS_TIME_TICK_LT(t1,t2) -- evaluates to true if t1 is before t2 in time. OS_TIME_TICK_GT(t1,t2) -- evaluates to true if t1 is after t2 in time OS_TIME_TICK_GEQ(t1,t2) -- evaluates to true if t1 is on or after t2 in time. NOTE: For all of these macros the calculations are done modulo 'os_time_t'. Ensure that comparison of OS time always uses the macros above (to compensate for the possible wrap of OS time). The following macros help adding or subtracting time when represented as struct os_timeval . All parameters to the following macros are pointers to struct os_timeval . os_timeradd(tvp, uvp, vvp) -- Add uvp to tvp and store result in vvp . os_timersub(tvp, uvp, vvp) -- Subtract uvp from tvp and store result in vvp . Special Notes Its important to understand how quickly the time wraps especially when doing time comparison using the macros above (or by any other means). For example, if a tick is 1 millisecond and os_time_t is 32-bits the OS time will wrap back to zero in about 49.7 days or stated another way, the OS time epoch is 49.7 days. If two times are more than 1/2 the OS time epoch apart, any time comparison will be incorrect. Ensure at design time that comparisons will not occur between times that are more than half the OS time epoch.","title":"toc"},{"location":"os/core_os/time/os_time/#os_time","text":"The system time for the Mynewt OS.","title":"OS_Time"},{"location":"os/core_os/time/os_time/#description","text":"The Mynewt OS contains an incrementing time that drives the OS scheduler and time delays. The time is a fixed size (e.g. 32 bits) and will eventually wrap back to zero. The time to wrap from zero back to zero is called the OS time epoch . The frequency of the OS time tick is specified in the architecture-specific OS code os_arch.h and is named OS_TICKS_PER_SEC . The Mynewt OS also provides APIs for setting and retrieving the wallclock time (also known as local time or time-of-day in other operating systems).","title":"Description"},{"location":"os/core_os/time/os_time/#data-structures","text":"Time is stored in Mynewt as an os_time_t value. Wallclock time is represented using the struct os_timeval and struct os_timezone tuple. struct os_timeval represents the number of seconds elapsed since 00:00:00 Jan 1, 1970 UTC. struct os_timeval { int64_t tv_sec; /* seconds since Jan 1 1970 UTC */ int32_t tv_usec; /* fractional seconds */ }; struct os_timeval tv = { 1457400000, 0 }; /* 01:20:00 Mar 8 2016 UTC */ struct os_timezone is used to specify the offset of local time from UTC and whether daylight savings is in effect. Note that tz_minuteswest is a positive number if the local time is behind UTC and a negative number if the local time is ahead of UTC. struct os_timezone { int16_t tz_minuteswest; int16_t tz_dsttime; }; /* Pacific Standard Time is 08:00 hours west of UTC */ struct os_timezone PST = { 480, 0 }; struct os_timezone PDT = { 480, 1 }; /* Indian Standard Time is 05:30 hours east of UTC */ struct os_timezone IST = { -330, 0 };","title":"Data Structures"},{"location":"os/core_os/time/os_time/#list-of-functions","text":"The functions available in time are: Function Description os_time_delay Put the current task to sleep for the given number of ticks. os_time_get Get the current value of OS time. os_time_tick Increments the OS time tick for the system. os_settimeofday Set the current time of day to the given time structs. os_gettimeofday Populate the given timeval and timezone structs with current time data.","title":"List of Functions"},{"location":"os/core_os/time/os_time/#list-of-macros","text":"Several macros help with the evalution of times with respect to each other. OS_TIME_TICK_LT(t1,t2) -- evaluates to true if t1 is before t2 in time. OS_TIME_TICK_GT(t1,t2) -- evaluates to true if t1 is after t2 in time OS_TIME_TICK_GEQ(t1,t2) -- evaluates to true if t1 is on or after t2 in time. NOTE: For all of these macros the calculations are done modulo 'os_time_t'. Ensure that comparison of OS time always uses the macros above (to compensate for the possible wrap of OS time). The following macros help adding or subtracting time when represented as struct os_timeval . All parameters to the following macros are pointers to struct os_timeval . os_timeradd(tvp, uvp, vvp) -- Add uvp to tvp and store result in vvp . os_timersub(tvp, uvp, vvp) -- Subtract uvp from tvp and store result in vvp .","title":"List of Macros"},{"location":"os/core_os/time/os_time/#special-notes","text":"Its important to understand how quickly the time wraps especially when doing time comparison using the macros above (or by any other means). For example, if a tick is 1 millisecond and os_time_t is 32-bits the OS time will wrap back to zero in about 49.7 days or stated another way, the OS time epoch is 49.7 days. If two times are more than 1/2 the OS time epoch apart, any time comparison will be incorrect. Ensure at design time that comparisons will not occur between times that are more than half the OS time epoch.","title":"Special Notes"},{"location":"os/core_os/time/os_time_delay/","text":"os_time_delay void os_time_delay ( int32_t ticks ) Arguments Arguments Description ticks Number of ticks to delay. Less than or equal to zero means no delay Returned values N/A Notes Passing OS_TIMEOUT_NEVER to this function will not block indefinitely but will return immediately. Passing delays larger than 1/2 the OS time epoch should be avoided; behavior is unpredictable. Example /* delay 3 seconds */ int32_t delay = OS_TICKS_PER_SEC * 3 ; os_time_delay ( delay );","title":"os_time_delay"},{"location":"os/core_os/time/os_time_delay/#os_time_delay","text":"void os_time_delay ( int32_t ticks )","title":"os_time_delay"},{"location":"os/core_os/time/os_time_delay/#arguments","text":"Arguments Description ticks Number of ticks to delay. Less than or equal to zero means no delay","title":"Arguments"},{"location":"os/core_os/time/os_time_delay/#returned-values","text":"N/A","title":"Returned values"},{"location":"os/core_os/time/os_time_delay/#notes","text":"Passing OS_TIMEOUT_NEVER to this function will not block indefinitely but will return immediately. Passing delays larger than 1/2 the OS time epoch should be avoided; behavior is unpredictable.","title":"Notes"},{"location":"os/core_os/time/os_time_delay/#example","text":"/* delay 3 seconds */ int32_t delay = OS_TICKS_PER_SEC * 3 ; os_time_delay ( delay );","title":"Example"},{"location":"os/core_os/time/os_time_get/","text":"os_time_get os_time_t os_time_get ( void ) Arguments N/A Returned values The current value of the OS time Notes See the Special Notes on OS time epoch and comparison Example os_time_t now = os_time_get ();","title":"os_time_get"},{"location":"os/core_os/time/os_time_get/#os_time_get","text":"os_time_t os_time_get ( void )","title":"os_time_get"},{"location":"os/core_os/time/os_time_get/#arguments","text":"N/A","title":"Arguments"},{"location":"os/core_os/time/os_time_get/#returned-values","text":"The current value of the OS time","title":"Returned values"},{"location":"os/core_os/time/os_time_get/#notes","text":"See the Special Notes on OS time epoch and comparison","title":"Notes"},{"location":"os/core_os/time/os_time_get/#example","text":"os_time_t now = os_time_get ();","title":"Example"},{"location":"os/core_os/time/os_time_tick/","text":"os_time_tick void os_time_tick ( void ) Increments the OS time tick for the system. Typically, this is called in one place by the architecture specific OS code ( libs/os/arch ) timer_handler which is in turn called by the BSP specific code assigned to drive the OS timer tick. See Porting Mynewt OS for details. Arguments N/A Returned values N/A Notes Called for every single tick by the architecture specific functions. Example os_time_tick ();","title":"os_time_tick"},{"location":"os/core_os/time/os_time_tick/#os_time_tick","text":"void os_time_tick ( void ) Increments the OS time tick for the system. Typically, this is called in one place by the architecture specific OS code ( libs/os/arch ) timer_handler which is in turn called by the BSP specific code assigned to drive the OS timer tick. See Porting Mynewt OS for details.","title":"os_time_tick"},{"location":"os/core_os/time/os_time_tick/#arguments","text":"N/A","title":"Arguments"},{"location":"os/core_os/time/os_time_tick/#returned-values","text":"N/A","title":"Returned values"},{"location":"os/core_os/time/os_time_tick/#notes","text":"Called for every single tick by the architecture specific functions.","title":"Notes"},{"location":"os/core_os/time/os_time_tick/#example","text":"os_time_tick ();","title":"Example"},{"location":"os/get_started/cross_tools/","text":"Installing Cross Tools for ARM This page shows how to install tools on your laptop/computer to use for direct communication (e.g. for debugging) with some ARM based HW platforms running Apache Mynewt. You will also have to use the Newt tool installed to run natively on your machine. You may choose to do this instead of using the build toolchain and Newt tool available in a Docker container. This page provides guidance for installing the tools directly on your MAC and Linux machine. See the relevant sections below. Install ARM Cross tools in Mac OS X Install Tool Chain Install the PX4 Toolchain and check the version installed. ARM maintains a pre-built GNU toolchain with a GCC source branch targeted at Embedded ARM Processors, namely Cortex-R/Cortex-M processor families. After installing, ensure that the symbolic link installed by Homebrew points to the correct version of the debugger. $ brew tap PX4/homebrew-px4 $ brew update $ brew install gcc-arm-none-eabi-49 $ arm-none-eabi-gcc --version arm-none-eabi-gcc (GNU Tools for ARM Embedded Processors) 4.9.3 20150529 (release) [ARM/embedded-4_9-branch revision 224288] Copyright (C) 2014 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ ls -al /usr/local/bin/arm-none-eabi-gdb lrwxr-xr-x 1 aditihilbert admin 69 Sep 22 17:16 /usr/local/bin/arm-none-eabi-gdb -> /usr/local/Cellar/gcc-arm-none-eabi-49/20150609/bin/arm-none-eabi-gdb Note: If no version is specified, brew will install the latest version available. Mynewt OS will eventually work with multiple versions available, including the latest releases. However, at present we have tested only with this version and recommend it for getting started. Install OpenOCD OpenOCD (Open On-Chip Debugger) is open-source software that allows your computer to interface with the JTAG debug connector on a variety of boards. A JTAG connection lets you debug and test embedded target devices. For more on OpenOCD go to http://openocd.org . $ brew install open-ocd $ which openocd /usr/local/bin/openocd $ ls -l $(which openocd) lrwxr-xr-x 1 <user> admin 36 Sep 17 16:22 /usr/local/bin/openocd -> ../Cellar/open-ocd/0.9.0/bin/openocd Install ARM cross arm tools for Linux Install Tool Chain On a Debian-based Linux distribution, gcc 4.9.3 for ARM can be installed with apt-get as documented below. The steps are explained in depth at https://launchpad.net/~terry.guo/+archive/ubuntu/gcc-arm-embedded . $ sudo apt-get remove binutils-arm-none-eabi gcc-arm-none-eabi $ sudo add-apt-repository ppa:terry.guo/gcc-arm-embedded $ sudo apt-get update $ sudo apt-get install gcc-arm-none-eabi $ sudo apt-get install gdb-arm-none-eabi Install OpenOCD OpenOCD (Open On-Chip Debugger) is open-source software that allows your computer to interface with the JTAG debug connector on a variety of boards. A JTAG connection lets you debug and test embedded target devices. For more on OpenOCD go to http://openocd.org . If you are running Ubuntu 15.x, then you are in luck and you can simply run: $ sudo apt-get install openocd For this project, you should download the openocd 0.8.0 package from https://launchpad.net/ubuntu/vivid/+source/openocd . The direct link to the amd64 build is http://launchpadlibrarian.net/188260097/openocd_0.8.0-4_amd64.deb .","title":"Install Cross Tools for ARM"},{"location":"os/get_started/cross_tools/#installing-cross-tools-for-arm","text":"This page shows how to install tools on your laptop/computer to use for direct communication (e.g. for debugging) with some ARM based HW platforms running Apache Mynewt. You will also have to use the Newt tool installed to run natively on your machine. You may choose to do this instead of using the build toolchain and Newt tool available in a Docker container. This page provides guidance for installing the tools directly on your MAC and Linux machine. See the relevant sections below.","title":"Installing Cross Tools for ARM"},{"location":"os/get_started/cross_tools/#install-arm-cross-tools-in-mac-os-x","text":"","title":"Install ARM Cross tools in Mac OS X"},{"location":"os/get_started/cross_tools/#install-tool-chain","text":"Install the PX4 Toolchain and check the version installed. ARM maintains a pre-built GNU toolchain with a GCC source branch targeted at Embedded ARM Processors, namely Cortex-R/Cortex-M processor families. After installing, ensure that the symbolic link installed by Homebrew points to the correct version of the debugger. $ brew tap PX4/homebrew-px4 $ brew update $ brew install gcc-arm-none-eabi-49 $ arm-none-eabi-gcc --version arm-none-eabi-gcc (GNU Tools for ARM Embedded Processors) 4.9.3 20150529 (release) [ARM/embedded-4_9-branch revision 224288] Copyright (C) 2014 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ ls -al /usr/local/bin/arm-none-eabi-gdb lrwxr-xr-x 1 aditihilbert admin 69 Sep 22 17:16 /usr/local/bin/arm-none-eabi-gdb -> /usr/local/Cellar/gcc-arm-none-eabi-49/20150609/bin/arm-none-eabi-gdb Note: If no version is specified, brew will install the latest version available. Mynewt OS will eventually work with multiple versions available, including the latest releases. However, at present we have tested only with this version and recommend it for getting started.","title":"Install Tool Chain"},{"location":"os/get_started/cross_tools/#install-openocd","text":"OpenOCD (Open On-Chip Debugger) is open-source software that allows your computer to interface with the JTAG debug connector on a variety of boards. A JTAG connection lets you debug and test embedded target devices. For more on OpenOCD go to http://openocd.org . $ brew install open-ocd $ which openocd /usr/local/bin/openocd $ ls -l $(which openocd) lrwxr-xr-x 1 <user> admin 36 Sep 17 16:22 /usr/local/bin/openocd -> ../Cellar/open-ocd/0.9.0/bin/openocd","title":"Install OpenOCD"},{"location":"os/get_started/cross_tools/#install-arm-cross-arm-tools-for-linux","text":"","title":"Install ARM cross arm tools for Linux"},{"location":"os/get_started/cross_tools/#install-tool-chain_1","text":"On a Debian-based Linux distribution, gcc 4.9.3 for ARM can be installed with apt-get as documented below. The steps are explained in depth at https://launchpad.net/~terry.guo/+archive/ubuntu/gcc-arm-embedded . $ sudo apt-get remove binutils-arm-none-eabi gcc-arm-none-eabi $ sudo add-apt-repository ppa:terry.guo/gcc-arm-embedded $ sudo apt-get update $ sudo apt-get install gcc-arm-none-eabi $ sudo apt-get install gdb-arm-none-eabi","title":"Install Tool Chain"},{"location":"os/get_started/cross_tools/#install-openocd_1","text":"OpenOCD (Open On-Chip Debugger) is open-source software that allows your computer to interface with the JTAG debug connector on a variety of boards. A JTAG connection lets you debug and test embedded target devices. For more on OpenOCD go to http://openocd.org . If you are running Ubuntu 15.x, then you are in luck and you can simply run: $ sudo apt-get install openocd For this project, you should download the openocd 0.8.0 package from https://launchpad.net/ubuntu/vivid/+source/openocd . The direct link to the amd64 build is http://launchpadlibrarian.net/188260097/openocd_0.8.0-4_amd64.deb .","title":"Install OpenOCD"},{"location":"os/get_started/docker/","text":"Everything You Need in a Docker Container Docker provides a quick and easy way to get up and running with Mynewt. The newt command line tool and the entire build toolchain is available in a single docker container. The container is all that's needed to run your Mynewt based application in the simulator. Enabling USB2 with your docker installation will allow you to load your application on a supported device. Docker is the only supported option if you are working on a Windows machine. If you are using Mac OS X or Linux, you have the choice of installing a Docker container of tools and toolchains or installing them natively. This chapter describes how to set up the Docker image for all three platforms. Install Docker Install docker for your platform. Mac OS X / Windows / Linux Mac and Windows Mac and Windows require Docker Toolbox to interact with USB devices. Docker for Mac and Docker for Windows do not support USB. Docker Toolbox uses VirtualBox and allows you to map USB devices into docker containers as described below. Make sure to double click the Docker Quickstart Terminal application if you're on Mac or Windows. Linux The docker daemon listens on a Unix domain socket on Linux. That socket is owned by root, which means by default you must be root to start a container. Make sure to follow the optional step of adding yourself to the docker group so you can start the newt container as yourself. Use the newt wrapper script Use the newt wrapper script to invoke newt. Create the following file, name it newt , make it executable, and put it in your path. This will allow you to run newt as if it was natively installed. You can now follow the normal tutorials using the newt wrapper script. #!/bin/bash if [ \" $1 \" = \"debug\" ] || [ \" $1 \" = \"run\" ] then ti= \"-ti\" fi docker run -e NEWT_USER= $( id -u ) -e NEWT_GROUP= $( id -g ) -e NEWT_HOST= $( uname ) $ti --rm --device = /dev/bus/usb --privileged -v $(pwd) :/workspace -w /workspace mynewt/newt:latest /newt \" $@ \" Note 1: Remember to point to the correct subdirectory level when invoking newt . For example, invoke it using ../newt in the example below. user@~/dockertest$ ls myproj newt user@~/dockertest$ cd myproj user@~/dockertest/myproj$ ../newt version Apache Newt (incubating) version: 0.8.0-b2 Note 2: You can upgrade your container by running docker pull mynewt/newt:latest when updates are made available. Enable USB2 Support for Mac or Windows If you plan on loading your application on an actual device, do the steps below. Install VirtualBox extension pack Docker uses a VirtualBox Linux VM to run containers. A free VirtualBox extension pack is required to enable USB2 support. Download the VirtualBox 5.0.16 Oracle VM VirtualBox Extension Pack and double click to install Enable USB2 and select your device The \"default\" VM created by docker-machine must first be stopped before you can enable USB2. You have two options: Run the command docker-machine stop default in the terminal window or Use the VirtualBox UI. Right click on default -> Close -> Power Off Enable USB2 using the VirtualBox UI. Select the \"default\" VM->Settings->Ports->USB2 to enable USB2. Add your device to the USB Device Filters to make the device visible in the docker container. See the image below. Restart the \"default\" VM. You have two options: Run docker-machine start default in the terminal window or Use the VirtualBox UI. Make sure the \"default\" machine is highlighted. Click the green \"Start\" button. Select \"Headless Start\". Note 3 : When working with actual hardware, remember that each board has an ID. If you swap boards and do not refresh the USB Device Filter on the VirtualBox UI, the ID might be stale and the Docker instance may not be able to see the board correctly. For example, you may see an error message like Error: unable to find CMSIS-DAP device when you try to load or run an image on the board. In that case, you need to click on the USB link in VirtualBox UI, remove the existing USB Device Filter (e.g. \"Atmel Corp. EDBG CMSIS-DAP[0101]\") by clicking on the \"Removes selected USB filter\" button, and add a new filter by clicking on the \"Adds new USB filter\" button.","title":"Docker Container Option"},{"location":"os/get_started/docker/#everything-you-need-in-a-docker-container","text":"Docker provides a quick and easy way to get up and running with Mynewt. The newt command line tool and the entire build toolchain is available in a single docker container. The container is all that's needed to run your Mynewt based application in the simulator. Enabling USB2 with your docker installation will allow you to load your application on a supported device. Docker is the only supported option if you are working on a Windows machine. If you are using Mac OS X or Linux, you have the choice of installing a Docker container of tools and toolchains or installing them natively. This chapter describes how to set up the Docker image for all three platforms.","title":"Everything You Need in a Docker Container"},{"location":"os/get_started/docker/#install-docker","text":"Install docker for your platform. Mac OS X / Windows / Linux","title":"Install Docker"},{"location":"os/get_started/docker/#mac-and-windows","text":"Mac and Windows require Docker Toolbox to interact with USB devices. Docker for Mac and Docker for Windows do not support USB. Docker Toolbox uses VirtualBox and allows you to map USB devices into docker containers as described below. Make sure to double click the Docker Quickstart Terminal application if you're on Mac or Windows.","title":"Mac and Windows"},{"location":"os/get_started/docker/#linux","text":"The docker daemon listens on a Unix domain socket on Linux. That socket is owned by root, which means by default you must be root to start a container. Make sure to follow the optional step of adding yourself to the docker group so you can start the newt container as yourself.","title":"Linux"},{"location":"os/get_started/docker/#use-the-newt-wrapper-script","text":"Use the newt wrapper script to invoke newt. Create the following file, name it newt , make it executable, and put it in your path. This will allow you to run newt as if it was natively installed. You can now follow the normal tutorials using the newt wrapper script. #!/bin/bash if [ \" $1 \" = \"debug\" ] || [ \" $1 \" = \"run\" ] then ti= \"-ti\" fi docker run -e NEWT_USER= $( id -u ) -e NEWT_GROUP= $( id -g ) -e NEWT_HOST= $( uname ) $ti --rm --device = /dev/bus/usb --privileged -v $(pwd) :/workspace -w /workspace mynewt/newt:latest /newt \" $@ \" Note 1: Remember to point to the correct subdirectory level when invoking newt . For example, invoke it using ../newt in the example below. user@~/dockertest$ ls myproj newt user@~/dockertest$ cd myproj user@~/dockertest/myproj$ ../newt version Apache Newt (incubating) version: 0.8.0-b2 Note 2: You can upgrade your container by running docker pull mynewt/newt:latest when updates are made available.","title":"Use the newt wrapper script"},{"location":"os/get_started/docker/#enable-usb2-support-for-mac-or-windows","text":"If you plan on loading your application on an actual device, do the steps below.","title":"Enable USB2 Support for Mac or Windows"},{"location":"os/get_started/docker/#install-virtualbox-extension-pack","text":"Docker uses a VirtualBox Linux VM to run containers. A free VirtualBox extension pack is required to enable USB2 support. Download the VirtualBox 5.0.16 Oracle VM VirtualBox Extension Pack and double click to install","title":"Install VirtualBox extension pack"},{"location":"os/get_started/docker/#enable-usb2-and-select-your-device","text":"The \"default\" VM created by docker-machine must first be stopped before you can enable USB2. You have two options: Run the command docker-machine stop default in the terminal window or Use the VirtualBox UI. Right click on default -> Close -> Power Off Enable USB2 using the VirtualBox UI. Select the \"default\" VM->Settings->Ports->USB2 to enable USB2. Add your device to the USB Device Filters to make the device visible in the docker container. See the image below. Restart the \"default\" VM. You have two options: Run docker-machine start default in the terminal window or Use the VirtualBox UI. Make sure the \"default\" machine is highlighted. Click the green \"Start\" button. Select \"Headless Start\". Note 3 : When working with actual hardware, remember that each board has an ID. If you swap boards and do not refresh the USB Device Filter on the VirtualBox UI, the ID might be stale and the Docker instance may not be able to see the board correctly. For example, you may see an error message like Error: unable to find CMSIS-DAP device when you try to load or run an image on the board. In that case, you need to click on the USB link in VirtualBox UI, remove the existing USB Device Filter (e.g. \"Atmel Corp. EDBG CMSIS-DAP[0101]\") by clicking on the \"Removes selected USB filter\" button, and add a new filter by clicking on the \"Adds new USB filter\" button.","title":"Enable USB2 and select your device"},{"location":"os/get_started/get_started/","text":"Quick Start If you are curious about Mynewt and want to get a quick feel for the project, you've come to the right place. We have two options for you: Option 1 is the quick and easy way to get up and running with Mynewt. The Newt tool and build toolchains are all available in a single All-in-one Docker Container that you can install on your laptop or computer. Option 2 allows you to install the Newt tool, instances of the Mynewt OS (for simulated targets), and toolchains for developing embedded software (e.g. GNU toolchain) natively on your laptop or computer. You may want this if you are already familiar with such environments or are concerned about performance on your machine. Follow the instructions to install native tools and install cross tools for ARM if you prefer this option. You can then proceed with the instructions on how to * Create Your First Project - on simulated hardware. Upon successful start, several tutorials await your eager attention! Send us an email on the dev@ mailing list if you have comments or suggestions! If you haven't joined the mailing list, you will find the links here .","title":"toc"},{"location":"os/get_started/get_started/#quick-start","text":"If you are curious about Mynewt and want to get a quick feel for the project, you've come to the right place. We have two options for you: Option 1 is the quick and easy way to get up and running with Mynewt. The Newt tool and build toolchains are all available in a single All-in-one Docker Container that you can install on your laptop or computer. Option 2 allows you to install the Newt tool, instances of the Mynewt OS (for simulated targets), and toolchains for developing embedded software (e.g. GNU toolchain) natively on your laptop or computer. You may want this if you are already familiar with such environments or are concerned about performance on your machine. Follow the instructions to install native tools and install cross tools for ARM if you prefer this option. You can then proceed with the instructions on how to * Create Your First Project - on simulated hardware. Upon successful start, several tutorials await your eager attention! Send us an email on the dev@ mailing list if you have comments or suggestions! If you haven't joined the mailing list, you will find the links here .","title":"Quick Start"},{"location":"os/get_started/native_tools/","text":"Installing Native Mynewt Tools This page shows how to install tools for native Mynewt targets (simulated targets on your laptop/computer) without using a Docker container. In other words, it allows you to run Mynewt OS as a native application on your Mac or Linux machine to simulate a target and use the Newt tool running natively on your machine to manage the simulated target. It also allows you to run the test suites for all packages not requiring HW support. You may choose to do this instead of using the build toolchain and Newt tool available in a Docker container. This page provides guidance for MAC and Linux. See the relevant sections below. Set up toolchain for Mac Install Brew If you have not already installed Homebrew from the newt tutorials pages , install it. Install gcc/libc OS X ships with a C compiler called Clang. To build applications for the Mynewt simulator with, a different compiler is used as default: gcc. $ brew install gcc ... ... ==> Summary \ud83c\udf7a /usr/local/Cellar/gcc/5.2.0: 1353 files, 248M Check the gcc version you have installed (either using brew or previously installed). The brew-installed version can be checked using brew list gcc . The default compiler.yml configuration file in Mynewt expects version 5.x for Mac users, so if the installed version is 6.x and you wish to continue with this newer version, modify the <mynewt-src-directory>/repos/apache-mynewt-core/compiler/sim/compiler.yml file to change the default gcc-5 defined there to gcc-6 . In other words, replace the lines shown highlighted below: # OS X. compiler.path.cc.DARWIN.OVERWRITE: \"/usr/local/bin/gcc-5\" compiler.path.as.DARWIN.OVERWRITE: \"/usr/local/bin/gcc-5 -x assembler-with-cpp\" compiler.path.objdump.DARWIN.OVERWRITE: \"gobjdump\" compiler.path.objsize.DARWIN.OVERWRITE: \"objsize\" compiler.path.objcopy.DARWIN.OVERWRITE: \"gobjcopy\" with the following: compiler.path.cc.DARWIN.OVERWRITE: \"/usr/local/bin/gcc-6\" compiler.path.as.DARWIN.OVERWRITE: \"/usr/local/bin/gcc-6 -x assembler-with-cpp\u201d In case you wish to use Clang, you can change your <mynewt-src-directory>/repos/apache-mynewt-core/compiler/sim/compiler.yml to use Clang. Delete the gcc-5 DARWIN.OVERWRITE lines highlighted below. # OS X. compiler.path.cc.DARWIN.OVERWRITE: \"/usr/local/bin/gcc-5\" compiler.path.as.DARWIN.OVERWRITE: \"/usr/local/bin/gcc-5 -x assembler-with-cpp\" compiler.path.objdump.DARWIN.OVERWRITE: \"gobjdump\" compiler.path.objsize.DARWIN.OVERWRITE: \"objsize\" compiler.path.objcopy.DARWIN.OVERWRITE: \"gobjcopy\" NOTE: Both the newer gcc 6.x and Clang report a few warnings but they can be ignored. FURTHER NOTE: Mynewt developers mostly use gcc 5.x for sim builds; so it may take a little while to fix issues reported by the newer compiler. One option is to disable warnings . To do that, remove the -Werror flag as an option for the compiler in the <mynewt-src-directory>/repos/apache-mynewt-core/compiler/sim/compiler.yml file as shown below. compiler.flags.base: > -m32 -Wall -ggdb You may alternatively choose to specify the precise warnings to ignore depending on the error thrown by the compiler. For example, if you see a [-Werror=misleading-indentation] error while building the sim image, add -Wno-misleading-indentation] as a compiler flag in the same line from the <mynewt-src-directory>/repos/apache-mynewt-core/compiler/sim/compiler.yml file. compiler.flags.base: > -m32 -Wall -Werror -ggdb -Wno-misleading-indentation A third option is to simply downgrade to gcc 5.x . Install gdb $ brew install gdb ... ... ==> Summary \ud83c\udf7a /usr/local/Cellar/gdb/7.10.1: XXX files,YYM NOTE: When running a program with gdb, you may need to sign your gdb executable. This page shows a recipe for gdb signing. Alternately you can skip this step and continue without the ability to debug your mynewt application on your PC.* Set up toolchain for Linux The below procedure can be used to set up a Debian-based Linux system (e.g., Ubuntu). If you are running a different Linux distribution, you will need to substitute invocations of apt-get in the below steps with the package manager that your distro uses. Install gcc/libc that will produce 32-bit executables: $ sudo apt-get install gcc-multilib libc6-i386 Install gdb $ sudo apt-get install gdb Reading package lists... Done Building dependency tree Reading state information... Done Suggested packages: gdb-doc gdbserver The following NEW packages will be installed: gdb ... Processing triggers for man-db (2.6.7.1-1ubuntu1) ... Setting up gdb (7.7.1-0ubuntu5~14.04.2) ... At this point you have installed all the necessary software to build and test code on a simluator running on your Mac or Linux. Proceed to the Create Your First Project section.","title":"toc"},{"location":"os/get_started/native_tools/#installing-native-mynewt-tools","text":"This page shows how to install tools for native Mynewt targets (simulated targets on your laptop/computer) without using a Docker container. In other words, it allows you to run Mynewt OS as a native application on your Mac or Linux machine to simulate a target and use the Newt tool running natively on your machine to manage the simulated target. It also allows you to run the test suites for all packages not requiring HW support. You may choose to do this instead of using the build toolchain and Newt tool available in a Docker container. This page provides guidance for MAC and Linux. See the relevant sections below.","title":"Installing Native Mynewt Tools"},{"location":"os/get_started/native_tools/#set-up-toolchain-for-mac","text":"","title":"Set up toolchain for Mac"},{"location":"os/get_started/native_tools/#install-brew","text":"If you have not already installed Homebrew from the newt tutorials pages , install it.","title":"Install Brew"},{"location":"os/get_started/native_tools/#install-gcclibc","text":"OS X ships with a C compiler called Clang. To build applications for the Mynewt simulator with, a different compiler is used as default: gcc. $ brew install gcc ... ... ==> Summary \ud83c\udf7a /usr/local/Cellar/gcc/5.2.0: 1353 files, 248M Check the gcc version you have installed (either using brew or previously installed). The brew-installed version can be checked using brew list gcc . The default compiler.yml configuration file in Mynewt expects version 5.x for Mac users, so if the installed version is 6.x and you wish to continue with this newer version, modify the <mynewt-src-directory>/repos/apache-mynewt-core/compiler/sim/compiler.yml file to change the default gcc-5 defined there to gcc-6 . In other words, replace the lines shown highlighted below: # OS X. compiler.path.cc.DARWIN.OVERWRITE: \"/usr/local/bin/gcc-5\" compiler.path.as.DARWIN.OVERWRITE: \"/usr/local/bin/gcc-5 -x assembler-with-cpp\" compiler.path.objdump.DARWIN.OVERWRITE: \"gobjdump\" compiler.path.objsize.DARWIN.OVERWRITE: \"objsize\" compiler.path.objcopy.DARWIN.OVERWRITE: \"gobjcopy\" with the following: compiler.path.cc.DARWIN.OVERWRITE: \"/usr/local/bin/gcc-6\" compiler.path.as.DARWIN.OVERWRITE: \"/usr/local/bin/gcc-6 -x assembler-with-cpp\u201d In case you wish to use Clang, you can change your <mynewt-src-directory>/repos/apache-mynewt-core/compiler/sim/compiler.yml to use Clang. Delete the gcc-5 DARWIN.OVERWRITE lines highlighted below. # OS X. compiler.path.cc.DARWIN.OVERWRITE: \"/usr/local/bin/gcc-5\" compiler.path.as.DARWIN.OVERWRITE: \"/usr/local/bin/gcc-5 -x assembler-with-cpp\" compiler.path.objdump.DARWIN.OVERWRITE: \"gobjdump\" compiler.path.objsize.DARWIN.OVERWRITE: \"objsize\" compiler.path.objcopy.DARWIN.OVERWRITE: \"gobjcopy\" NOTE: Both the newer gcc 6.x and Clang report a few warnings but they can be ignored. FURTHER NOTE: Mynewt developers mostly use gcc 5.x for sim builds; so it may take a little while to fix issues reported by the newer compiler. One option is to disable warnings . To do that, remove the -Werror flag as an option for the compiler in the <mynewt-src-directory>/repos/apache-mynewt-core/compiler/sim/compiler.yml file as shown below. compiler.flags.base: > -m32 -Wall -ggdb You may alternatively choose to specify the precise warnings to ignore depending on the error thrown by the compiler. For example, if you see a [-Werror=misleading-indentation] error while building the sim image, add -Wno-misleading-indentation] as a compiler flag in the same line from the <mynewt-src-directory>/repos/apache-mynewt-core/compiler/sim/compiler.yml file. compiler.flags.base: > -m32 -Wall -Werror -ggdb -Wno-misleading-indentation A third option is to simply downgrade to gcc 5.x .","title":"Install gcc/libc"},{"location":"os/get_started/native_tools/#install-gdb","text":"$ brew install gdb ... ... ==> Summary \ud83c\udf7a /usr/local/Cellar/gdb/7.10.1: XXX files,YYM NOTE: When running a program with gdb, you may need to sign your gdb executable. This page shows a recipe for gdb signing. Alternately you can skip this step and continue without the ability to debug your mynewt application on your PC.*","title":"Install gdb"},{"location":"os/get_started/native_tools/#set-up-toolchain-for-linux","text":"The below procedure can be used to set up a Debian-based Linux system (e.g., Ubuntu). If you are running a different Linux distribution, you will need to substitute invocations of apt-get in the below steps with the package manager that your distro uses.","title":"Set up toolchain for Linux"},{"location":"os/get_started/native_tools/#install-gcclibc-that-will-produce-32-bit-executables","text":"$ sudo apt-get install gcc-multilib libc6-i386","title":"Install gcc/libc that will produce 32-bit executables:"},{"location":"os/get_started/native_tools/#install-gdb_1","text":"$ sudo apt-get install gdb Reading package lists... Done Building dependency tree Reading state information... Done Suggested packages: gdb-doc gdbserver The following NEW packages will be installed: gdb ... Processing triggers for man-db (2.6.7.1-1ubuntu1) ... Setting up gdb (7.7.1-0ubuntu5~14.04.2) ... At this point you have installed all the necessary software to build and test code on a simluator running on your Mac or Linux. Proceed to the Create Your First Project section.","title":"Install gdb"},{"location":"os/get_started/project_create/","text":"Create Your First Mynewt Project This page shows how to create a Mynewt Project using the newt command-line tool. Pre-Requisites Newt: If you have taken the Docker route, you have already installed Newt. If you have taken the native install route, you have to ensure that you have installed the Newt tool following the instructions for Mac or Linux as appropriate, and that the newt command is in your system path. You must have Internet connectivity to fetch remote Mynewt components. You must install the compiler tools to support native compiling to build the project this tutorial creates. Newt New Choose a project name. For this tutorial we will call this project myproj . Enter the newt new myproj command. $ newt new myproj Downloading project skeleton from apache/incubator-mynewt-blinky... Installing skeleton in myproj... Project myproj successfully created. Newt populates this new project with a base skeleton of a new Apache Mynewt project. It has the following structure. Note : If you do not have tree , install it by running brew install tree . $ cd myproj $ tree . \u251c\u2500\u2500 DISCLAIMER \u251c\u2500\u2500 LICENSE \u251c\u2500\u2500 NOTICE \u251c\u2500\u2500 README.md \u251c\u2500\u2500 apps \u2502 \u2514\u2500\u2500 blinky \u2502 \u251c\u2500\u2500 pkg.yml \u2502 \u2514\u2500\u2500 src \u251c\u2500\u2500 project.yml \u2514\u2500\u2500 targets \u251c\u2500\u2500 my_blinky_sim \u2502 \u251c\u2500\u2500 pkg.yml \u2502 \u2514\u2500\u2500 target.yml \u2514\u2500\u2500 unittest \u251c\u2500\u2500 pkg.yml \u2514\u2500\u2500 target.yml 6 directories, 10 files The Newt tool has installed the base files for a project comprising the following: The file project.yml contains the repository list that the project uses to fetch its packages. Your project is a collection of repositories. In this case, the project just comprises the core mynewt repository. Later you will add more repositories to include other mynewt components. The file apps/blinky/pkg.yml contains the description of your application and its package dependencies. A target directory containing my_blinky_sim , a target descriptor used to build a version of myproj. Use newt target show to see available build targets. A non-buildable target called unittest . This is used internally by newt and is not a formal build target. NOTE: the actual code and package files are not installed (except the template for main.c ). See the next step for installing the packages. Newt Install Once you've switched into your new project's directory, the next step is to fetch any dependencies this project has. By default, all Newt projects rely on a single remote repository, apache-mynewt-core. The newt install command will fetch this repository. $ newt install apache-mynewt-core NOTE: apache-mynewt-core may take a while to download. To see progress, use the -v (verbose) option to install. Once newt install has successfully finished, the contents of apache-mynewt-core will have been downloaded into your local directory. You can view them by issuing the following commands in the base directory of the new project: $ tree -L 2 repos/apache-mynewt-core/ . <snip> \u251c\u2500\u2500 fs \u2502 \u251c\u2500\u2500 fs \u2502 \u2514\u2500\u2500 nffs \u251c\u2500\u2500 hw \u2502 \u251c\u2500\u2500 bsp \u2502 \u251c\u2500\u2500 hal \u2502 \u2514\u2500\u2500 mcu \u251c\u2500\u2500 libs \u2502 \u251c\u2500\u2500 baselibc \u2502 \u251c\u2500\u2500 bootutil \u2502 \u251c\u2500\u2500 cmsis-core \u2502 \u251c\u2500\u2500 console \u2502 \u251c\u2500\u2500 elua \u2502 \u251c\u2500\u2500 flash_test \u2502 \u251c\u2500\u2500 imgmgr \u2502 \u251c\u2500\u2500 json \u2502 \u251c\u2500\u2500 mbedtls \u2502 \u251c\u2500\u2500 newtmgr \u2502 \u251c\u2500\u2500 os \u2502 \u251c\u2500\u2500 shell \u2502 \u251c\u2500\u2500 testreport \u2502 \u251c\u2500\u2500 testutil \u2502 \u2514\u2500\u2500 util \u251c\u2500\u2500 net \u2502 \u2514\u2500\u2500 nimble <snip> As you can see, the core of the Apache Mynewt operating system has been brought into your local directory. Test the project's packages You have already built your first basic project. You can ask Newt to execute the unit tests in a package. For example, to test the libs/os package in the apache-mynewt-core repo, call newt as shown below. $ newt test @apache-mynewt-core/libs/os Testing package @apache-mynewt-core/libs/os Compiling hal_bsp.c Compiling os_bsp.c Compiling sbrk.c Archiving native.a Compiling flash_map.c <snip> To test all the packages in a project, specify all instead of the package name. $ newt test all ...lots of compiling and testing... ...about 2 minutes later ... Archiving bootutil.a Linking test_bootutil Executing test: /myproj/bin/unittest/libs/bootutil/test_bootutil Passed tests: [net/nimble/host fs/nffs libs/os hw/hal libs/mbedtls libs/util sys/config libs/bootutil] All tests passed Build the Project To build and run your new application, simply issue the following command: $ newt build my_blinky_sim Compiling base64.c Compiling cbmem.c Compiling datetime.c Compiling tpq.c Archiving util.a Compiling main.c Archiving blinky.a Compiling flash_map.c Compiling hal_flash.c Archiving hal.a Compiling cons_fmt.c Compiling cons_tty.c <snip> Linking blinky.elf App successfully built: /Users/sterling/dev/tmp/my_app/bin/my_blinky_sim/apps/blinky/blinky.elf Run the Project You can run the simulated version of your project and see the simulated LED blink. $ newt run my_blinky_sim No download script for BSP hw/bsp/native Debugging /workspace/bin/my_blinky_sim/apps/blinky/blinky.elf <snip> Reading symbols from /workspace/bin/my_blinky_sim/apps/blinky/blinky.elf...done. (gdb) Type r at the (gdb) prompt to run the project. You will see an output indicating that the hal_gpio pin is toggling between 1 and 0 in a simulated blink. Complete Congratulations, you have created your first project! The blinky application is not terribly exciting when it is run in the simulator, as there is no LED to blink. Apache Mynewt has a lot more functionality than just running simulated applications. It provides all the features you'll need to cross-compile your application, run it on real hardware and develop a full featured application. If you're interested in learning more, a good next step is to dig in to one of the tutorials and get a Mynewt project running on real hardware. Happy Hacking!","title":"Create Your First Project"},{"location":"os/get_started/project_create/#create-your-first-mynewt-project","text":"This page shows how to create a Mynewt Project using the newt command-line tool.","title":"Create Your First Mynewt Project"},{"location":"os/get_started/project_create/#pre-requisites","text":"Newt: If you have taken the Docker route, you have already installed Newt. If you have taken the native install route, you have to ensure that you have installed the Newt tool following the instructions for Mac or Linux as appropriate, and that the newt command is in your system path. You must have Internet connectivity to fetch remote Mynewt components. You must install the compiler tools to support native compiling to build the project this tutorial creates.","title":"Pre-Requisites"},{"location":"os/get_started/project_create/#newt-new","text":"Choose a project name. For this tutorial we will call this project myproj . Enter the newt new myproj command. $ newt new myproj Downloading project skeleton from apache/incubator-mynewt-blinky... Installing skeleton in myproj... Project myproj successfully created. Newt populates this new project with a base skeleton of a new Apache Mynewt project. It has the following structure. Note : If you do not have tree , install it by running brew install tree . $ cd myproj $ tree . \u251c\u2500\u2500 DISCLAIMER \u251c\u2500\u2500 LICENSE \u251c\u2500\u2500 NOTICE \u251c\u2500\u2500 README.md \u251c\u2500\u2500 apps \u2502 \u2514\u2500\u2500 blinky \u2502 \u251c\u2500\u2500 pkg.yml \u2502 \u2514\u2500\u2500 src \u251c\u2500\u2500 project.yml \u2514\u2500\u2500 targets \u251c\u2500\u2500 my_blinky_sim \u2502 \u251c\u2500\u2500 pkg.yml \u2502 \u2514\u2500\u2500 target.yml \u2514\u2500\u2500 unittest \u251c\u2500\u2500 pkg.yml \u2514\u2500\u2500 target.yml 6 directories, 10 files The Newt tool has installed the base files for a project comprising the following: The file project.yml contains the repository list that the project uses to fetch its packages. Your project is a collection of repositories. In this case, the project just comprises the core mynewt repository. Later you will add more repositories to include other mynewt components. The file apps/blinky/pkg.yml contains the description of your application and its package dependencies. A target directory containing my_blinky_sim , a target descriptor used to build a version of myproj. Use newt target show to see available build targets. A non-buildable target called unittest . This is used internally by newt and is not a formal build target. NOTE: the actual code and package files are not installed (except the template for main.c ). See the next step for installing the packages.","title":"Newt New"},{"location":"os/get_started/project_create/#newt-install","text":"Once you've switched into your new project's directory, the next step is to fetch any dependencies this project has. By default, all Newt projects rely on a single remote repository, apache-mynewt-core. The newt install command will fetch this repository. $ newt install apache-mynewt-core NOTE: apache-mynewt-core may take a while to download. To see progress, use the -v (verbose) option to install. Once newt install has successfully finished, the contents of apache-mynewt-core will have been downloaded into your local directory. You can view them by issuing the following commands in the base directory of the new project: $ tree -L 2 repos/apache-mynewt-core/ . <snip> \u251c\u2500\u2500 fs \u2502 \u251c\u2500\u2500 fs \u2502 \u2514\u2500\u2500 nffs \u251c\u2500\u2500 hw \u2502 \u251c\u2500\u2500 bsp \u2502 \u251c\u2500\u2500 hal \u2502 \u2514\u2500\u2500 mcu \u251c\u2500\u2500 libs \u2502 \u251c\u2500\u2500 baselibc \u2502 \u251c\u2500\u2500 bootutil \u2502 \u251c\u2500\u2500 cmsis-core \u2502 \u251c\u2500\u2500 console \u2502 \u251c\u2500\u2500 elua \u2502 \u251c\u2500\u2500 flash_test \u2502 \u251c\u2500\u2500 imgmgr \u2502 \u251c\u2500\u2500 json \u2502 \u251c\u2500\u2500 mbedtls \u2502 \u251c\u2500\u2500 newtmgr \u2502 \u251c\u2500\u2500 os \u2502 \u251c\u2500\u2500 shell \u2502 \u251c\u2500\u2500 testreport \u2502 \u251c\u2500\u2500 testutil \u2502 \u2514\u2500\u2500 util \u251c\u2500\u2500 net \u2502 \u2514\u2500\u2500 nimble <snip> As you can see, the core of the Apache Mynewt operating system has been brought into your local directory.","title":"Newt Install"},{"location":"os/get_started/project_create/#test-the-projects-packages","text":"You have already built your first basic project. You can ask Newt to execute the unit tests in a package. For example, to test the libs/os package in the apache-mynewt-core repo, call newt as shown below. $ newt test @apache-mynewt-core/libs/os Testing package @apache-mynewt-core/libs/os Compiling hal_bsp.c Compiling os_bsp.c Compiling sbrk.c Archiving native.a Compiling flash_map.c <snip> To test all the packages in a project, specify all instead of the package name. $ newt test all ...lots of compiling and testing... ...about 2 minutes later ... Archiving bootutil.a Linking test_bootutil Executing test: /myproj/bin/unittest/libs/bootutil/test_bootutil Passed tests: [net/nimble/host fs/nffs libs/os hw/hal libs/mbedtls libs/util sys/config libs/bootutil] All tests passed","title":"Test the project's packages"},{"location":"os/get_started/project_create/#build-the-project","text":"To build and run your new application, simply issue the following command: $ newt build my_blinky_sim Compiling base64.c Compiling cbmem.c Compiling datetime.c Compiling tpq.c Archiving util.a Compiling main.c Archiving blinky.a Compiling flash_map.c Compiling hal_flash.c Archiving hal.a Compiling cons_fmt.c Compiling cons_tty.c <snip> Linking blinky.elf App successfully built: /Users/sterling/dev/tmp/my_app/bin/my_blinky_sim/apps/blinky/blinky.elf","title":"Build the Project"},{"location":"os/get_started/project_create/#run-the-project","text":"You can run the simulated version of your project and see the simulated LED blink. $ newt run my_blinky_sim No download script for BSP hw/bsp/native Debugging /workspace/bin/my_blinky_sim/apps/blinky/blinky.elf <snip> Reading symbols from /workspace/bin/my_blinky_sim/apps/blinky/blinky.elf...done. (gdb) Type r at the (gdb) prompt to run the project. You will see an output indicating that the hal_gpio pin is toggling between 1 and 0 in a simulated blink.","title":"Run the Project"},{"location":"os/get_started/project_create/#complete","text":"Congratulations, you have created your first project! The blinky application is not terribly exciting when it is run in the simulator, as there is no LED to blink. Apache Mynewt has a lot more functionality than just running simulated applications. It provides all the features you'll need to cross-compile your application, run it on real hardware and develop a full featured application. If you're interested in learning more, a good next step is to dig in to one of the tutorials and get a Mynewt project running on real hardware. Happy Hacking!","title":"Complete"},{"location":"os/get_started/vocabulary/","text":"Concepts This page is meant to introduce you to some of the concepts inherent to the Apache Mynewt Operating System, and Newt the tool that stitches a project built on Apache Mynewt together. Project The project is the base directory of your embedded software tree. It is a workspace that contains a logical collection of source code, for one or more of your applications. A project consists of the following items: Project Definition: defines project level dependencies, and parameters (located in project.yml ) Packages Packages are described in detail in the section below. Here is an example project definition file from the default Apache Mynewt project: $ more project.yml <snip> project.name: \"my_project\" project.repositories: - apache-mynewt-core # Use github's distribution mechanism for core ASF libraries. # This provides mirroring automatically for us. # repository.apache-mynewt-core: type: github vers: 0-latest user: apache repo: incubator-mynewt-core $ A couple of things to note in the project definition: project.repositories : Defines the remote repositories that this project relies upon. repository.apache-mynewt-core : Defines the repository information for the apache-mynewt-core repository. Repositories are versioned collections of packages. Projects can rely on remote repositories for functionality, and the newt tool will resolve those remote repositories, and download the correct version into your local source tree. Newly fetched repositories are put in the repos directory of your project, and can be referenced throughout the system by using the @ specifier. By default, the @apache-mynewt-core repository is included in every project. Apache Mynewt Core contains all the base functionality of the Apache Mynewt Operating System, including the Real Time Kernel, Bluetooth Networking Stack, Flash File System, Console, Shell and Bootloader. NOTE: Any project can be converted into a repository by providing it with a repository.yml file and putting it up onto Github. More information about repositories can be found in the Newt documentation. Package A package is a collection items that form a fundamental unit in the Mynewt Operating System. Packages can be: Applications Libraries Compiler definitions Targets A package is identified by having a pkg.yml file in it's base directory. Here is a sample pkg.yml file for the blinky applicaton: $ more pkg.yml <snip> pkg.name: apps/blinky pkg.type: app pkg.description: Basic example application which blinks an LED. pkg.author: \"Apache Mynewt <dev@mynewt.incubator.apache.org>\" pkg.homepage: \"http://mynewt.apache.org/\" pkg.keywords: pkg.deps: - \"@apache-mynewt-core/libs/os\" - \"@apache-mynewt-core/hw/hal\" - \"@apache-mynewt-core/libs/console/full\" Packages have a few features worth noting: Dependencies: Packages can rely upon other packages, and when they do they will inherit their functionality (header files, library definitions, etc.) APIs: Packages can export named APIs, and they can require that certain APIs be present, in order to compile. Features: Packages can operate differently depending on what named features are present in the system. Packages can also export features to the rest of the Mynewt system. Everything that newt knows about within a project's directory is a package. This makes it very clean and easy to write re-usable components, which can describe their Dependencies and APIs to the rest of the system. Target A target in Apache Mynewt is very similar to a target in make . It is the collection of parameters that must be passed to Newt in order to generate a reproducible build. A target represents the top of the build tree, and any packages or parameters specified at the target level, cascade down to all dependencies. Targets are also packages, and are stored in the targets/ directory at the base of your project. Most targets consist of: app : The application to build. bsp : The board support package to combine with that application build_profile : Either debug or optimized . Targets can also have additional items specified, including: cflags : Any additional compiler flags you might want to specify to the build. features : Any system level features you want to enable. In order to create and manipulate targets, the newt tool offers a set of helper commands, you can find more information about these by issuing: $ newt target Usage: newt target [flags] newt target [command] Available Commands: show View target configuration variables set Set target configuration variable create Create a target delete Delete target copy Copy target vars Show variable names Flags: -h, --help=false: help for target Global Flags: -l, --loglevel=\"WARN\": Log level, defaults to WARN. -o, --outfile=\"\": Filename to tee log output to -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands. Additional help topics: Use \"newt help [command]\" for more information about a command. $","title":"Concepts"},{"location":"os/get_started/vocabulary/#concepts","text":"This page is meant to introduce you to some of the concepts inherent to the Apache Mynewt Operating System, and Newt the tool that stitches a project built on Apache Mynewt together.","title":"Concepts"},{"location":"os/get_started/vocabulary/#project","text":"The project is the base directory of your embedded software tree. It is a workspace that contains a logical collection of source code, for one or more of your applications. A project consists of the following items: Project Definition: defines project level dependencies, and parameters (located in project.yml ) Packages Packages are described in detail in the section below. Here is an example project definition file from the default Apache Mynewt project: $ more project.yml <snip> project.name: \"my_project\" project.repositories: - apache-mynewt-core # Use github's distribution mechanism for core ASF libraries. # This provides mirroring automatically for us. # repository.apache-mynewt-core: type: github vers: 0-latest user: apache repo: incubator-mynewt-core $ A couple of things to note in the project definition: project.repositories : Defines the remote repositories that this project relies upon. repository.apache-mynewt-core : Defines the repository information for the apache-mynewt-core repository. Repositories are versioned collections of packages. Projects can rely on remote repositories for functionality, and the newt tool will resolve those remote repositories, and download the correct version into your local source tree. Newly fetched repositories are put in the repos directory of your project, and can be referenced throughout the system by using the @ specifier. By default, the @apache-mynewt-core repository is included in every project. Apache Mynewt Core contains all the base functionality of the Apache Mynewt Operating System, including the Real Time Kernel, Bluetooth Networking Stack, Flash File System, Console, Shell and Bootloader. NOTE: Any project can be converted into a repository by providing it with a repository.yml file and putting it up onto Github. More information about repositories can be found in the Newt documentation.","title":"Project"},{"location":"os/get_started/vocabulary/#package","text":"A package is a collection items that form a fundamental unit in the Mynewt Operating System. Packages can be: Applications Libraries Compiler definitions Targets A package is identified by having a pkg.yml file in it's base directory. Here is a sample pkg.yml file for the blinky applicaton: $ more pkg.yml <snip> pkg.name: apps/blinky pkg.type: app pkg.description: Basic example application which blinks an LED. pkg.author: \"Apache Mynewt <dev@mynewt.incubator.apache.org>\" pkg.homepage: \"http://mynewt.apache.org/\" pkg.keywords: pkg.deps: - \"@apache-mynewt-core/libs/os\" - \"@apache-mynewt-core/hw/hal\" - \"@apache-mynewt-core/libs/console/full\" Packages have a few features worth noting: Dependencies: Packages can rely upon other packages, and when they do they will inherit their functionality (header files, library definitions, etc.) APIs: Packages can export named APIs, and they can require that certain APIs be present, in order to compile. Features: Packages can operate differently depending on what named features are present in the system. Packages can also export features to the rest of the Mynewt system. Everything that newt knows about within a project's directory is a package. This makes it very clean and easy to write re-usable components, which can describe their Dependencies and APIs to the rest of the system.","title":"Package"},{"location":"os/get_started/vocabulary/#target","text":"A target in Apache Mynewt is very similar to a target in make . It is the collection of parameters that must be passed to Newt in order to generate a reproducible build. A target represents the top of the build tree, and any packages or parameters specified at the target level, cascade down to all dependencies. Targets are also packages, and are stored in the targets/ directory at the base of your project. Most targets consist of: app : The application to build. bsp : The board support package to combine with that application build_profile : Either debug or optimized . Targets can also have additional items specified, including: cflags : Any additional compiler flags you might want to specify to the build. features : Any system level features you want to enable. In order to create and manipulate targets, the newt tool offers a set of helper commands, you can find more information about these by issuing: $ newt target Usage: newt target [flags] newt target [command] Available Commands: show View target configuration variables set Set target configuration variable create Create a target delete Delete target copy Copy target vars Show variable names Flags: -h, --help=false: help for target Global Flags: -l, --loglevel=\"WARN\": Log level, defaults to WARN. -o, --outfile=\"\": Filename to tee log output to -q, --quiet=false: Be quiet; only display error output. -s, --silent=false: Be silent; don't output anything. -v, --verbose=false: Enable verbose output when executing commands. Additional help topics: Use \"newt help [command]\" for more information about a command. $","title":"Target"},{"location":"os/modules/baselibc/","text":"Baselibc Baselibc is a very simple libc for embedded systems geared primarily for 32-bit microcontrollers in the 10-100kB memory range. The library of basic system calls and facilities compiles to less than 5kB total on Cortex-M3, and much less if some functions aren't used. The code is based on klibc and tinyprintf modules, and licensed under the BSD license. Baselibc comes from https://github.com/PetteriAimonen/Baselibc.git Description Mynewt OS can utilize libc which comes with compiler (e.g. newlib bundled with some binary distributions of arm-none-eabi-gcc). However, you may choose to replace the libc with baselibc for a reduced image size. Baselibc optimizes for size rather than performance, which is usually a more important goal in embedded environments. How to switch to baselibc In order to switch from using libc to using baselibc you have to add the baselibc pkg as a dependency in the project pkg. Specifying this dependency ensures that the linker first looks for the functions in baselibc before falling back to libc while creating the executable. For example, project boot uses baselibc. Its project description file boot.yml looks like the following: no-highlight project.name: boot project.identities: bootloader project.pkgs: - libs/os - libs/bootutil - libs/nffs - libs/console/stub - libs/util - libs/baselibc List of Functions Documentation for libc functions is available from multiple places. One example are the on-line manual pages at https://www.freebsd.org/cgi/man.cgi . baselibc supports most libc functionality; malloc(), printf-family, string handling, and conversion routines. There is some functionality which is not available, e.g. support for floating point numbers, and limited support for 'long long'.","title":"Baselibc library"},{"location":"os/modules/baselibc/#baselibc","text":"Baselibc is a very simple libc for embedded systems geared primarily for 32-bit microcontrollers in the 10-100kB memory range. The library of basic system calls and facilities compiles to less than 5kB total on Cortex-M3, and much less if some functions aren't used. The code is based on klibc and tinyprintf modules, and licensed under the BSD license. Baselibc comes from https://github.com/PetteriAimonen/Baselibc.git","title":"Baselibc"},{"location":"os/modules/baselibc/#description","text":"Mynewt OS can utilize libc which comes with compiler (e.g. newlib bundled with some binary distributions of arm-none-eabi-gcc). However, you may choose to replace the libc with baselibc for a reduced image size. Baselibc optimizes for size rather than performance, which is usually a more important goal in embedded environments.","title":"Description"},{"location":"os/modules/baselibc/#how-to-switch-to-baselibc","text":"In order to switch from using libc to using baselibc you have to add the baselibc pkg as a dependency in the project pkg. Specifying this dependency ensures that the linker first looks for the functions in baselibc before falling back to libc while creating the executable. For example, project boot uses baselibc. Its project description file boot.yml looks like the following: no-highlight project.name: boot project.identities: bootloader project.pkgs: - libs/os - libs/bootutil - libs/nffs - libs/console/stub - libs/util - libs/baselibc","title":"How to switch to baselibc"},{"location":"os/modules/baselibc/#list-of-functions","text":"Documentation for libc functions is available from multiple places. One example are the on-line manual pages at https://www.freebsd.org/cgi/man.cgi . baselibc supports most libc functionality; malloc(), printf-family, string handling, and conversion routines. There is some functionality which is not available, e.g. support for floating point numbers, and limited support for 'long long'.","title":"List of Functions"},{"location":"os/modules/newtmgr/","text":"Bootloader Insert synopsis here Description Describe module here, special features, how pieces fit together etc. Data structures Replace this with the list of data structures used, why, any neat features List of Functions The functions available in this OS feature are: boot_slot_addr boot_find_image_slot add the rest Function Reference boot_slot_addr static void boot_slot_addr(int slot_num, uint8_t *flash_id, uint32_t *address) Arguments Arguments Description xx explain argument xx yy explain argument yy Returned values List any values returned. Error codes? Notes Any special feature/special benefit that we want to tout. Does it need to be used with some other specific functions? Any caveats to be careful about (e.g. high memory requirements). Example <Insert the code snippet here> boot_find_image_slot <Insert function callout here > Arguments Arguments Description xx explain argument xx yy explain argument yy Returned values List any values returned. Error codes? Notes Any special feature/special benefit that we want to tout. Does it need to be used with some other specific functions? Any caveats to be careful about (e.g. high memory requirements). Example <Insert the code snippet here> next_one <Insert function callout here > Arguments Arguments Description xx explain argument xx yy explain argument yy Returned values List any values returned. Error codes? Notes Any special feature/special benefit that we want to tout. Does it need to be used with some other specific functions? Any caveats to be careful about (e.g. high memory requirements). Example <Insert the code snippet here>","title":"Bootloader"},{"location":"os/modules/newtmgr/#bootloader","text":"Insert synopsis here","title":"Bootloader"},{"location":"os/modules/newtmgr/#description","text":"Describe module here, special features, how pieces fit together etc.","title":"Description"},{"location":"os/modules/newtmgr/#data-structures","text":"Replace this with the list of data structures used, why, any neat features","title":"Data structures"},{"location":"os/modules/newtmgr/#list-of-functions","text":"The functions available in this OS feature are: boot_slot_addr boot_find_image_slot add the rest","title":"List of Functions"},{"location":"os/modules/newtmgr/#function-reference","text":"","title":"Function Reference"},{"location":"os/modules/newtmgr/#boot_slot_addr","text":"static void boot_slot_addr(int slot_num, uint8_t *flash_id, uint32_t *address)","title":" boot_slot_addr "},{"location":"os/modules/newtmgr/#arguments","text":"Arguments Description xx explain argument xx yy explain argument yy","title":"Arguments"},{"location":"os/modules/newtmgr/#returned-values","text":"List any values returned. Error codes?","title":"Returned values"},{"location":"os/modules/newtmgr/#notes","text":"Any special feature/special benefit that we want to tout. Does it need to be used with some other specific functions? Any caveats to be careful about (e.g. high memory requirements).","title":"Notes"},{"location":"os/modules/newtmgr/#example","text":"<Insert the code snippet here>","title":"Example"},{"location":"os/modules/newtmgr/#boot_find_image_slot","text":"<Insert function callout here >","title":" boot_find_image_slot "},{"location":"os/modules/newtmgr/#arguments_1","text":"Arguments Description xx explain argument xx yy explain argument yy","title":"Arguments"},{"location":"os/modules/newtmgr/#returned-values_1","text":"List any values returned. Error codes?","title":"Returned values"},{"location":"os/modules/newtmgr/#notes_1","text":"Any special feature/special benefit that we want to tout. Does it need to be used with some other specific functions? Any caveats to be careful about (e.g. high memory requirements).","title":"Notes"},{"location":"os/modules/newtmgr/#example_1","text":"<Insert the code snippet here>","title":"Example"},{"location":"os/modules/newtmgr/#next_one","text":"<Insert function callout here >","title":" next_one "},{"location":"os/modules/newtmgr/#arguments_2","text":"Arguments Description xx explain argument xx yy explain argument yy","title":"Arguments"},{"location":"os/modules/newtmgr/#returned-values_2","text":"List any values returned. Error codes?","title":"Returned values"},{"location":"os/modules/newtmgr/#notes_2","text":"Any special feature/special benefit that we want to tout. Does it need to be used with some other specific functions? Any caveats to be careful about (e.g. high memory requirements).","title":"Notes"},{"location":"os/modules/newtmgr/#example_2","text":"<Insert the code snippet here>","title":"Example"},{"location":"os/modules/bootloader/boot_build_status/","text":"","title":"boot_build_status"},{"location":"os/modules/bootloader/boot_build_status_one/","text":"","title":"boot_build_status_one"},{"location":"os/modules/bootloader/boot_clear_status/","text":"","title":"boot_clear_status"},{"location":"os/modules/bootloader/boot_copy_area/","text":"","title":"boot_copy_area"},{"location":"os/modules/bootloader/boot_copy_image/","text":"","title":"boot_copy_image"},{"location":"os/modules/bootloader/boot_erase_area/","text":"","title":"boot_erase_area"},{"location":"os/modules/bootloader/boot_fill_slot/","text":"","title":"boot_fill_slot"},{"location":"os/modules/bootloader/boot_find_image_area_idx/","text":"","title":"boot_find_image_area_idx"},{"location":"os/modules/bootloader/boot_find_image_part/","text":"","title":"boot_find_image_part"},{"location":"os/modules/bootloader/boot_find_image_slot/","text":"","title":"boot_find_image_slot"},{"location":"os/modules/bootloader/boot_go/","text":"","title":"boot_go"},{"location":"os/modules/bootloader/boot_init_flash/","text":"","title":"boot_init_flash"},{"location":"os/modules/bootloader/boot_move_area/","text":"","title":"boot_move_area"},{"location":"os/modules/bootloader/boot_read_image_header/","text":"","title":"boot_read_image_header"},{"location":"os/modules/bootloader/boot_read_image_headers/","text":"","title":"boot_read_image_headers"},{"location":"os/modules/bootloader/boot_read_status/","text":"","title":"boot_read_status"},{"location":"os/modules/bootloader/boot_select_image_slot/","text":"","title":"boot_select_image_slot"},{"location":"os/modules/bootloader/boot_slot_addr/","text":"","title":"boot_slot_addr"},{"location":"os/modules/bootloader/boot_slot_to_area_idx/","text":"","title":"boot_slot_to_area_idx"},{"location":"os/modules/bootloader/boot_swap_areas/","text":"","title":"boot_swap_areas"},{"location":"os/modules/bootloader/boot_vect_delete_main/","text":"","title":"boot_vect_delete_main"},{"location":"os/modules/bootloader/boot_vect_delete_test/","text":"","title":"boot_vect_delete_test"},{"location":"os/modules/bootloader/boot_vect_read_main/","text":"","title":"boot_vect_read_main"},{"location":"os/modules/bootloader/boot_vect_read_one/","text":"","title":"boot_vect_read_one"},{"location":"os/modules/bootloader/boot_vect_read_test/","text":"","title":"boot_vect_read_test"},{"location":"os/modules/bootloader/boot_write_status/","text":"","title":"boot_write_status"},{"location":"os/modules/bootloader/bootloader/","text":"Bootloader Insert synopsis here Description Describe module here, special features, how pieces fit together etc. Data structures Replace this with the list of data structures used, why, any neat features List of Functions The functions available in bootloader are: boot_build_status boot_build_status_one boot_clear_status boot_copy_area boot_copy_image boot_erase_area boot_fill_slot boot_find_image_area_idx boot_find_image_part boot_find_image_slot boot_go boot_init_flash boot_move_area boot_read_image_header boot_read_image_headers boot_read_status boot_select_image_slot boot_slot_addr boot_slot_to_area_idx boot_swap_areas boot_vect_delete_main boot_vect_delete_test boot_vect_read_main boot_vect_read_one boot_vect_read_test boot_write_status","title":"toc"},{"location":"os/modules/bootloader/bootloader/#bootloader","text":"Insert synopsis here","title":"Bootloader"},{"location":"os/modules/bootloader/bootloader/#description","text":"Describe module here, special features, how pieces fit together etc.","title":"Description"},{"location":"os/modules/bootloader/bootloader/#data-structures","text":"Replace this with the list of data structures used, why, any neat features","title":"Data structures"},{"location":"os/modules/bootloader/bootloader/#list-of-functions","text":"The functions available in bootloader are: boot_build_status boot_build_status_one boot_clear_status boot_copy_area boot_copy_image boot_erase_area boot_fill_slot boot_find_image_area_idx boot_find_image_part boot_find_image_slot boot_go boot_init_flash boot_move_area boot_read_image_header boot_read_image_headers boot_read_status boot_select_image_slot boot_slot_addr boot_slot_to_area_idx boot_swap_areas boot_vect_delete_main boot_vect_delete_test boot_vect_read_main boot_vect_read_one boot_vect_read_test boot_write_status","title":"List of Functions"},{"location":"os/modules/console/console/","text":"Console The console is an operating system window where users interact with system programs of the operating system or a console application by entering text input (typically from a keyboard) and reading text output (typically on the computer terminal or monitor). The text written on the console brings some information and is a sequence of characters sent by the OS or programs running on the OS. Support is currently available for console access via the serial port on the hardware board. Description In the Mynewt OS, the console library comes in two versions: full - containing the full implementation stub - containing stubs for the API Both of these have pkg.yml file which states that they provide the console API. If a pkg uses this API, it should list console as a requirement. For example, the shell pkg is defined by the following pkg.yml file: pkg.name: libs/shell pkg.vers: 0.1 pkg.deps: - libs/os - libs/util pkg.reqs: - console pkg.identities: - SHELL The project .yml file decides which version of the console pkg should be included. If project requires the full console capability it lists dependency libs/console/full in its pkg.yml file. On the other hand, a project may not have a physical console (e.g. a UART port to connect a terminal to) but may have a dependency on a pkg that has console capability. In that case you would use a console stub. Another example would be the bootloader project where we want to keep the size of the image small. It includes the libs/os pkg that can print out messages on a console (e.g. if there is a hard fault) and the libs/util pkg that uses full console (but only if SHELL is present to provide a CLI). However, we do not want to use any console I/O capability in this particular bootloader project to keep the size small. We simply use the console stub instead, and the pkg.yml file for the project boot pkg looks like the following: project.name: boot project.identities: bootloader project.pkgs: - libs/os - libs/bootutil - libs/nffs - libs/console/stub - libs/util Console has 2 modes for transmit; blocking mode and non-blocking mode . Usually the non-blocking mode is the active one; the output buffer is drained by getting TX completion interrupts from hardware, and more data is added based on these interrupts. Blocking mode is used when we don't want TX completion interrupts. It is used when system crashes, and we still want to output info related to that crash. Console, by default, echoes everything it receives back. Terminal programs expect this, and is a way for the user to know that the console is connected and responsive. Whether echoing happens or not can be controlled programmatically. Data structures N/A List of Functions The functions available in console are: Function Description console_blocking_mode Calls the console_blocking_tx function to flush the buffered console output (transmit) queue. console_echo Controls whether echoing is on or off for the console. console_init Initialize the console. console_is_init Returns whether console has been initialized or not. console_printf Writes a formatted message instead of raw output to the console. console_read Copies up the to given number of bytes to the input string. console_write Queues characters to console display over serial port.","title":"toc"},{"location":"os/modules/console/console/#console","text":"The console is an operating system window where users interact with system programs of the operating system or a console application by entering text input (typically from a keyboard) and reading text output (typically on the computer terminal or monitor). The text written on the console brings some information and is a sequence of characters sent by the OS or programs running on the OS. Support is currently available for console access via the serial port on the hardware board.","title":"Console"},{"location":"os/modules/console/console/#description","text":"In the Mynewt OS, the console library comes in two versions: full - containing the full implementation stub - containing stubs for the API Both of these have pkg.yml file which states that they provide the console API. If a pkg uses this API, it should list console as a requirement. For example, the shell pkg is defined by the following pkg.yml file: pkg.name: libs/shell pkg.vers: 0.1 pkg.deps: - libs/os - libs/util pkg.reqs: - console pkg.identities: - SHELL The project .yml file decides which version of the console pkg should be included. If project requires the full console capability it lists dependency libs/console/full in its pkg.yml file. On the other hand, a project may not have a physical console (e.g. a UART port to connect a terminal to) but may have a dependency on a pkg that has console capability. In that case you would use a console stub. Another example would be the bootloader project where we want to keep the size of the image small. It includes the libs/os pkg that can print out messages on a console (e.g. if there is a hard fault) and the libs/util pkg that uses full console (but only if SHELL is present to provide a CLI). However, we do not want to use any console I/O capability in this particular bootloader project to keep the size small. We simply use the console stub instead, and the pkg.yml file for the project boot pkg looks like the following: project.name: boot project.identities: bootloader project.pkgs: - libs/os - libs/bootutil - libs/nffs - libs/console/stub - libs/util Console has 2 modes for transmit; blocking mode and non-blocking mode . Usually the non-blocking mode is the active one; the output buffer is drained by getting TX completion interrupts from hardware, and more data is added based on these interrupts. Blocking mode is used when we don't want TX completion interrupts. It is used when system crashes, and we still want to output info related to that crash. Console, by default, echoes everything it receives back. Terminal programs expect this, and is a way for the user to know that the console is connected and responsive. Whether echoing happens or not can be controlled programmatically.","title":"Description"},{"location":"os/modules/console/console/#data-structures","text":"N/A","title":"Data structures"},{"location":"os/modules/console/console/#list-of-functions","text":"The functions available in console are: Function Description console_blocking_mode Calls the console_blocking_tx function to flush the buffered console output (transmit) queue. console_echo Controls whether echoing is on or off for the console. console_init Initialize the console. console_is_init Returns whether console has been initialized or not. console_printf Writes a formatted message instead of raw output to the console. console_read Copies up the to given number of bytes to the input string. console_write Queues characters to console display over serial port.","title":"List of Functions"},{"location":"os/modules/console/console_blocking_mode/","text":"console_blocking_mode void console_blocking_mode(void) Calls the console_blocking_tx function to flush the buffered console output (transmit) queue. The function OS_ENTER_CRITICAL() is called to disable interrupts and OS_EXIT_CRITICAL() is called to enable interrupts back again once the buffer is flushed. Arguments None Returned values N/A Example Here is an example of calling console_blocking_mode and printing crash information from an assert to help debug. void _assert_func(const char *file, int line, const char *func, const char *e) { int sr; OS_ENTER_CRITICAL(sr); (void)sr; os_die_line = line; os_die_module = file; console_blocking_mode(); console_printf(\"Assert %s; failed in %s:%d\\n\", e ? e : \"\", file, line); system_reset(); }","title":"console_blocking_mode"},{"location":"os/modules/console/console_blocking_mode/#console_blocking_mode","text":"void console_blocking_mode(void) Calls the console_blocking_tx function to flush the buffered console output (transmit) queue. The function OS_ENTER_CRITICAL() is called to disable interrupts and OS_EXIT_CRITICAL() is called to enable interrupts back again once the buffer is flushed.","title":" console_blocking_mode "},{"location":"os/modules/console/console_blocking_mode/#arguments","text":"None","title":"Arguments"},{"location":"os/modules/console/console_blocking_mode/#returned-values","text":"N/A","title":"Returned values"},{"location":"os/modules/console/console_blocking_mode/#example","text":"Here is an example of calling console_blocking_mode and printing crash information from an assert to help debug. void _assert_func(const char *file, int line, const char *func, const char *e) { int sr; OS_ENTER_CRITICAL(sr); (void)sr; os_die_line = line; os_die_module = file; console_blocking_mode(); console_printf(\"Assert %s; failed in %s:%d\\n\", e ? e : \"\", file, line); system_reset(); }","title":"Example"},{"location":"os/modules/console/console_echo/","text":"console_echo void console_echo(int on) Controls whether echoing is on or off for the console. When echoing is on, all characters received are transmitted back. Arguments Arguments Description on 1 turns on echoing, 0 turns it off Returned values None Notes Example Here is an example where newtmgr protocol handler is controlling whether echoing is on or off. Newtmgr, the tool, turns echoing off when it's transmitting large chunks of data to target board. static int nmgr_def_console_echo(struct nmgr_jbuf *njb) { int echo_on = 1; int rc; struct json_attr_t attrs[3] = { [0] = { .attribute = \"echo\", .type = t_integer, .addr.integer = &echo_on, .nodefault = 1 }, [1] = { .attribute = NULL } }; rc = json_read_object(&njb->njb_buf, attrs); if (rc) { return OS_EINVAL; } if (echo_on) { console_echo(1); } else { console_echo(0); } return (0); }","title":"console_echo"},{"location":"os/modules/console/console_echo/#console_echo","text":"void console_echo(int on) Controls whether echoing is on or off for the console. When echoing is on, all characters received are transmitted back.","title":" console_echo "},{"location":"os/modules/console/console_echo/#arguments","text":"Arguments Description on 1 turns on echoing, 0 turns it off","title":"Arguments"},{"location":"os/modules/console/console_echo/#returned-values","text":"None","title":"Returned values"},{"location":"os/modules/console/console_echo/#notes","text":"","title":"Notes"},{"location":"os/modules/console/console_echo/#example","text":"Here is an example where newtmgr protocol handler is controlling whether echoing is on or off. Newtmgr, the tool, turns echoing off when it's transmitting large chunks of data to target board. static int nmgr_def_console_echo(struct nmgr_jbuf *njb) { int echo_on = 1; int rc; struct json_attr_t attrs[3] = { [0] = { .attribute = \"echo\", .type = t_integer, .addr.integer = &echo_on, .nodefault = 1 }, [1] = { .attribute = NULL } }; rc = json_read_object(&njb->njb_buf, attrs); if (rc) { return OS_EINVAL; } if (echo_on) { console_echo(1); } else { console_echo(0); } return (0); }","title":"Example"},{"location":"os/modules/console/console_init/","text":"console_init int console_init(console_rx_cb rx_cb) Initializes console receive buffer and calls hal funtions hal_uart_init_cbs and hal_uart_config to initialize serial port connection and configure it (e.g. baud rate, flow control etc.) Caller registers a function pointer of type void (*console_rx_cb)(int full_line) . This function will be called when console receives either a) full line of data or b) when RX buffer in console is full. Note that this function is most likely getting called from interrupt context. Arguments Arguments Description rx_cb Function pointer, which gets called input is received. Returned values Returns 0 on success. Non-zero if HAL UART function calls fail. Example int main(int argc, char **argv) { .... /* Init tasks */ shell_task_init(SHELL_TASK_PRIO, shell_stack, SHELL_TASK_STACK_SIZE, SHELL_MAX_INPUT_LEN); console_init(shell_console_rx_cb); .... }","title":"console_init"},{"location":"os/modules/console/console_init/#console_init","text":"int console_init(console_rx_cb rx_cb) Initializes console receive buffer and calls hal funtions hal_uart_init_cbs and hal_uart_config to initialize serial port connection and configure it (e.g. baud rate, flow control etc.) Caller registers a function pointer of type void (*console_rx_cb)(int full_line) . This function will be called when console receives either a) full line of data or b) when RX buffer in console is full. Note that this function is most likely getting called from interrupt context.","title":" console_init "},{"location":"os/modules/console/console_init/#arguments","text":"Arguments Description rx_cb Function pointer, which gets called input is received.","title":"Arguments"},{"location":"os/modules/console/console_init/#returned-values","text":"Returns 0 on success. Non-zero if HAL UART function calls fail.","title":"Returned values"},{"location":"os/modules/console/console_init/#example","text":"int main(int argc, char **argv) { .... /* Init tasks */ shell_task_init(SHELL_TASK_PRIO, shell_stack, SHELL_TASK_STACK_SIZE, SHELL_MAX_INPUT_LEN); console_init(shell_console_rx_cb); .... }","title":"Example"},{"location":"os/modules/console/console_is_init/","text":"console_is_init int console_is_init(void) Returns whether console has been initialized or not. I.e. whether console_init() has been called yet. Arguments None Returned values Returns 1 if console has been initialized. 0 if not. Example static int log_console_append(struct log *log, void *buf, int len) { .... if (!console_is_init()) { return (0); } /* print log entry to console */ .... }","title":"console_is_init"},{"location":"os/modules/console/console_is_init/#console_is_init","text":"int console_is_init(void) Returns whether console has been initialized or not. I.e. whether console_init() has been called yet.","title":" console_is_init "},{"location":"os/modules/console/console_is_init/#arguments","text":"None","title":"Arguments"},{"location":"os/modules/console/console_is_init/#returned-values","text":"Returns 1 if console has been initialized. 0 if not.","title":"Returned values"},{"location":"os/modules/console/console_is_init/#example","text":"static int log_console_append(struct log *log, void *buf, int len) { .... if (!console_is_init()) { return (0); } /* print log entry to console */ .... }","title":"Example"},{"location":"os/modules/console/console_printf/","text":"console_printf void console_printf(const char *fmt, ...) Writes a formatted message instead of raw output to the console. It first composes a C string containing text specified as arguments to the function or containing the elements in the variable argument list passed to it using snprintf or vsnprintf, respectively. It then uses function console_write to output the formatted data (messages) on the console. Arguments Arguments Description fmt Pointer to C string that contains a format string that follows the same specifications as format in printf. The string is printed to console. ... Depending on the format string, the function may expect either a sequence of additional arguments to be used to replace a format specifier in the format string or a variable arguments list. va_list is a special type defined in in stdarg.h. Returned values None Notes While console_printf , with its well understood formatting options in C, is more convenient and easy on the eyes than the raw output of console_write , the associated code size is considerably larger. Example Example #1: char adv_data_buf[32]; void task() { char adv_data_buf[32]; console_printf(\"%s\", adv_data_buf); } Example #2: struct exception_frame { uint32_t r0; uint32_t r1; struct trap_frame { struct exception_frame *ef; uint32_t r2; uint32_t r3; }; void task(struct trap_frame *tf) { console_printf(\" r0:%8.8x r1:%8.8x\", tf->ef->r0, tf->ef->r1); console_printf(\" r8:%8.8x r9:%8.8x\", tf->r2, tf->r3); }","title":"console_printf"},{"location":"os/modules/console/console_printf/#console_printf","text":"void console_printf(const char *fmt, ...) Writes a formatted message instead of raw output to the console. It first composes a C string containing text specified as arguments to the function or containing the elements in the variable argument list passed to it using snprintf or vsnprintf, respectively. It then uses function console_write to output the formatted data (messages) on the console.","title":" console_printf"},{"location":"os/modules/console/console_printf/#arguments","text":"Arguments Description fmt Pointer to C string that contains a format string that follows the same specifications as format in printf. The string is printed to console. ... Depending on the format string, the function may expect either a sequence of additional arguments to be used to replace a format specifier in the format string or a variable arguments list. va_list is a special type defined in in stdarg.h.","title":"Arguments"},{"location":"os/modules/console/console_printf/#returned-values","text":"None","title":"Returned values"},{"location":"os/modules/console/console_printf/#notes","text":"While console_printf , with its well understood formatting options in C, is more convenient and easy on the eyes than the raw output of console_write , the associated code size is considerably larger.","title":"Notes"},{"location":"os/modules/console/console_printf/#example","text":"Example #1: char adv_data_buf[32]; void task() { char adv_data_buf[32]; console_printf(\"%s\", adv_data_buf); } Example #2: struct exception_frame { uint32_t r0; uint32_t r1; struct trap_frame { struct exception_frame *ef; uint32_t r2; uint32_t r3; }; void task(struct trap_frame *tf) { console_printf(\" r0:%8.8x r1:%8.8x\", tf->ef->r0, tf->ef->r1); console_printf(\" r8:%8.8x r9:%8.8x\", tf->r2, tf->r3); }","title":"Example"},{"location":"os/modules/console/console_read/","text":"console_read int console_read(char *str, int cnt) Copies up to cnt bytes of received data to buffer pointed by str . Function tries to break the input into separate lines; once it encounters a newline character, it replaces that with end-of-string and returns. Arguments Arguments Description str Buffer where data is copied to. cnt Maximum number of characters to copy. Returned values Returns the number of characters copied. 0 if there was no data available, or if the first received character was '\\n'. Example void task1_loop(void *arg) { struct os_event *ev; char rx_msg[128]; int rx_len; while (1) { ev = os_eventq_get(&task1_evq); assert(ev); if (ev->ev_type == CONS_EV_TYPE) { rx_len = console_read(rx_msg, sizeof(rx_msg)); if (rx_len) { if (!strncmp(rx_msg, \"reset\", rx_len)) { assert(0); }","title":"console_read"},{"location":"os/modules/console/console_read/#console_read","text":"int console_read(char *str, int cnt) Copies up to cnt bytes of received data to buffer pointed by str . Function tries to break the input into separate lines; once it encounters a newline character, it replaces that with end-of-string and returns.","title":" console_read "},{"location":"os/modules/console/console_read/#arguments","text":"Arguments Description str Buffer where data is copied to. cnt Maximum number of characters to copy.","title":"Arguments"},{"location":"os/modules/console/console_read/#returned-values","text":"Returns the number of characters copied. 0 if there was no data available, or if the first received character was '\\n'.","title":"Returned values"},{"location":"os/modules/console/console_read/#example","text":"void task1_loop(void *arg) { struct os_event *ev; char rx_msg[128]; int rx_len; while (1) { ev = os_eventq_get(&task1_evq); assert(ev); if (ev->ev_type == CONS_EV_TYPE) { rx_len = console_read(rx_msg, sizeof(rx_msg)); if (rx_len) { if (!strncmp(rx_msg, \"reset\", rx_len)) { assert(0); }","title":"Example"},{"location":"os/modules/console/console_write/","text":"console_write void console_write(char *str, int cnt) Queues characters to console display over serial port. Arguments Arguments Description *str pointer to the character or packet to be transmitted cnt number of characters in str Returned values N/A Example Here is an example of the function being used in an echo command with a newline at the end. static int shell_echo_cmd(int argc, char **argv) { int i; for (i = 1; i < argc; i++) { console_write(argv[i], strlen(argv[i])); console_write(\" \", sizeof(\" \")-1); } console_write(\"\\n\", sizeof(\"\\n\")-1); return (0); }","title":"console_write"},{"location":"os/modules/console/console_write/#console_write","text":"void console_write(char *str, int cnt) Queues characters to console display over serial port.","title":" console_write "},{"location":"os/modules/console/console_write/#arguments","text":"Arguments Description *str pointer to the character or packet to be transmitted cnt number of characters in str","title":"Arguments"},{"location":"os/modules/console/console_write/#returned-values","text":"N/A","title":"Returned values"},{"location":"os/modules/console/console_write/#example","text":"Here is an example of the function being used in an echo command with a newline at the end. static int shell_echo_cmd(int argc, char **argv) { int i; for (i = 1; i < argc; i++) { console_write(argv[i], strlen(argv[i])); console_write(\" \", sizeof(\" \")-1); } console_write(\"\\n\", sizeof(\"\\n\")-1); return (0); }","title":"Example"},{"location":"os/modules/elua/elua/","text":"elua Description This package contains a Lua interpreter. See http://lua.org for documentation of the language. You can execute lua scripts either from console with shell or start the execution programmatically. Data structures Notes Currently we don't have language extension modules which would go together with this one, but those should be added. List of Functions Function Description lua_init Registers 'lua' command with shell. lua_main Executes lua script in current task's context. Arguments given are passed to lua interpreter.","title":"toc"},{"location":"os/modules/elua/elua/#elua","text":"","title":"elua"},{"location":"os/modules/elua/elua/#description","text":"This package contains a Lua interpreter. See http://lua.org for documentation of the language. You can execute lua scripts either from console with shell or start the execution programmatically.","title":"Description"},{"location":"os/modules/elua/elua/#data-structures","text":"","title":"Data structures"},{"location":"os/modules/elua/elua/#notes","text":"Currently we don't have language extension modules which would go together with this one, but those should be added.","title":"Notes"},{"location":"os/modules/elua/elua/#list-of-functions","text":"Function Description lua_init Registers 'lua' command with shell. lua_main Executes lua script in current task's context. Arguments given are passed to lua interpreter.","title":"List of Functions"},{"location":"os/modules/elua/lua_init/","text":"lua_init int lua_init(void) Registers 'lua' command with shell. This function should be called while initializing the project, preferably after shell itself has been initialized. Arguments N/A Returned values Returns Notes Calling this is meaningful only if you include the shell package in your project. Example int main(int argc, char **argv) { ... shell_task_init(SHELL_TASK_PRIO, shell_stack, SHELL_TASK_STACK_SIZE, SHELL_MAX_INPUT_LEN); ... lua_init(); ... }","title":"lua_init"},{"location":"os/modules/elua/lua_init/#lua_init","text":"int lua_init(void) Registers 'lua' command with shell. This function should be called while initializing the project, preferably after shell itself has been initialized.","title":" lua_init "},{"location":"os/modules/elua/lua_init/#arguments","text":"N/A","title":"Arguments"},{"location":"os/modules/elua/lua_init/#returned-values","text":"Returns","title":"Returned values"},{"location":"os/modules/elua/lua_init/#notes","text":"Calling this is meaningful only if you include the shell package in your project.","title":"Notes"},{"location":"os/modules/elua/lua_init/#example","text":"int main(int argc, char **argv) { ... shell_task_init(SHELL_TASK_PRIO, shell_stack, SHELL_TASK_STACK_SIZE, SHELL_MAX_INPUT_LEN); ... lua_init(); ... }","title":"Example"},{"location":"os/modules/elua/lua_main/","text":"lua_main int lua_main(int argc, char **argv) Executes lua script in current task's context. Arguments given are passed to lua interpreter. Arguments Arguments Description argc Number of elements in argv array argv Array of character strings Returned values Returns the return code from the lua interpreter. Notes Example static int lua_cmd(int argc, char **argv) { lua_main(argc, argv); return 0; }","title":"lua_main"},{"location":"os/modules/elua/lua_main/#lua_main","text":"int lua_main(int argc, char **argv) Executes lua script in current task's context. Arguments given are passed to lua interpreter.","title":" lua_main "},{"location":"os/modules/elua/lua_main/#arguments","text":"Arguments Description argc Number of elements in argv array argv Array of character strings","title":"Arguments"},{"location":"os/modules/elua/lua_main/#returned-values","text":"Returns the return code from the lua interpreter.","title":"Returned values"},{"location":"os/modules/elua/lua_main/#notes","text":"","title":"Notes"},{"location":"os/modules/elua/lua_main/#example","text":"static int lua_cmd(int argc, char **argv) { lua_main(argc, argv); return 0; }","title":"Example"},{"location":"os/modules/fs/otherfs/","text":"Other File Systems Libraries use Mynewt's file system abstraction layer ( fs/fs ) for all file operations. Because clients use an abstraction layer, the underlying file system can be swapped out without affecting client code. This page documents the procedure for plugging a custom file system into the Mynewt file system abstraction layer. 1. Specify fs/fs as a dependency of your file system package. The file system package must register itself with the fs/fs package, so it must specify fs/fs as a dependency. As an example, part of the Newtron Flash File System (nffs) pkg.yml is reproduced below. Notice the first item in the pkg.deps list. pkg.name: fs/nffs pkg.deps: - fs/fs - hw/hal - libs/os - libs/testutil - sys/log 2. Register your package's API with the fs/fs interface. The fs/fs package calls into the underlying file system via a collection of function pointers. To plug your file system into the fs/fs API, you must assign these function pointers to the corresponding routines in your file system package. For example, nffs registers itself with fs/fs as follows (from fs/nffs/src/nffs.c ): static const struct fs_ops nffs_ops = { . f_open = nffs_open , . f_close = nffs_close , . f_read = nffs_read , . f_write = nffs_write , . f_seek = nffs_seek , . f_getpos = nffs_getpos , . f_filelen = nffs_file_len , . f_unlink = nffs_unlink , . f_rename = nffs_rename , . f_mkdir = nffs_mkdir , . f_opendir = nffs_opendir , . f_readdir = nffs_readdir , . f_closedir = nffs_closedir , . f_dirent_name = nffs_dirent_name , . f_dirent_is_dir = nffs_dirent_is_dir , . f_name = \"nffs\" }; int nffs_init ( void ) { /* [...] */ fs_register ( &nffs_ops ); } Header Files To gain access to fs/fs 's registration interface, include the following header: #include \"fs/fs_if.h\"","title":"Other File Systems"},{"location":"os/modules/fs/otherfs/#other-file-systems","text":"Libraries use Mynewt's file system abstraction layer ( fs/fs ) for all file operations. Because clients use an abstraction layer, the underlying file system can be swapped out without affecting client code. This page documents the procedure for plugging a custom file system into the Mynewt file system abstraction layer.","title":"Other File Systems"},{"location":"os/modules/fs/otherfs/#1-specify-fsfs-as-a-dependency-of-your-file-system-package","text":"The file system package must register itself with the fs/fs package, so it must specify fs/fs as a dependency. As an example, part of the Newtron Flash File System (nffs) pkg.yml is reproduced below. Notice the first item in the pkg.deps list. pkg.name: fs/nffs pkg.deps: - fs/fs - hw/hal - libs/os - libs/testutil - sys/log","title":"1. Specify fs/fs as a dependency of your file system package."},{"location":"os/modules/fs/otherfs/#2-register-your-packages-api-with-the-fsfs-interface","text":"The fs/fs package calls into the underlying file system via a collection of function pointers. To plug your file system into the fs/fs API, you must assign these function pointers to the corresponding routines in your file system package. For example, nffs registers itself with fs/fs as follows (from fs/nffs/src/nffs.c ): static const struct fs_ops nffs_ops = { . f_open = nffs_open , . f_close = nffs_close , . f_read = nffs_read , . f_write = nffs_write , . f_seek = nffs_seek , . f_getpos = nffs_getpos , . f_filelen = nffs_file_len , . f_unlink = nffs_unlink , . f_rename = nffs_rename , . f_mkdir = nffs_mkdir , . f_opendir = nffs_opendir , . f_readdir = nffs_readdir , . f_closedir = nffs_closedir , . f_dirent_name = nffs_dirent_name , . f_dirent_is_dir = nffs_dirent_is_dir , . f_name = \"nffs\" }; int nffs_init ( void ) { /* [...] */ fs_register ( &nffs_ops ); }","title":"2. Register your package's API with the fs/fs interface."},{"location":"os/modules/fs/otherfs/#header-files","text":"To gain access to fs/fs 's registration interface, include the following header: #include \"fs/fs_if.h\"","title":"Header Files"},{"location":"os/modules/fs/fs/fs/","text":"File System Abstraction Mynewt provides a file system abstraction layer ( fs/fs ) to allow client code to be file system agnostic. By accessing the file system via the fs/fs API, client code can perform file system operations without being tied to a particular implementation. When possible, library code should use the fs/fs API rather than accessing the underlying file system directly. Description Applications should aim to minimize the amount of code which depends on a particular file system implementation. When possible, only depend on the fs/fs package. In the simplest case, the only code which needs to know which file system is in use is the code which initializes the file system. In terms of the Mynewt hierarchy, the app package must depend on a specific file system package, while library packages should only depend on fs/fs . The following example illustrates how file system dependencies should be managed. In the slinky application, the app is responsible for initializing the file system, so it depends on a concrete file system package called fs/nffs (Newtron Flash File System). The app explicitly initializes nffs via calls to nffs_init() , nffs_detect() and nffs_format() . # repos/apache-mynewt-core/apps/slinky/pkg.yml pkg.name: repos/apache-mynewt-core/apps/slinky pkg.deps: - fs/nffs # [...] /* repos/apache-mynewt-core/apps/slinky/src/main.c */ #include \"nffs/nffs.h\" int main ( int argc , char **argv ) { int rc ; int cnt ; struct nffs_area_desc descs [ NFFS_AREA_MAX ]; rc = nffs_init (); assert ( rc == 0 ); cnt = NFFS_AREA_MAX ; rc = flash_area_to_nffs_desc ( FLASH_AREA_NFFS , &cnt , descs ); assert ( rc == 0 ); if ( nffs_detect ( descs ) == FS_ECORRUPT ) { rc = nffs_format ( descs ); assert ( rc == 0 ); } // [...] } On the other hand, code which uses the file system after it has been initialized need only depend on fs/fs . For example, the libs/imgmgr package is a library which provides firmware upload and download functionality via the use of a file system. This library is only used after the main app has initialized the file system, and therefore only depends on the fs/fs package. # repos/apache-mynewt-core/libs/imgmgr/pkg.yml pkg.name: libs/imgmgr pkg.deps: - fs/fs # [...] The libs/imgmgr package uses the fs/fs API for all file system operations. Thread Safety All fs/fs functions are thread safe. Header Files All code which uses the fs/fs package needs to include the following header: #include \"fs/fs.h\" Data Structures All fs/fs data structures are opaque to client code. struct fs_file ; struct fs_dir ; struct fs_dirent ; API Functions in fs/fs that indicate success or failure do so with the following set of return codes: Return Codes The functions available in this OS feature are: Function Description fs_close Closes the specified file and invalidates the file handle. fs_closedir Closes the specified directory handle. fs_dirent_is_dir Tells you whether the specified directory entry is a sub-directory or a regular file. fs_dirent_name Retrieves the filename of the specified directory entry. fs_filelen Retrieves the current length of the specified open file. fs_getpos Retrieves the current read and write position of the specified open file. fs_mkdir Creates the directory represented by the specified path. fs_open Opens a file at the specified path. fs_opendir Opens the directory at the specified path. fs_read Reads data from the specified file. fs_readdir Reads the next entry in an open directory. fs_register Registers a file system with the abstraction layer. fs_rename Performs a rename and/or move of the specified source path to the specified destination. fs_seek Positions a file's read and write pointer at the specified offset. fs_unlink Unlinks the file or directory at the specified path. fs_write Writes the supplied data to the current offset of the specified file handle. Additional file system utilities that bundle some of the basic functions above are: Function Description fsutil_read_file Opens a file at the specified path, retrieve data from the file starting from the specified offset, and close the file and invalidate the file handle. fsutil_write_file Open a file at the specified path, write the supplied data to the current offset of the specified file handle, and close the file and invalidate the file handle.","title":"toc"},{"location":"os/modules/fs/fs/fs/#file-system-abstraction","text":"Mynewt provides a file system abstraction layer ( fs/fs ) to allow client code to be file system agnostic. By accessing the file system via the fs/fs API, client code can perform file system operations without being tied to a particular implementation. When possible, library code should use the fs/fs API rather than accessing the underlying file system directly.","title":"File System Abstraction"},{"location":"os/modules/fs/fs/fs/#description","text":"Applications should aim to minimize the amount of code which depends on a particular file system implementation. When possible, only depend on the fs/fs package. In the simplest case, the only code which needs to know which file system is in use is the code which initializes the file system. In terms of the Mynewt hierarchy, the app package must depend on a specific file system package, while library packages should only depend on fs/fs . The following example illustrates how file system dependencies should be managed. In the slinky application, the app is responsible for initializing the file system, so it depends on a concrete file system package called fs/nffs (Newtron Flash File System). The app explicitly initializes nffs via calls to nffs_init() , nffs_detect() and nffs_format() . # repos/apache-mynewt-core/apps/slinky/pkg.yml pkg.name: repos/apache-mynewt-core/apps/slinky pkg.deps: - fs/nffs # [...] /* repos/apache-mynewt-core/apps/slinky/src/main.c */ #include \"nffs/nffs.h\" int main ( int argc , char **argv ) { int rc ; int cnt ; struct nffs_area_desc descs [ NFFS_AREA_MAX ]; rc = nffs_init (); assert ( rc == 0 ); cnt = NFFS_AREA_MAX ; rc = flash_area_to_nffs_desc ( FLASH_AREA_NFFS , &cnt , descs ); assert ( rc == 0 ); if ( nffs_detect ( descs ) == FS_ECORRUPT ) { rc = nffs_format ( descs ); assert ( rc == 0 ); } // [...] } On the other hand, code which uses the file system after it has been initialized need only depend on fs/fs . For example, the libs/imgmgr package is a library which provides firmware upload and download functionality via the use of a file system. This library is only used after the main app has initialized the file system, and therefore only depends on the fs/fs package. # repos/apache-mynewt-core/libs/imgmgr/pkg.yml pkg.name: libs/imgmgr pkg.deps: - fs/fs # [...] The libs/imgmgr package uses the fs/fs API for all file system operations.","title":"Description"},{"location":"os/modules/fs/fs/fs/#thread-safety","text":"All fs/fs functions are thread safe.","title":"Thread Safety"},{"location":"os/modules/fs/fs/fs/#header-files","text":"All code which uses the fs/fs package needs to include the following header: #include \"fs/fs.h\"","title":"Header Files"},{"location":"os/modules/fs/fs/fs/#data-structures","text":"All fs/fs data structures are opaque to client code. struct fs_file ; struct fs_dir ; struct fs_dirent ;","title":"Data Structures"},{"location":"os/modules/fs/fs/fs/#api","text":"Functions in fs/fs that indicate success or failure do so with the following set of return codes: Return Codes The functions available in this OS feature are: Function Description fs_close Closes the specified file and invalidates the file handle. fs_closedir Closes the specified directory handle. fs_dirent_is_dir Tells you whether the specified directory entry is a sub-directory or a regular file. fs_dirent_name Retrieves the filename of the specified directory entry. fs_filelen Retrieves the current length of the specified open file. fs_getpos Retrieves the current read and write position of the specified open file. fs_mkdir Creates the directory represented by the specified path. fs_open Opens a file at the specified path. fs_opendir Opens the directory at the specified path. fs_read Reads data from the specified file. fs_readdir Reads the next entry in an open directory. fs_register Registers a file system with the abstraction layer. fs_rename Performs a rename and/or move of the specified source path to the specified destination. fs_seek Positions a file's read and write pointer at the specified offset. fs_unlink Unlinks the file or directory at the specified path. fs_write Writes the supplied data to the current offset of the specified file handle. Additional file system utilities that bundle some of the basic functions above are: Function Description fsutil_read_file Opens a file at the specified path, retrieve data from the file starting from the specified offset, and close the file and invalidate the file handle. fsutil_write_file Open a file at the specified path, write the supplied data to the current offset of the specified file handle, and close the file and invalidate the file handle.","title":"API"},{"location":"os/modules/fs/fs/fs_close/","text":"fs_close int fs_close ( struct fs_file *file ) Closes the specified file and invalidates the file handle. Arguments Argument Description file Pointer to the file to close Returned values 0 on success FS error code on failure Notes If the file has already been unlinked, and the file has no other open handles, the fs_close() function causes the file to be deleted from the disk. Header file #include \"fs/fs.h\" Example The below code opens the file /settings/config.txt for reading, reads some data, and then closes the file. int read_config ( void ) { struct fs_file *file ; uint32_t bytes_read ; uint8_t buf [ 16 ]; int rc ; /* Open the file for reading. */ rc = fs_open ( \"/settings/config.txt\" , FS_ACCESS_READ , &file ); if ( rc != 0 ) { return -1 ; } /* Read up to 16 bytes from the file. */ rc = fs_read ( file , sizeof buf , buf , &bytes_read ); if ( rc == 0 ) { /* buf now contains up to 16 bytes of file data. */ console_printf ( \"read %u bytes\\n\" , bytes_read ) } /* Close the file. */ fs_close ( file ); return rc == 0 ? 0 : -1 ; }","title":"fs_close"},{"location":"os/modules/fs/fs/fs_close/#fs_close","text":"int fs_close ( struct fs_file *file ) Closes the specified file and invalidates the file handle.","title":"fs_close"},{"location":"os/modules/fs/fs/fs_close/#arguments","text":"Argument Description file Pointer to the file to close","title":"Arguments"},{"location":"os/modules/fs/fs/fs_close/#returned-values","text":"0 on success FS error code on failure","title":"Returned values"},{"location":"os/modules/fs/fs/fs_close/#notes","text":"If the file has already been unlinked, and the file has no other open handles, the fs_close() function causes the file to be deleted from the disk.","title":"Notes"},{"location":"os/modules/fs/fs/fs_close/#header-file","text":"#include \"fs/fs.h\"","title":"Header file"},{"location":"os/modules/fs/fs/fs_close/#example","text":"The below code opens the file /settings/config.txt for reading, reads some data, and then closes the file. int read_config ( void ) { struct fs_file *file ; uint32_t bytes_read ; uint8_t buf [ 16 ]; int rc ; /* Open the file for reading. */ rc = fs_open ( \"/settings/config.txt\" , FS_ACCESS_READ , &file ); if ( rc != 0 ) { return -1 ; } /* Read up to 16 bytes from the file. */ rc = fs_read ( file , sizeof buf , buf , &bytes_read ); if ( rc == 0 ) { /* buf now contains up to 16 bytes of file data. */ console_printf ( \"read %u bytes\\n\" , bytes_read ) } /* Close the file. */ fs_close ( file ); return rc == 0 ? 0 : -1 ; }","title":"Example"},{"location":"os/modules/fs/fs/fs_closedir/","text":"fs_closedir int fs_closedir ( struct fs_dir *dir ) Closes the specified directory handle. Arguments Argument Description dir The name of the directory to close Returned values 0 on success FS error code on failure Header file #include \"fs/fs.h\" Example This example iterates through the contents of a directory, printing the name of each child node. When the traversal is complete, the code closes the directory handle. int traverse_dir ( const char *dirname ) { struct fs_dirent *dirent ; struct fs_dir *dir ; char buf [ 64 ]; uint8_t name_len ; int rc ; rc = fs_opendir ( dirname , &dir ); if ( rc != 0 ) { return -1 ; } /* Iterate through the parent directory, printing the name of each child * entry. The loop only terminates via a function return. */ while ( 1 ) { /* Retrieve the next child node. */ rc = fs_readdir ( dir , &dirent ); if ( rc == FS_ENOENT ) { /* Traversal complete. */ return 0 ; } else if ( rc != 0 ) { /* Unexpected error. */ return -1 ; } /* Read the child node's name from the file system. */ rc = fs_dirent_name ( dirent , sizeof buf , buf , &name_len ); if ( rc != 0 ) { return -1 ; } /* Print the child node's name to the console. */ if ( fs_dirent_is_dir ( dirent )) { console_printf ( \" dir: \" ); } else { console_printf ( \"file: \" ); } console_printf ( \"%s\\n\" , buf ); } }","title":"fs_closedir"},{"location":"os/modules/fs/fs/fs_closedir/#fs_closedir","text":"int fs_closedir ( struct fs_dir *dir ) Closes the specified directory handle.","title":"fs_closedir"},{"location":"os/modules/fs/fs/fs_closedir/#arguments","text":"Argument Description dir The name of the directory to close","title":"Arguments"},{"location":"os/modules/fs/fs/fs_closedir/#returned-values","text":"0 on success FS error code on failure","title":"Returned values"},{"location":"os/modules/fs/fs/fs_closedir/#header-file","text":"#include \"fs/fs.h\"","title":"Header file"},{"location":"os/modules/fs/fs/fs_closedir/#example","text":"This example iterates through the contents of a directory, printing the name of each child node. When the traversal is complete, the code closes the directory handle. int traverse_dir ( const char *dirname ) { struct fs_dirent *dirent ; struct fs_dir *dir ; char buf [ 64 ]; uint8_t name_len ; int rc ; rc = fs_opendir ( dirname , &dir ); if ( rc != 0 ) { return -1 ; } /* Iterate through the parent directory, printing the name of each child * entry. The loop only terminates via a function return. */ while ( 1 ) { /* Retrieve the next child node. */ rc = fs_readdir ( dir , &dirent ); if ( rc == FS_ENOENT ) { /* Traversal complete. */ return 0 ; } else if ( rc != 0 ) { /* Unexpected error. */ return -1 ; } /* Read the child node's name from the file system. */ rc = fs_dirent_name ( dirent , sizeof buf , buf , &name_len ); if ( rc != 0 ) { return -1 ; } /* Print the child node's name to the console. */ if ( fs_dirent_is_dir ( dirent )) { console_printf ( \" dir: \" ); } else { console_printf ( \"file: \" ); } console_printf ( \"%s\\n\" , buf ); } }","title":"Example"},{"location":"os/modules/fs/fs/fs_dirent_is_dir/","text":"fs_dirent_is_dir int fs_dirent_is_dir ( const struct fs_dirent *dirent ) Tells you whether the specified directory entry is a sub-directory or a regular file. Arguments Argument Description dirent Pointer to the directory entry to query Returned values 1: The entry is a directory 0: The entry is a regular file. Header file #include \"fs/fs.h\" Example This example iterates through the contents of a directory, printing the name of each child node. When the traversal is complete, the code closes the directory handle. int traverse_dir ( const char *dirname ) { struct fs_dirent *dirent ; struct fs_dir *dir ; char buf [ 64 ]; uint8_t name_len ; int rc ; rc = fs_opendir ( dirname , &dir ); if ( rc != 0 ) { return -1 ; } /* Iterate through the parent directory, printing the name of each child * entry. The loop only terminates via a function return. */ while ( 1 ) { /* Retrieve the next child node. */ rc = fs_readdir ( dir , &dirent ); if ( rc == FS_ENOENT ) { /* Traversal complete. */ return 0 ; } else if ( rc != 0 ) { /* Unexpected error. */ return -1 ; } /* Read the child node's name from the file system. */ rc = fs_dirent_name ( dirent , sizeof buf , buf , &name_len ); if ( rc != 0 ) { return -1 ; } /* Print the child node's name to the console. */ if ( fs_dirent_is_dir ( dirent )) { console_printf ( \" dir: \" ); } else { console_printf ( \"file: \" ); } console_printf ( \"%s\\n\" , buf ); } }","title":"fs_dirent_is_dir"},{"location":"os/modules/fs/fs/fs_dirent_is_dir/#fs_dirent_is_dir","text":"int fs_dirent_is_dir ( const struct fs_dirent *dirent ) Tells you whether the specified directory entry is a sub-directory or a regular file.","title":"fs_dirent_is_dir"},{"location":"os/modules/fs/fs/fs_dirent_is_dir/#arguments","text":"Argument Description dirent Pointer to the directory entry to query","title":"Arguments"},{"location":"os/modules/fs/fs/fs_dirent_is_dir/#returned-values","text":"1: The entry is a directory 0: The entry is a regular file.","title":"Returned values"},{"location":"os/modules/fs/fs/fs_dirent_is_dir/#header-file","text":"#include \"fs/fs.h\"","title":"Header file"},{"location":"os/modules/fs/fs/fs_dirent_is_dir/#example","text":"This example iterates through the contents of a directory, printing the name of each child node. When the traversal is complete, the code closes the directory handle. int traverse_dir ( const char *dirname ) { struct fs_dirent *dirent ; struct fs_dir *dir ; char buf [ 64 ]; uint8_t name_len ; int rc ; rc = fs_opendir ( dirname , &dir ); if ( rc != 0 ) { return -1 ; } /* Iterate through the parent directory, printing the name of each child * entry. The loop only terminates via a function return. */ while ( 1 ) { /* Retrieve the next child node. */ rc = fs_readdir ( dir , &dirent ); if ( rc == FS_ENOENT ) { /* Traversal complete. */ return 0 ; } else if ( rc != 0 ) { /* Unexpected error. */ return -1 ; } /* Read the child node's name from the file system. */ rc = fs_dirent_name ( dirent , sizeof buf , buf , &name_len ); if ( rc != 0 ) { return -1 ; } /* Print the child node's name to the console. */ if ( fs_dirent_is_dir ( dirent )) { console_printf ( \" dir: \" ); } else { console_printf ( \"file: \" ); } console_printf ( \"%s\\n\" , buf ); } }","title":"Example"},{"location":"os/modules/fs/fs/fs_dirent_name/","text":"fs_dirent_name int fs_dirent_name ( const struct fs_dirent *dirent , size_t max_len , char *out_name , uint8_t *out_name_len ) Retrieves the filename of the specified directory entry. Arguments Argument Description dirent Pointer to the directory entry to query max_len Size of the \"out_name\" character buffer out_name On success, the entry's filename is written here; always null-terminated out_name_len On success, contains the actual length of the filename, NOT including the null-terminator Returned values 0 on success FS error code on failure Notes The retrieved filename is always null-terminated. To ensure enough space to hold the full filename plus a null-termintor, a destination buffer of size filename-max-length + 1 should be used. Header file #include \"fs/fs.h\" Example This example iterates through the contents of a directory, printing the name of each child node. When the traversal is complete, the code closes the directory handle. int traverse_dir ( const char *dirname ) { struct fs_dirent *dirent ; struct fs_dir *dir ; char buf [ 64 ]; uint8_t name_len ; int rc ; rc = fs_opendir ( dirname , &dir ); if ( rc != 0 ) { return -1 ; } /* Iterate through the parent directory, printing the name of each child * entry. The loop only terminates via a function return. */ while ( 1 ) { /* Retrieve the next child node. */ rc = fs_readdir ( dir , &dirent ); if ( rc == FS_ENOENT ) { /* Traversal complete. */ return 0 ; } else if ( rc != 0 ) { /* Unexpected error. */ return -1 ; } /* Read the child node's name from the file system. */ rc = fs_dirent_name ( dirent , sizeof buf , buf , &name_len ); if ( rc != 0 ) { return -1 ; } /* Print the child node's name to the console. */ if ( fs_dirent_is_dir ( dirent )) { console_printf ( \" dir: \" ); } else { console_printf ( \"file: \" ); } console_printf ( \"%s\\n\" , buf ); } }","title":"fs_dirent_name"},{"location":"os/modules/fs/fs/fs_dirent_name/#fs_dirent_name","text":"int fs_dirent_name ( const struct fs_dirent *dirent , size_t max_len , char *out_name , uint8_t *out_name_len ) Retrieves the filename of the specified directory entry.","title":"fs_dirent_name"},{"location":"os/modules/fs/fs/fs_dirent_name/#arguments","text":"Argument Description dirent Pointer to the directory entry to query max_len Size of the \"out_name\" character buffer out_name On success, the entry's filename is written here; always null-terminated out_name_len On success, contains the actual length of the filename, NOT including the null-terminator","title":"Arguments"},{"location":"os/modules/fs/fs/fs_dirent_name/#returned-values","text":"0 on success FS error code on failure","title":"Returned values"},{"location":"os/modules/fs/fs/fs_dirent_name/#notes","text":"The retrieved filename is always null-terminated. To ensure enough space to hold the full filename plus a null-termintor, a destination buffer of size filename-max-length + 1 should be used.","title":"Notes"},{"location":"os/modules/fs/fs/fs_dirent_name/#header-file","text":"#include \"fs/fs.h\"","title":"Header file"},{"location":"os/modules/fs/fs/fs_dirent_name/#example","text":"This example iterates through the contents of a directory, printing the name of each child node. When the traversal is complete, the code closes the directory handle. int traverse_dir ( const char *dirname ) { struct fs_dirent *dirent ; struct fs_dir *dir ; char buf [ 64 ]; uint8_t name_len ; int rc ; rc = fs_opendir ( dirname , &dir ); if ( rc != 0 ) { return -1 ; } /* Iterate through the parent directory, printing the name of each child * entry. The loop only terminates via a function return. */ while ( 1 ) { /* Retrieve the next child node. */ rc = fs_readdir ( dir , &dirent ); if ( rc == FS_ENOENT ) { /* Traversal complete. */ return 0 ; } else if ( rc != 0 ) { /* Unexpected error. */ return -1 ; } /* Read the child node's name from the file system. */ rc = fs_dirent_name ( dirent , sizeof buf , buf , &name_len ); if ( rc != 0 ) { return -1 ; } /* Print the child node's name to the console. */ if ( fs_dirent_is_dir ( dirent )) { console_printf ( \" dir: \" ); } else { console_printf ( \"file: \" ); } console_printf ( \"%s\\n\" , buf ); } }","title":"Example"},{"location":"os/modules/fs/fs/fs_filelen/","text":"fs_filelen int fs_filelen ( const struct fs_file *file , uint32_t *out_len ) Retrieves the current length of the specified open file. Arguments Argument Description file Pointer to the file to query out_len On success, the number of bytes in the file gets written here Returned values 0 on success FS error code on failure Header file #include \"fs/fs.h\" Example int write_config ( void ) { struct fs_file *file ; int rc ; /* If the file doesn't exist, create it. If it does exist, truncate it to * zero bytes. */ rc = fs_open ( \"/settings/config.txt\" , FS_ACCESS_WRITE | FS_ACCESS_TRUNCATE , &file ); if ( rc == 0 ) { /* Write 5 bytes of data to the file. */ rc = fs_write ( file , \"hello\" , 5 ); if ( rc == 0 ) { /* The file should now contain exactly five bytes. */ assert ( fs_filelen ( file ) == 5 ); } /* Close the file. */ fs_close ( file ); } return rc == 0 ? 0 : -1 ; }","title":"fs_filelen"},{"location":"os/modules/fs/fs/fs_filelen/#fs_filelen","text":"int fs_filelen ( const struct fs_file *file , uint32_t *out_len ) Retrieves the current length of the specified open file.","title":"fs_filelen"},{"location":"os/modules/fs/fs/fs_filelen/#arguments","text":"Argument Description file Pointer to the file to query out_len On success, the number of bytes in the file gets written here","title":"Arguments"},{"location":"os/modules/fs/fs/fs_filelen/#returned-values","text":"0 on success FS error code on failure","title":"Returned values"},{"location":"os/modules/fs/fs/fs_filelen/#header-file","text":"#include \"fs/fs.h\"","title":"Header file"},{"location":"os/modules/fs/fs/fs_filelen/#example","text":"int write_config ( void ) { struct fs_file *file ; int rc ; /* If the file doesn't exist, create it. If it does exist, truncate it to * zero bytes. */ rc = fs_open ( \"/settings/config.txt\" , FS_ACCESS_WRITE | FS_ACCESS_TRUNCATE , &file ); if ( rc == 0 ) { /* Write 5 bytes of data to the file. */ rc = fs_write ( file , \"hello\" , 5 ); if ( rc == 0 ) { /* The file should now contain exactly five bytes. */ assert ( fs_filelen ( file ) == 5 ); } /* Close the file. */ fs_close ( file ); } return rc == 0 ? 0 : -1 ; }","title":"Example"},{"location":"os/modules/fs/fs/fs_getpos/","text":"fs_getpos uint32_t fs_getpos ( const struct fs_file *file ) Retrieves the current read and write position of the specified open file. Arguments Argument Description file Pointer to the file to query Returned values The file offset, in bytes Notes If a file is opened in append mode, its write pointer is always positioned at the end of the file. Calling this function on such a file only indicates the read position. Header file #include \"fs/fs.h\"","title":"fs_getpos"},{"location":"os/modules/fs/fs/fs_getpos/#fs_getpos","text":"uint32_t fs_getpos ( const struct fs_file *file ) Retrieves the current read and write position of the specified open file.","title":"fs_getpos"},{"location":"os/modules/fs/fs/fs_getpos/#arguments","text":"Argument Description file Pointer to the file to query","title":"Arguments"},{"location":"os/modules/fs/fs/fs_getpos/#returned-values","text":"The file offset, in bytes","title":"Returned values"},{"location":"os/modules/fs/fs/fs_getpos/#notes","text":"If a file is opened in append mode, its write pointer is always positioned at the end of the file. Calling this function on such a file only indicates the read position.","title":"Notes"},{"location":"os/modules/fs/fs/fs_getpos/#header-file","text":"#include \"fs/fs.h\"","title":"Header file"},{"location":"os/modules/fs/fs/fs_mkdir/","text":"fs_mkdir int fs_mkdir ( const char *path ) Creates the directory represented by the specified path. Arguments Argument Description path The name of the directory to create Returned values 0 on success FS error code on failure. Notes All intermediate directories must already exist. The specified path must start with a '/' character. Header file #include \"fs/fs.h\" Example This example demonstrates creating a series of nested directories. int create_path ( void ) { int rc ; rc = fs_mkdir ( \"/data\" ); if ( rc != 0 ) goto err ; rc = fs_mkdir ( \"/data/logs\" ); if ( rc != 0 ) goto err ; rc = fs_mkdir ( \"/data/logs/temperature\" ); if ( rc != 0 ) goto err ; rc = fs_mkdir ( \"/data/logs/temperature/current\" ); if ( rc != 0 ) goto err ; return 0 ; err : /* Clean up the incomplete directory tree, if any. */ fs_unlink ( \"/data\" ); return -1 ; }","title":"fs_mkdir"},{"location":"os/modules/fs/fs/fs_mkdir/#fs_mkdir","text":"int fs_mkdir ( const char *path ) Creates the directory represented by the specified path.","title":"fs_mkdir"},{"location":"os/modules/fs/fs/fs_mkdir/#arguments","text":"Argument Description path The name of the directory to create","title":"Arguments"},{"location":"os/modules/fs/fs/fs_mkdir/#returned-values","text":"0 on success FS error code on failure.","title":"Returned values"},{"location":"os/modules/fs/fs/fs_mkdir/#notes","text":"All intermediate directories must already exist. The specified path must start with a '/' character.","title":"Notes"},{"location":"os/modules/fs/fs/fs_mkdir/#header-file","text":"#include \"fs/fs.h\"","title":"Header file"},{"location":"os/modules/fs/fs/fs_mkdir/#example","text":"This example demonstrates creating a series of nested directories. int create_path ( void ) { int rc ; rc = fs_mkdir ( \"/data\" ); if ( rc != 0 ) goto err ; rc = fs_mkdir ( \"/data/logs\" ); if ( rc != 0 ) goto err ; rc = fs_mkdir ( \"/data/logs/temperature\" ); if ( rc != 0 ) goto err ; rc = fs_mkdir ( \"/data/logs/temperature/current\" ); if ( rc != 0 ) goto err ; return 0 ; err : /* Clean up the incomplete directory tree, if any. */ fs_unlink ( \"/data\" ); return -1 ; }","title":"Example"},{"location":"os/modules/fs/fs/fs_open/","text":"fs_open int fs_open ( const char *filename , uint8_t access_flags , struct fs_file **out_file ) Opens a file at the specified path. The result of opening a nonexistent file depends on the access flags specified. All intermediate directories must already exist. The access flags are best understood by comparing them to their equivalent mode strings accepted by the C standard library function fopen() . The mode strings passed to fopen() map to fs_open() 's access flags as follows: \"r\" - FS_ACCESS_READ \"r+\" - FS_ACCESS_READ | FS_ACCESS_WRITE \"w\" - FS_ACCESS_WRITE | FS_ACCESS_TRUNCATE \"w+\" - FS_ACCESS_READ | FS_ACCESS_WRITE | FS_ACCESS_TRUNCATE \"a\" - FS_ACCESS_WRITE | FS_ACCESS_APPEND \"a+\" - FS_ACCESS_READ | FS_ACCESS_WRITE | FS_ACCESS_APPEND Arguments Argument Description filename Null-terminated string indicating the full path of the file to open access_flags Flags controlling file access; see above table out_file On success, a pointer to the newly-created file handle gets written here Returned values 0 on success FS error code on failure Notes There is no concept of current working directory. Therefore all file names should start with '/'. Always close files when you are done using them. If you forget to close a file, the file stays open forever. Do this too many times, and the underlying file system will run out of file handles, causing subsequent open operations to fail. This type of bug is known as a file handle leak or a file descriptor leak. Header file #include \"fs/fs.h\" Example The below code opens the file /settings/config.txt for reading, reads some data, and then closes the file. int read_config ( void ) { struct fs_file *file ; uint32_t bytes_read ; uint8_t buf [ 16 ]; int rc ; /* Open the file for reading. */ rc = fs_open ( \"/settings/config.txt\" , FS_ACCESS_READ , &file ); if ( rc != 0 ) { return -1 ; } /* Read up to 16 bytes from the file. */ rc = fs_read ( file , sizeof buf , buf , &bytes_read ); if ( rc == 0 ) { /* buf now contains up to 16 bytes of file data. */ console_printf ( \"read %u bytes\\n\" , bytes_read ) } /* Close the file. */ fs_close ( file ); return rc == 0 ? 0 : -1 ; }","title":"fs_open"},{"location":"os/modules/fs/fs/fs_open/#fs_open","text":"int fs_open ( const char *filename , uint8_t access_flags , struct fs_file **out_file ) Opens a file at the specified path. The result of opening a nonexistent file depends on the access flags specified. All intermediate directories must already exist. The access flags are best understood by comparing them to their equivalent mode strings accepted by the C standard library function fopen() . The mode strings passed to fopen() map to fs_open() 's access flags as follows: \"r\" - FS_ACCESS_READ \"r+\" - FS_ACCESS_READ | FS_ACCESS_WRITE \"w\" - FS_ACCESS_WRITE | FS_ACCESS_TRUNCATE \"w+\" - FS_ACCESS_READ | FS_ACCESS_WRITE | FS_ACCESS_TRUNCATE \"a\" - FS_ACCESS_WRITE | FS_ACCESS_APPEND \"a+\" - FS_ACCESS_READ | FS_ACCESS_WRITE | FS_ACCESS_APPEND","title":"fs_open"},{"location":"os/modules/fs/fs/fs_open/#arguments","text":"Argument Description filename Null-terminated string indicating the full path of the file to open access_flags Flags controlling file access; see above table out_file On success, a pointer to the newly-created file handle gets written here","title":"Arguments"},{"location":"os/modules/fs/fs/fs_open/#returned-values","text":"0 on success FS error code on failure","title":"Returned values"},{"location":"os/modules/fs/fs/fs_open/#notes","text":"There is no concept of current working directory. Therefore all file names should start with '/'. Always close files when you are done using them. If you forget to close a file, the file stays open forever. Do this too many times, and the underlying file system will run out of file handles, causing subsequent open operations to fail. This type of bug is known as a file handle leak or a file descriptor leak.","title":"Notes"},{"location":"os/modules/fs/fs/fs_open/#header-file","text":"#include \"fs/fs.h\"","title":"Header file"},{"location":"os/modules/fs/fs/fs_open/#example","text":"The below code opens the file /settings/config.txt for reading, reads some data, and then closes the file. int read_config ( void ) { struct fs_file *file ; uint32_t bytes_read ; uint8_t buf [ 16 ]; int rc ; /* Open the file for reading. */ rc = fs_open ( \"/settings/config.txt\" , FS_ACCESS_READ , &file ); if ( rc != 0 ) { return -1 ; } /* Read up to 16 bytes from the file. */ rc = fs_read ( file , sizeof buf , buf , &bytes_read ); if ( rc == 0 ) { /* buf now contains up to 16 bytes of file data. */ console_printf ( \"read %u bytes\\n\" , bytes_read ) } /* Close the file. */ fs_close ( file ); return rc == 0 ? 0 : -1 ; }","title":"Example"},{"location":"os/modules/fs/fs/fs_opendir/","text":"fs_opendir int fs_opendir ( const char *path , struct fs_dir **out_dir ) Opens the directory at the specified path. The directory's contents can be read with subsequent calls to fs_readdir(). When you are done with the directory handle, close it with fs_closedir(). Arguments Argument Description path The name of the directory to open out_dir On success, points to the directory handle Returned values 0 on success FS_ENOENT if the specified directory does not exist Other FS error code on error. Notes Unlinking files from the directory while it is open may result in unpredictable behavior during subsequent calls to fs_readdir() . New files can be created inside the directory without causing problems. Always close a directory when you are done reading from it. If you forget to close a directory, the directory stays open forever. Do this too many times, and the underlying file system will run out of directory handles, causing subsequent open operations to fail. This type of bug is known as a file handle leak or a file descriptor leak. Header file #include \"fs/fs.h\" Example This example iterates through the contents of a directory, printing the name of each child node. When the traversal is complete, the code closes the directory handle. int traverse_dir ( const char *dirname ) { struct fs_dirent *dirent ; struct fs_dir *dir ; char buf [ 64 ]; uint8_t name_len ; int rc ; rc = fs_opendir ( dirname , &dir ); if ( rc != 0 ) { return -1 ; } /* Iterate through the parent directory, printing the name of each child * entry. The loop only terminates via a function return. */ while ( 1 ) { /* Retrieve the next child node. */ rc = fs_readdir ( dir , &dirent ); if ( rc == FS_ENOENT ) { /* Traversal complete. */ return 0 ; } else if ( rc != 0 ) { /* Unexpected error. */ return -1 ; } /* Read the child node's name from the file system. */ rc = fs_dirent_name ( dirent , sizeof buf , buf , &name_len ); if ( rc != 0 ) { return -1 ; } /* Print the child node's name to the console. */ if ( fs_dirent_is_dir ( dirent )) { console_printf ( \" dir: \" ); } else { console_printf ( \"file: \" ); } console_printf ( \"%s\\n\" , buf ); } }","title":"fs_opendir"},{"location":"os/modules/fs/fs/fs_opendir/#fs_opendir","text":"int fs_opendir ( const char *path , struct fs_dir **out_dir ) Opens the directory at the specified path. The directory's contents can be read with subsequent calls to fs_readdir(). When you are done with the directory handle, close it with fs_closedir().","title":"fs_opendir"},{"location":"os/modules/fs/fs/fs_opendir/#arguments","text":"Argument Description path The name of the directory to open out_dir On success, points to the directory handle","title":"Arguments"},{"location":"os/modules/fs/fs/fs_opendir/#returned-values","text":"0 on success FS_ENOENT if the specified directory does not exist Other FS error code on error.","title":"Returned values"},{"location":"os/modules/fs/fs/fs_opendir/#notes","text":"Unlinking files from the directory while it is open may result in unpredictable behavior during subsequent calls to fs_readdir() . New files can be created inside the directory without causing problems. Always close a directory when you are done reading from it. If you forget to close a directory, the directory stays open forever. Do this too many times, and the underlying file system will run out of directory handles, causing subsequent open operations to fail. This type of bug is known as a file handle leak or a file descriptor leak.","title":"Notes"},{"location":"os/modules/fs/fs/fs_opendir/#header-file","text":"#include \"fs/fs.h\"","title":"Header file"},{"location":"os/modules/fs/fs/fs_opendir/#example","text":"This example iterates through the contents of a directory, printing the name of each child node. When the traversal is complete, the code closes the directory handle. int traverse_dir ( const char *dirname ) { struct fs_dirent *dirent ; struct fs_dir *dir ; char buf [ 64 ]; uint8_t name_len ; int rc ; rc = fs_opendir ( dirname , &dir ); if ( rc != 0 ) { return -1 ; } /* Iterate through the parent directory, printing the name of each child * entry. The loop only terminates via a function return. */ while ( 1 ) { /* Retrieve the next child node. */ rc = fs_readdir ( dir , &dirent ); if ( rc == FS_ENOENT ) { /* Traversal complete. */ return 0 ; } else if ( rc != 0 ) { /* Unexpected error. */ return -1 ; } /* Read the child node's name from the file system. */ rc = fs_dirent_name ( dirent , sizeof buf , buf , &name_len ); if ( rc != 0 ) { return -1 ; } /* Print the child node's name to the console. */ if ( fs_dirent_is_dir ( dirent )) { console_printf ( \" dir: \" ); } else { console_printf ( \"file: \" ); } console_printf ( \"%s\\n\" , buf ); } }","title":"Example"},{"location":"os/modules/fs/fs/fs_ops/","text":"struct fs_ops struct fs_ops { int ( *f_open )( const char *filename , uint8_t access_flags , struct fs_file **out_file ); int ( *f_close )( struct fs_file *file ); int ( *f_read )( struct fs_file *file , uint32_t len , void *out_data , uint32_t *out_len ); int ( *f_write )( struct fs_file *file , const void *data , int len ); int ( *f_seek )( struct fs_file *file , uint32_t offset ); uint32_t ( *f_getpos )( const struct fs_file *file ); int ( *f_filelen )( const struct fs_file *file , uint32_t *out_len ); int ( *f_unlink )( const char *filename ); int ( *f_rename )( const char *from , const char *to ); int ( *f_mkdir )( const char *path ); int ( *f_opendir )( const char *path , struct fs_dir **out_dir ); int ( *f_readdir )( struct fs_dir *dir , struct fs_dirent **out_dirent ); int ( *f_closedir )( struct fs_dir *dir ); int ( *f_dirent_name )( const struct fs_dirent *dirent , size_t max_len , char *out_name , uint8_t *out_name_len ); int ( *f_dirent_is_dir )( const struct fs_dirent *dirent ); const char *f_name ; }; This data structure consists of a set of function pointers. Each function pointer corresponds to a file system operation. When registering a file system with the abstraction layer, each function pointer must be pointed at the corresponding routine in the custom file system package. The required behavior of each corresponding function is documented in the file system abstraction layer API . Header file #include \"fs/fs_if.h\"","title":"struct fs_ops"},{"location":"os/modules/fs/fs/fs_ops/#struct-fs_ops","text":"struct fs_ops { int ( *f_open )( const char *filename , uint8_t access_flags , struct fs_file **out_file ); int ( *f_close )( struct fs_file *file ); int ( *f_read )( struct fs_file *file , uint32_t len , void *out_data , uint32_t *out_len ); int ( *f_write )( struct fs_file *file , const void *data , int len ); int ( *f_seek )( struct fs_file *file , uint32_t offset ); uint32_t ( *f_getpos )( const struct fs_file *file ); int ( *f_filelen )( const struct fs_file *file , uint32_t *out_len ); int ( *f_unlink )( const char *filename ); int ( *f_rename )( const char *from , const char *to ); int ( *f_mkdir )( const char *path ); int ( *f_opendir )( const char *path , struct fs_dir **out_dir ); int ( *f_readdir )( struct fs_dir *dir , struct fs_dirent **out_dirent ); int ( *f_closedir )( struct fs_dir *dir ); int ( *f_dirent_name )( const struct fs_dirent *dirent , size_t max_len , char *out_name , uint8_t *out_name_len ); int ( *f_dirent_is_dir )( const struct fs_dirent *dirent ); const char *f_name ; }; This data structure consists of a set of function pointers. Each function pointer corresponds to a file system operation. When registering a file system with the abstraction layer, each function pointer must be pointed at the corresponding routine in the custom file system package. The required behavior of each corresponding function is documented in the file system abstraction layer API .","title":"struct fs_ops"},{"location":"os/modules/fs/fs/fs_ops/#header-file","text":"#include \"fs/fs_if.h\"","title":"Header file"},{"location":"os/modules/fs/fs/fs_read/","text":"fs_read int fs_read ( struct fs_file *file , uint32_t len , void *out_data , uint32_t *out_len ) Reads data from the specified file. If more data is requested than remains in the file, all available data is retrieved and a success code is returned. Arguments Argument Description file Pointer to the the file to read from len The number of bytes to attempt to read out_data The destination buffer to read into out_len On success, the number of bytes actually read gets written here. Pass null if you don't care. Returned values 0 on success FS error code on failure Header file #include \"fs/fs.h\" Example The below code opens the file /settings/config.txt for reading, reads some data, and then closes the file. int read_config ( void ) { struct fs_file *file ; uint32_t bytes_read ; uint8_t buf [ 16 ]; int rc ; /* Open the file for reading. */ rc = fs_open ( \"/settings/config.txt\" , FS_ACCESS_READ , &file ); if ( rc != 0 ) { return -1 ; } /* Read up to 16 bytes from the file. */ rc = fs_read ( file , sizeof buf , buf , &bytes_read ); if ( rc == 0 ) { /* buf now contains up to 16 bytes of file data. */ console_printf ( \"read %u bytes\\n\" , bytes_read ) } /* Close the file. */ fs_close ( file ); return rc == 0 ? 0 : -1 ; }","title":"fs_read"},{"location":"os/modules/fs/fs/fs_read/#fs_read","text":"int fs_read ( struct fs_file *file , uint32_t len , void *out_data , uint32_t *out_len ) Reads data from the specified file. If more data is requested than remains in the file, all available data is retrieved and a success code is returned.","title":"fs_read"},{"location":"os/modules/fs/fs/fs_read/#arguments","text":"Argument Description file Pointer to the the file to read from len The number of bytes to attempt to read out_data The destination buffer to read into out_len On success, the number of bytes actually read gets written here. Pass null if you don't care.","title":"Arguments"},{"location":"os/modules/fs/fs/fs_read/#returned-values","text":"0 on success FS error code on failure","title":"Returned values"},{"location":"os/modules/fs/fs/fs_read/#header-file","text":"#include \"fs/fs.h\"","title":"Header file"},{"location":"os/modules/fs/fs/fs_read/#example","text":"The below code opens the file /settings/config.txt for reading, reads some data, and then closes the file. int read_config ( void ) { struct fs_file *file ; uint32_t bytes_read ; uint8_t buf [ 16 ]; int rc ; /* Open the file for reading. */ rc = fs_open ( \"/settings/config.txt\" , FS_ACCESS_READ , &file ); if ( rc != 0 ) { return -1 ; } /* Read up to 16 bytes from the file. */ rc = fs_read ( file , sizeof buf , buf , &bytes_read ); if ( rc == 0 ) { /* buf now contains up to 16 bytes of file data. */ console_printf ( \"read %u bytes\\n\" , bytes_read ) } /* Close the file. */ fs_close ( file ); return rc == 0 ? 0 : -1 ; }","title":"Example"},{"location":"os/modules/fs/fs/fs_readdir/","text":"fs_readdir int fs_readdir ( struct fs_dir *dir , struct fs_dirent **out_dirent ); Reads the next entry in an open directory. Arguments Argument Description dir The directory handle to read from out_dirent On success, points to the next child entry in the specified directory Returned values 0 on success FS_ENOENT if there are no more entries in the parent directory Other FS error code on error. Header file #include \"fs/fs.h\" Example This example iterates through the contents of a directory, printing the name of each child node. When the traversal is complete, the code closes the directory handle. int traverse_dir ( const char *dirname ) { struct fs_dirent *dirent ; struct fs_dir *dir ; char buf [ 64 ]; uint8_t name_len ; int rc ; rc = fs_opendir ( dirname , &dir ); if ( rc != 0 ) { return -1 ; } /* Iterate through the parent directory, printing the name of each child * entry. The loop only terminates via a function return. */ while ( 1 ) { /* Retrieve the next child node. */ rc = fs_readdir ( dir , &dirent ); if ( rc == FS_ENOENT ) { /* Traversal complete. */ return 0 ; } else if ( rc != 0 ) { /* Unexpected error. */ return -1 ; } /* Read the child node's name from the file system. */ rc = fs_dirent_name ( dirent , sizeof buf , buf , &name_len ); if ( rc != 0 ) { return -1 ; } /* Print the child node's name to the console. */ if ( fs_dirent_is_dir ( dirent )) { console_printf ( \" dir: \" ); } else { console_printf ( \"file: \" ); } console_printf ( \"%s\\n\" , buf ); } }","title":"fs_readdir"},{"location":"os/modules/fs/fs/fs_readdir/#fs_readdir","text":"int fs_readdir ( struct fs_dir *dir , struct fs_dirent **out_dirent ); Reads the next entry in an open directory.","title":"fs_readdir"},{"location":"os/modules/fs/fs/fs_readdir/#arguments","text":"Argument Description dir The directory handle to read from out_dirent On success, points to the next child entry in the specified directory","title":"Arguments"},{"location":"os/modules/fs/fs/fs_readdir/#returned-values","text":"0 on success FS_ENOENT if there are no more entries in the parent directory Other FS error code on error.","title":"Returned values"},{"location":"os/modules/fs/fs/fs_readdir/#header-file","text":"#include \"fs/fs.h\"","title":"Header file"},{"location":"os/modules/fs/fs/fs_readdir/#example","text":"This example iterates through the contents of a directory, printing the name of each child node. When the traversal is complete, the code closes the directory handle. int traverse_dir ( const char *dirname ) { struct fs_dirent *dirent ; struct fs_dir *dir ; char buf [ 64 ]; uint8_t name_len ; int rc ; rc = fs_opendir ( dirname , &dir ); if ( rc != 0 ) { return -1 ; } /* Iterate through the parent directory, printing the name of each child * entry. The loop only terminates via a function return. */ while ( 1 ) { /* Retrieve the next child node. */ rc = fs_readdir ( dir , &dirent ); if ( rc == FS_ENOENT ) { /* Traversal complete. */ return 0 ; } else if ( rc != 0 ) { /* Unexpected error. */ return -1 ; } /* Read the child node's name from the file system. */ rc = fs_dirent_name ( dirent , sizeof buf , buf , &name_len ); if ( rc != 0 ) { return -1 ; } /* Print the child node's name to the console. */ if ( fs_dirent_is_dir ( dirent )) { console_printf ( \" dir: \" ); } else { console_printf ( \"file: \" ); } console_printf ( \"%s\\n\" , buf ); } }","title":"Example"},{"location":"os/modules/fs/fs/fs_register/","text":"fs_register int fs_register ( const struct fs_ops *fops ) Registers a file system with the abstraction layer. On success, all calls into fs/fs will use the registered file system. Arguments Argument Description fops A pointer to const struct fs_ops . Specifies which file system routines get mapped to the fs/fs API. All function pointers must be filled in. Returned values 0 on success FS_EEXIST if a file system has already been registered Notes Only one file system can be registered. The registered file system is mounted in the root directory ( / ). Header file #include \"fs/fs.h\"","title":"fs_register"},{"location":"os/modules/fs/fs/fs_register/#fs_register","text":"int fs_register ( const struct fs_ops *fops ) Registers a file system with the abstraction layer. On success, all calls into fs/fs will use the registered file system.","title":"fs_register"},{"location":"os/modules/fs/fs/fs_register/#arguments","text":"Argument Description fops A pointer to const struct fs_ops . Specifies which file system routines get mapped to the fs/fs API. All function pointers must be filled in.","title":"Arguments"},{"location":"os/modules/fs/fs/fs_register/#returned-values","text":"0 on success FS_EEXIST if a file system has already been registered","title":"Returned values"},{"location":"os/modules/fs/fs/fs_register/#notes","text":"Only one file system can be registered. The registered file system is mounted in the root directory ( / ).","title":"Notes"},{"location":"os/modules/fs/fs/fs_register/#header-file","text":"#include \"fs/fs.h\"","title":"Header file"},{"location":"os/modules/fs/fs/fs_rename/","text":"fs_rename int fs_rename ( const char *from , const char *to ) Performs a rename and / or move of the specified source path to the specified destination. The source path can refer to a file or a directory. Arguments Argument Description from The source path to The destination path Returned values 0 on success FS error code on failure Notes The source path can refer to either a file or a directory. All intermediate directories in the destination path must already exist. If the source path refers to a file, the destination path must contain a full filename path, rather than just the new parent directory. If an object already exists at the specified destination path, this function causes it to be unlinked prior to the rename (i.e., the destination gets clobbered). Header file #include \"fs/fs.h\" Example This example demonstrates how to use fs_rename() to perform a log rotation. In this example, there is one primary log and three archived logs. FS_ENOENT errors returned by fs_rename() are ignored; it is not an error if an archived log was never created. int rotate_logs ( void ) { struct fs_file *file ; int rc ; /* Rotate each of the log files. */ rc = fs_rename ( \"/var/log/messages.2\" , \"/var/log/messages.3\" ) if ( rc != 0 && rc != FS_ENOENT ) return -1 ; rc = fs_rename ( \"/var/log/messages.1\" , \"/var/log/messages.2\" ) if ( rc != 0 && rc != FS_ENOENT ) return -1 ; rc = fs_rename ( \"/var/log/messages.0\" , \"/var/log/messages.1\" ) if ( rc != 0 && rc != FS_ENOENT ) return -1 ; rc = fs_rename ( \"/var/log/messages\" , \"/var/log/messages.0\" ) if ( rc != 0 && rc != FS_ENOENT ) return -1 ; /* Now create the new log file. */ rc = fs_open ( \"/var/log/messages\" , FS_ACCESS_WRITE | FS_ACCESS_TRUNCATE , &file ); if ( rc != 0 ) return -1 ; rc = fs_write ( file , \"Creating new log file.\\n\" , 23 ); fs_close ( file ); return rc == 0 ? 0 : -1 ; }","title":"fs_rename"},{"location":"os/modules/fs/fs/fs_rename/#fs_rename","text":"int fs_rename ( const char *from , const char *to ) Performs a rename and / or move of the specified source path to the specified destination. The source path can refer to a file or a directory.","title":"fs_rename"},{"location":"os/modules/fs/fs/fs_rename/#arguments","text":"Argument Description from The source path to The destination path","title":"Arguments"},{"location":"os/modules/fs/fs/fs_rename/#returned-values","text":"0 on success FS error code on failure","title":"Returned values"},{"location":"os/modules/fs/fs/fs_rename/#notes","text":"The source path can refer to either a file or a directory. All intermediate directories in the destination path must already exist. If the source path refers to a file, the destination path must contain a full filename path, rather than just the new parent directory. If an object already exists at the specified destination path, this function causes it to be unlinked prior to the rename (i.e., the destination gets clobbered).","title":"Notes"},{"location":"os/modules/fs/fs/fs_rename/#header-file","text":"#include \"fs/fs.h\"","title":"Header file"},{"location":"os/modules/fs/fs/fs_rename/#example","text":"This example demonstrates how to use fs_rename() to perform a log rotation. In this example, there is one primary log and three archived logs. FS_ENOENT errors returned by fs_rename() are ignored; it is not an error if an archived log was never created. int rotate_logs ( void ) { struct fs_file *file ; int rc ; /* Rotate each of the log files. */ rc = fs_rename ( \"/var/log/messages.2\" , \"/var/log/messages.3\" ) if ( rc != 0 && rc != FS_ENOENT ) return -1 ; rc = fs_rename ( \"/var/log/messages.1\" , \"/var/log/messages.2\" ) if ( rc != 0 && rc != FS_ENOENT ) return -1 ; rc = fs_rename ( \"/var/log/messages.0\" , \"/var/log/messages.1\" ) if ( rc != 0 && rc != FS_ENOENT ) return -1 ; rc = fs_rename ( \"/var/log/messages\" , \"/var/log/messages.0\" ) if ( rc != 0 && rc != FS_ENOENT ) return -1 ; /* Now create the new log file. */ rc = fs_open ( \"/var/log/messages\" , FS_ACCESS_WRITE | FS_ACCESS_TRUNCATE , &file ); if ( rc != 0 ) return -1 ; rc = fs_write ( file , \"Creating new log file.\\n\" , 23 ); fs_close ( file ); return rc == 0 ? 0 : -1 ; }","title":"Example"},{"location":"os/modules/fs/fs/fs_return_codes/","text":"fs/fs Return Codes Functions in fs/fs that indicate success or failure do so with the following set of return codes: Return code Description FS_EOK Success FS_ECORRUPT File system corrupt FS_EHW Error accessing storage medium FS_EOFFSET Invalid offset FS_EINVAL Invalid argument FS_ENOMEM Insufficient memory FS_ENOENT No such file or directory FS_EEMPTY Specified region is empty (internal only) FS_EFULL Disk full FS_EUNEXP Disk contains unexpected metadata FS_EOS OS error FS_EEXIST File or directory already exists FS_EACCESS Operation prohibited by file open mode FS_EUNINIT File system not initialized Header file #include \"fs/fs.h\"","title":"Return Codes"},{"location":"os/modules/fs/fs/fs_return_codes/#fsfs-return-codes","text":"Functions in fs/fs that indicate success or failure do so with the following set of return codes: Return code Description FS_EOK Success FS_ECORRUPT File system corrupt FS_EHW Error accessing storage medium FS_EOFFSET Invalid offset FS_EINVAL Invalid argument FS_ENOMEM Insufficient memory FS_ENOENT No such file or directory FS_EEMPTY Specified region is empty (internal only) FS_EFULL Disk full FS_EUNEXP Disk contains unexpected metadata FS_EOS OS error FS_EEXIST File or directory already exists FS_EACCESS Operation prohibited by file open mode FS_EUNINIT File system not initialized","title":"fs/fs Return Codes"},{"location":"os/modules/fs/fs/fs_return_codes/#header-file","text":"#include \"fs/fs.h\"","title":"Header file"},{"location":"os/modules/fs/fs/fs_seek/","text":"fs_seek int fs_seek ( struct fs_file *file , uint32_t offset ) Positions a file's read and write pointer at the specified offset. The offset is expressed as the number of bytes from the start of the file (i.e., seeking to offset 0 places the pointer at the first byte in the file). Arguments Argument Description file Pointer to the file to reposition offset The 0-based file offset to seek to Returned values 0 on success FS error code on failure Notes If a file is opened in append mode, its write pointer is always positioned at the end of the file. Calling this function on such a file only affects the read pointer. Header file #include \"fs/fs.h\" Example The following example reads four bytes from a file, starting at an offset of eight. int read_part1_middle ( void ) { struct fs_file *file ; uint32_t bytes_read ; uint8_t buf [ 4 ]; int rc ; rc = fs_open ( \"/data/parts/1.bin\" , FS_ACCESS_READ , &file ); if ( rc == 0 ) { /* Advance to offset 8. */ rc = fs_seek ( file , 8 ); if ( rc == 0 ) { /* Read bytes 8, 9, 10, and 11. */ rc = fs_read ( file , 4 , buf , &bytes_read ); if ( rc == 0 ) { /* buf now contains up to 4 bytes of file data. */ console_printf ( \"read %u bytes\\n\" , bytes_read ) } } /* Close the file. */ fs_close ( file ); } return rc == 0 ? 0 : -1 ; }","title":"fs_seek"},{"location":"os/modules/fs/fs/fs_seek/#fs_seek","text":"int fs_seek ( struct fs_file *file , uint32_t offset ) Positions a file's read and write pointer at the specified offset. The offset is expressed as the number of bytes from the start of the file (i.e., seeking to offset 0 places the pointer at the first byte in the file).","title":"fs_seek"},{"location":"os/modules/fs/fs/fs_seek/#arguments","text":"Argument Description file Pointer to the file to reposition offset The 0-based file offset to seek to","title":"Arguments"},{"location":"os/modules/fs/fs/fs_seek/#returned-values","text":"0 on success FS error code on failure","title":"Returned values"},{"location":"os/modules/fs/fs/fs_seek/#notes","text":"If a file is opened in append mode, its write pointer is always positioned at the end of the file. Calling this function on such a file only affects the read pointer.","title":"Notes"},{"location":"os/modules/fs/fs/fs_seek/#header-file","text":"#include \"fs/fs.h\"","title":"Header file"},{"location":"os/modules/fs/fs/fs_seek/#example","text":"The following example reads four bytes from a file, starting at an offset of eight. int read_part1_middle ( void ) { struct fs_file *file ; uint32_t bytes_read ; uint8_t buf [ 4 ]; int rc ; rc = fs_open ( \"/data/parts/1.bin\" , FS_ACCESS_READ , &file ); if ( rc == 0 ) { /* Advance to offset 8. */ rc = fs_seek ( file , 8 ); if ( rc == 0 ) { /* Read bytes 8, 9, 10, and 11. */ rc = fs_read ( file , 4 , buf , &bytes_read ); if ( rc == 0 ) { /* buf now contains up to 4 bytes of file data. */ console_printf ( \"read %u bytes\\n\" , bytes_read ) } } /* Close the file. */ fs_close ( file ); } return rc == 0 ? 0 : -1 ; }","title":"Example"},{"location":"os/modules/fs/fs/fs_unlink/","text":"fs_unlink int fs_unlink ( const char *filename ) Unlinks the file or directory at the specified path. This is the function to use if you want to delete a file or directory from the disk. If the path refers to a directory, all the directory's descendants are recursively unlinked. Any open file handles referring to an unlinked file remain valid, and can be read from and written to as long as they remain open. Arguments Argument Description filename The path of the file or directory to unlink Returned values 0 on success FS error code on failure Header file #include \"fs/fs.h\" Example The following example creates a file and then immediately unlinks it. By unlinking the file, this function prevents other OS tasks from accessing it. When the function closes the file, it is deleted from the disk. int process_data ( void ) { struct fs_file *file ; int rc ; /* If the file doesn't exist, create it. If it does exist, truncate it to * zero bytes. */ rc = fs_open ( \"/tmp/buffer.bin\" , FS_ACCESS_WRITE | FS_ACCESS_TRUNCATE , &file ); if ( rc == 0 ) { /* Unlink the file so that other tasks cannot access it. */ fs_unlink ( \"/tmp/buffer.bin\" ) /* <use the file as a data buffer> */ /* Close the file. This operation causes the file to be deleted from * the disk because it was unlinked earlier (and it has no other open * file handles). */ fs_close ( file ); } return rc == 0 ? 0 : -1 ; }","title":"fs_unlink"},{"location":"os/modules/fs/fs/fs_unlink/#fs_unlink","text":"int fs_unlink ( const char *filename ) Unlinks the file or directory at the specified path. This is the function to use if you want to delete a file or directory from the disk. If the path refers to a directory, all the directory's descendants are recursively unlinked. Any open file handles referring to an unlinked file remain valid, and can be read from and written to as long as they remain open.","title":"fs_unlink"},{"location":"os/modules/fs/fs/fs_unlink/#arguments","text":"Argument Description filename The path of the file or directory to unlink","title":"Arguments"},{"location":"os/modules/fs/fs/fs_unlink/#returned-values","text":"0 on success FS error code on failure","title":"Returned values"},{"location":"os/modules/fs/fs/fs_unlink/#header-file","text":"#include \"fs/fs.h\"","title":"Header file"},{"location":"os/modules/fs/fs/fs_unlink/#example","text":"The following example creates a file and then immediately unlinks it. By unlinking the file, this function prevents other OS tasks from accessing it. When the function closes the file, it is deleted from the disk. int process_data ( void ) { struct fs_file *file ; int rc ; /* If the file doesn't exist, create it. If it does exist, truncate it to * zero bytes. */ rc = fs_open ( \"/tmp/buffer.bin\" , FS_ACCESS_WRITE | FS_ACCESS_TRUNCATE , &file ); if ( rc == 0 ) { /* Unlink the file so that other tasks cannot access it. */ fs_unlink ( \"/tmp/buffer.bin\" ) /* <use the file as a data buffer> */ /* Close the file. This operation causes the file to be deleted from * the disk because it was unlinked earlier (and it has no other open * file handles). */ fs_close ( file ); } return rc == 0 ? 0 : -1 ; }","title":"Example"},{"location":"os/modules/fs/fs/fs_write/","text":"fs_write int fs_write ( struct fs_file *file , const void *data , int len ) Writes the supplied data to the current offset of the specified file handle. Arguments Argument Description file Pointer to the file to write to data The data to write len The number of bytes to write Returned values 0 on success FS error code on failure Notes For files opened in append mode, the specified data is always written to the end. Header file #include \"fs/fs.h\" Example int write_config ( void ) { struct fs_file *file ; int rc ; /* If the file doesn't exist, create it. If it does exist, truncate it to * zero bytes. */ rc = fs_open ( \"/settings/config.txt\" , FS_ACCESS_WRITE | FS_ACCESS_TRUNCATE , &file ); if ( rc == 0 ) { /* Write 5 bytes of data to the file. */ rc = fs_write ( file , \"hello\" , 5 ); if ( rc == 0 ) { /* The file should now contain exactly five bytes. */ assert ( fs_filelen ( file ) == 5 ); } /* Close the file. */ fs_close ( file ); } return rc == 0 ? 0 : -1 ; }","title":"fs_write"},{"location":"os/modules/fs/fs/fs_write/#fs_write","text":"int fs_write ( struct fs_file *file , const void *data , int len ) Writes the supplied data to the current offset of the specified file handle.","title":"fs_write"},{"location":"os/modules/fs/fs/fs_write/#arguments","text":"Argument Description file Pointer to the file to write to data The data to write len The number of bytes to write","title":"Arguments"},{"location":"os/modules/fs/fs/fs_write/#returned-values","text":"0 on success FS error code on failure","title":"Returned values"},{"location":"os/modules/fs/fs/fs_write/#notes","text":"For files opened in append mode, the specified data is always written to the end.","title":"Notes"},{"location":"os/modules/fs/fs/fs_write/#header-file","text":"#include \"fs/fs.h\"","title":"Header file"},{"location":"os/modules/fs/fs/fs_write/#example","text":"int write_config ( void ) { struct fs_file *file ; int rc ; /* If the file doesn't exist, create it. If it does exist, truncate it to * zero bytes. */ rc = fs_open ( \"/settings/config.txt\" , FS_ACCESS_WRITE | FS_ACCESS_TRUNCATE , &file ); if ( rc == 0 ) { /* Write 5 bytes of data to the file. */ rc = fs_write ( file , \"hello\" , 5 ); if ( rc == 0 ) { /* The file should now contain exactly five bytes. */ assert ( fs_filelen ( file ) == 5 ); } /* Close the file. */ fs_close ( file ); } return rc == 0 ? 0 : -1 ; }","title":"Example"},{"location":"os/modules/fs/fs/fsutil_read_file/","text":"fsutil_read_file int fsutil_read_file ( const char *path , uint32_t offset , uint32_t len , void *dst , uint32_t *out_len ) Calls fs_open(), fs_read(), and fs_close() to open a file at the specified path, retrieve data from the file starting from the specified offset, and close the file and invalidate the file handle. Arguments Argument Description path Pointer to the directory entry to query offset Position of the file's read pointer len Number of bytes to attempt to read dst Destination buffer to read into out_len On success, the number of bytes actually read gets written here. Pass null if you don't care. Returned values 0 on success FS error code on failure Notes This is a convenience function. It is useful when the amount of data to be read from the file is small (i.e., all the data read can easily fit in a single buffer). Header file #include \"fs/fs.h\" Example This example demonstrates reading a small text file in its entirety and printing its contents to the console. int print_status ( void ) { uint32_t bytes_read ; uint8_t buf [ 16 ]; int rc ; /* Read up to 15 bytes from the start of the file. */ rc = fsutil_read_file ( \"/cfg/status.txt\" , 0 , sizeof buf - 1 , buf , &bytes_read ); if ( rc != 0 ) return -1 ; /* Null-terminate the string just read. */ buf [ bytes_read ] = '\\0' ; /* Print the file contents to the console. */ console_printf ( \"%s\\n\" , buf ); return 0 ; }","title":"fsutil_read_file"},{"location":"os/modules/fs/fs/fsutil_read_file/#fsutil_read_file","text":"int fsutil_read_file ( const char *path , uint32_t offset , uint32_t len , void *dst , uint32_t *out_len ) Calls fs_open(), fs_read(), and fs_close() to open a file at the specified path, retrieve data from the file starting from the specified offset, and close the file and invalidate the file handle.","title":"fsutil_read_file"},{"location":"os/modules/fs/fs/fsutil_read_file/#arguments","text":"Argument Description path Pointer to the directory entry to query offset Position of the file's read pointer len Number of bytes to attempt to read dst Destination buffer to read into out_len On success, the number of bytes actually read gets written here. Pass null if you don't care.","title":"Arguments"},{"location":"os/modules/fs/fs/fsutil_read_file/#returned-values","text":"0 on success FS error code on failure","title":"Returned values"},{"location":"os/modules/fs/fs/fsutil_read_file/#notes","text":"This is a convenience function. It is useful when the amount of data to be read from the file is small (i.e., all the data read can easily fit in a single buffer).","title":"Notes"},{"location":"os/modules/fs/fs/fsutil_read_file/#header-file","text":"#include \"fs/fs.h\"","title":"Header file"},{"location":"os/modules/fs/fs/fsutil_read_file/#example","text":"This example demonstrates reading a small text file in its entirety and printing its contents to the console. int print_status ( void ) { uint32_t bytes_read ; uint8_t buf [ 16 ]; int rc ; /* Read up to 15 bytes from the start of the file. */ rc = fsutil_read_file ( \"/cfg/status.txt\" , 0 , sizeof buf - 1 , buf , &bytes_read ); if ( rc != 0 ) return -1 ; /* Null-terminate the string just read. */ buf [ bytes_read ] = '\\0' ; /* Print the file contents to the console. */ console_printf ( \"%s\\n\" , buf ); return 0 ; }","title":"Example"},{"location":"os/modules/fs/fs/fsutil_write_file/","text":"fsutil_write_file int fsutil_write_file ( const char *path , const void *data , uint32_t len ) Calls fs_open(), fs_write(), and fs_close() to open a file at the specified path, write the supplied data to the current offset of the specified file handle, and close the file and invalidate the file handle. If the specified file already exists, it is truncated and overwritten with the specified data. Arguments Argument Description path Pointer to the file to write to data The data to write len The number of bytes to write Returned values 0 on success FS error code on failure Header file #include \"fs/fs.h\" Example This example creates a 4-byte file. int write_id ( void ) { int rc ; /* Create the parent directory. */ rc = fs_mkdir ( \"/cfg\" ); if ( rc != 0 && rc != FS_EALREADY ) { return -1 ; } /* Create a file and write four bytes to it. */ rc = fsutil_write_file ( \"/cfg/id.txt\" , \"1234\" , 4 ); if ( rc != 0 ) { return -1 ; } return 0 ; }","title":"fsutil_write_file"},{"location":"os/modules/fs/fs/fsutil_write_file/#fsutil_write_file","text":"int fsutil_write_file ( const char *path , const void *data , uint32_t len ) Calls fs_open(), fs_write(), and fs_close() to open a file at the specified path, write the supplied data to the current offset of the specified file handle, and close the file and invalidate the file handle. If the specified file already exists, it is truncated and overwritten with the specified data.","title":"fsutil_write_file"},{"location":"os/modules/fs/fs/fsutil_write_file/#arguments","text":"Argument Description path Pointer to the file to write to data The data to write len The number of bytes to write","title":"Arguments"},{"location":"os/modules/fs/fs/fsutil_write_file/#returned-values","text":"0 on success FS error code on failure","title":"Returned values"},{"location":"os/modules/fs/fs/fsutil_write_file/#header-file","text":"#include \"fs/fs.h\"","title":"Header file"},{"location":"os/modules/fs/fs/fsutil_write_file/#example","text":"This example creates a 4-byte file. int write_id ( void ) { int rc ; /* Create the parent directory. */ rc = fs_mkdir ( \"/cfg\" ); if ( rc != 0 && rc != FS_EALREADY ) { return -1 ; } /* Create a file and write four bytes to it. */ rc = fsutil_write_file ( \"/cfg/id.txt\" , \"1234\" , 4 ); if ( rc != 0 ) { return -1 ; } return 0 ; }","title":"Example"},{"location":"os/modules/fs/nffs/nffs/","text":"Newtron Flash Filesystem (nffs) Mynewt includes the Newtron Flash File System (nffs). This file system is designed with two priorities that makes it suitable for embedded use: Minimal RAM usage Reliability Mynewt also provides an abstraction layer API (fs) to allow you to swap out nffs with a different file system of your choice. Description Areas At the top level, an nffs disk is partitioned into areas . An area is a region of disk with the following properties: An area can be fully erased without affecting any other areas. Writing to one area does not restrict writes to other areas. Regarding property 1: Generally, flash hardware divides its memory space into \"blocks.\" When erasing flash, entire blocks must be erased in a single operation; partial erases are not possible. Regarding property 2: Furthermore, some flash hardware imposes a restriction with regards to writes: writes within a block must be strictly sequential. For example, if you wish to write to the first 16 bytes of a block, you must write bytes 1 through 15 before writing byte 16. This restriction only applies at the block level; writes to one block have no effect on what parts of other blocks can be written. Thus, each area must comprise a discrete number of blocks. Initialization Before nffs can be used, it must be initialized. There are two means of initializing an nffs file system: Restore an existing file system via detection. Create a new file system via formatting. A typical initialization sequence is the following: Detect an nffs file system in a specific region of flash. If no file system was detected, format a new file system in the same flash region. Both methods require the user to describe how the flash memory should be divided into nffs areas. This is accomplished with an array of struct nffs_area_desc . Typically, a product's flash layout is exposed via its BSP-specific bsp_flash_dev() function. This function retrieves the layout of the specified flash device resident in the BSP. The result of this function can then be converted into the struct nffs_area_desc[] that nffs requires. The below example, taken from the slinky project, illustrates the nffs initialization procedure. /*** hw/hal/include/hal/flash_map.h */ /* * Flash area types */ #define FLASH_AREA_BOOTLOADER 0 #define FLASH_AREA_IMAGE_0 1 #define FLASH_AREA_IMAGE_1 2 #define FLASH_AREA_IMAGE_SCRATCH 3 #define FLASH_AREA_NFFS 4 /*** project/slinky/src/main.c */ int main ( int argc , char **argv ) { int rc ; int cnt ; /* NFFS_AREA_MAX is defined in the BSP-specified bsp.h header file. */ struct nffs_area_desc descs [ NFFS_AREA_MAX ]; /* Initialize nffs's internal state. */ rc = nffs_init (); assert ( rc == 0 ); /* Convert the set of flash blocks we intend to use for nffs into an array * of nffs area descriptors. */ cnt = NFFS_AREA_MAX ; rc = flash_area_to_nffs_desc ( FLASH_AREA_NFFS , &cnt , descs ); assert ( rc == 0 ); /* Attempt to restore an existing nffs file system from flash. */ if ( nffs_detect ( descs ) == FS_ECORRUPT ) { /* No valid nffs instance detected; format a new one. */ rc = nffs_format ( descs ); assert ( rc == 0 ); } /* [ ... ] */ } After nffs has been initialized, the application can access the file system via the file system abstraction layer . Configuration The nffs file system is configured by populating fields in a global struct nffs_config instance. Each field in the structure corresponds to a setting. All configuration must be done prior to calling nffs_init(). The global struct nffs_config instance is exposed in nffs/nffs.h as follows: extern struct nffs_config nffs_config ; Data Structures The fs/nffs package exposes the following data structures: Struct Description struct nffs_area_desc Descriptor for a single nffs area. struct nffs_config Configuration struct for nffs. API The functions available in this OS feature are: Function Description nffs_detect Searches for a valid nffs file system among the specified areas. nffs_format Erases all the specified areas and initializes them with a clean nffs file system. nffs_init Initializes internal nffs memory and data structures. Miscellaneous measures RAM usage: 24 bytes per inode 12 bytes per data block 36 bytes per inode cache entry 32 bytes per data block cache entry Maximum filename size: 256 characters (no null terminator required) Disallowed filename characters: '/' and '\\0' Internals nffs implementation details can be found here: nffs_internals Future enhancements Error correction. Encryption. Compression.","title":"toc"},{"location":"os/modules/fs/nffs/nffs/#newtron-flash-filesystem-nffs","text":"Mynewt includes the Newtron Flash File System (nffs). This file system is designed with two priorities that makes it suitable for embedded use: Minimal RAM usage Reliability Mynewt also provides an abstraction layer API (fs) to allow you to swap out nffs with a different file system of your choice.","title":"Newtron Flash Filesystem (nffs)"},{"location":"os/modules/fs/nffs/nffs/#description","text":"","title":"Description"},{"location":"os/modules/fs/nffs/nffs/#areas","text":"At the top level, an nffs disk is partitioned into areas . An area is a region of disk with the following properties: An area can be fully erased without affecting any other areas. Writing to one area does not restrict writes to other areas. Regarding property 1: Generally, flash hardware divides its memory space into \"blocks.\" When erasing flash, entire blocks must be erased in a single operation; partial erases are not possible. Regarding property 2: Furthermore, some flash hardware imposes a restriction with regards to writes: writes within a block must be strictly sequential. For example, if you wish to write to the first 16 bytes of a block, you must write bytes 1 through 15 before writing byte 16. This restriction only applies at the block level; writes to one block have no effect on what parts of other blocks can be written. Thus, each area must comprise a discrete number of blocks.","title":"Areas"},{"location":"os/modules/fs/nffs/nffs/#initialization","text":"Before nffs can be used, it must be initialized. There are two means of initializing an nffs file system: Restore an existing file system via detection. Create a new file system via formatting. A typical initialization sequence is the following: Detect an nffs file system in a specific region of flash. If no file system was detected, format a new file system in the same flash region. Both methods require the user to describe how the flash memory should be divided into nffs areas. This is accomplished with an array of struct nffs_area_desc . Typically, a product's flash layout is exposed via its BSP-specific bsp_flash_dev() function. This function retrieves the layout of the specified flash device resident in the BSP. The result of this function can then be converted into the struct nffs_area_desc[] that nffs requires. The below example, taken from the slinky project, illustrates the nffs initialization procedure. /*** hw/hal/include/hal/flash_map.h */ /* * Flash area types */ #define FLASH_AREA_BOOTLOADER 0 #define FLASH_AREA_IMAGE_0 1 #define FLASH_AREA_IMAGE_1 2 #define FLASH_AREA_IMAGE_SCRATCH 3 #define FLASH_AREA_NFFS 4 /*** project/slinky/src/main.c */ int main ( int argc , char **argv ) { int rc ; int cnt ; /* NFFS_AREA_MAX is defined in the BSP-specified bsp.h header file. */ struct nffs_area_desc descs [ NFFS_AREA_MAX ]; /* Initialize nffs's internal state. */ rc = nffs_init (); assert ( rc == 0 ); /* Convert the set of flash blocks we intend to use for nffs into an array * of nffs area descriptors. */ cnt = NFFS_AREA_MAX ; rc = flash_area_to_nffs_desc ( FLASH_AREA_NFFS , &cnt , descs ); assert ( rc == 0 ); /* Attempt to restore an existing nffs file system from flash. */ if ( nffs_detect ( descs ) == FS_ECORRUPT ) { /* No valid nffs instance detected; format a new one. */ rc = nffs_format ( descs ); assert ( rc == 0 ); } /* [ ... ] */ } After nffs has been initialized, the application can access the file system via the file system abstraction layer .","title":"Initialization"},{"location":"os/modules/fs/nffs/nffs/#configuration","text":"The nffs file system is configured by populating fields in a global struct nffs_config instance. Each field in the structure corresponds to a setting. All configuration must be done prior to calling nffs_init(). The global struct nffs_config instance is exposed in nffs/nffs.h as follows: extern struct nffs_config nffs_config ;","title":"Configuration"},{"location":"os/modules/fs/nffs/nffs/#data-structures","text":"The fs/nffs package exposes the following data structures: Struct Description struct nffs_area_desc Descriptor for a single nffs area. struct nffs_config Configuration struct for nffs.","title":"Data Structures"},{"location":"os/modules/fs/nffs/nffs/#api","text":"The functions available in this OS feature are: Function Description nffs_detect Searches for a valid nffs file system among the specified areas. nffs_format Erases all the specified areas and initializes them with a clean nffs file system. nffs_init Initializes internal nffs memory and data structures.","title":"API"},{"location":"os/modules/fs/nffs/nffs/#miscellaneous-measures","text":"RAM usage: 24 bytes per inode 12 bytes per data block 36 bytes per inode cache entry 32 bytes per data block cache entry Maximum filename size: 256 characters (no null terminator required) Disallowed filename characters: '/' and '\\0'","title":"Miscellaneous measures"},{"location":"os/modules/fs/nffs/nffs/#internals","text":"nffs implementation details can be found here: nffs_internals","title":"Internals"},{"location":"os/modules/fs/nffs/nffs/#future-enhancements","text":"Error correction. Encryption. Compression.","title":"Future enhancements"},{"location":"os/modules/fs/nffs/nffs_area_desc/","text":"struct nffs_area_desc struct nffs_area_desc { uint32_t nad_offset ; /* Flash offset of start of area. */ uint32_t nad_length ; /* Size of area, in bytes. */ uint8_t nad_flash_id ; /* Logical flash id */ }; Descriptor for a single nffs area. An area is a region of disk with the following properties: An area can be fully erased without affecting any other areas. Writing to one area does not restrict writes to other areas. Regarding property 1: Generally, flash hardware divides its memory space into \"blocks.\" When erasing flash, entire blocks must be erased in a single operation; partial erases are not possible. Regarding property 2: Furthermore, some flash hardware imposes a restriction with regards to writes: writes within a block must be strictly sequential. For example, if you wish to write to the first 16 bytes of a block, you must write bytes 1 through 15 before writing byte 16. This restriction only applies at the block level; writes to one block have no effect on what parts of other blocks can be written. Thus, each area must comprise a discrete number of blocks. An array of area descriptors is terminated by an entry with a nad_length value of 0. Notes Typically, a product's flash layout is exposed via its BSP-specific bsp_flash_dev() function. This function retrieves the layout of the specified flash device resident in the BSP. The result of this function can then be converted into the struct nffs_area_desc[] that nffs requires. Header file #include \"nffs/nffs.h\"","title":"struct nffs_area_desc"},{"location":"os/modules/fs/nffs/nffs_area_desc/#struct-nffs_area_desc","text":"struct nffs_area_desc { uint32_t nad_offset ; /* Flash offset of start of area. */ uint32_t nad_length ; /* Size of area, in bytes. */ uint8_t nad_flash_id ; /* Logical flash id */ }; Descriptor for a single nffs area. An area is a region of disk with the following properties: An area can be fully erased without affecting any other areas. Writing to one area does not restrict writes to other areas. Regarding property 1: Generally, flash hardware divides its memory space into \"blocks.\" When erasing flash, entire blocks must be erased in a single operation; partial erases are not possible. Regarding property 2: Furthermore, some flash hardware imposes a restriction with regards to writes: writes within a block must be strictly sequential. For example, if you wish to write to the first 16 bytes of a block, you must write bytes 1 through 15 before writing byte 16. This restriction only applies at the block level; writes to one block have no effect on what parts of other blocks can be written. Thus, each area must comprise a discrete number of blocks. An array of area descriptors is terminated by an entry with a nad_length value of 0.","title":"struct nffs_area_desc"},{"location":"os/modules/fs/nffs/nffs_area_desc/#notes","text":"Typically, a product's flash layout is exposed via its BSP-specific bsp_flash_dev() function. This function retrieves the layout of the specified flash device resident in the BSP. The result of this function can then be converted into the struct nffs_area_desc[] that nffs requires.","title":"Notes"},{"location":"os/modules/fs/nffs/nffs_area_desc/#header-file","text":"#include \"nffs/nffs.h\"","title":"Header file"},{"location":"os/modules/fs/nffs/nffs_config/","text":"struct nffs_config struct nffs_config { /** Maximum number of inodes; default=1024. */ uint32_t nc_num_inodes ; /** Maximum number of data blocks; default=4096. */ uint32_t nc_num_blocks ; /** Maximum number of open files; default=4. */ uint32_t nc_num_files ; /** Inode cache size; default=4. */ uint32_t nc_num_cache_inodes ; /** Data block cache size; default=64. */ uint32_t nc_num_cache_blocks ; }; The file system is configured by populating fields in a global struct nffs_config instance. Each field in the structure corresponds to a setting. All configuration must be done prior to calling nffs_init(). Any fields that are set to 0 (or not set at all) inherit the corresponding default value. This means that it is impossible to configure any setting with a value of zero. Notes The global struct nffs_config instance is exposed in nffs/nffs.h as follows: extern struct nffs_config nffs_config ; Header file #include \"nffs/nffs.h\"","title":"struct nffs_config"},{"location":"os/modules/fs/nffs/nffs_config/#struct-nffs_config","text":"struct nffs_config { /** Maximum number of inodes; default=1024. */ uint32_t nc_num_inodes ; /** Maximum number of data blocks; default=4096. */ uint32_t nc_num_blocks ; /** Maximum number of open files; default=4. */ uint32_t nc_num_files ; /** Inode cache size; default=4. */ uint32_t nc_num_cache_inodes ; /** Data block cache size; default=64. */ uint32_t nc_num_cache_blocks ; }; The file system is configured by populating fields in a global struct nffs_config instance. Each field in the structure corresponds to a setting. All configuration must be done prior to calling nffs_init(). Any fields that are set to 0 (or not set at all) inherit the corresponding default value. This means that it is impossible to configure any setting with a value of zero.","title":"struct nffs_config"},{"location":"os/modules/fs/nffs/nffs_config/#notes","text":"The global struct nffs_config instance is exposed in nffs/nffs.h as follows: extern struct nffs_config nffs_config ;","title":"Notes"},{"location":"os/modules/fs/nffs/nffs_config/#header-file","text":"#include \"nffs/nffs.h\"","title":"Header file"},{"location":"os/modules/fs/nffs/nffs_detect/","text":"nffs_detect int nffs_detect ( const struct nffs_area_desc *area_descs ) Searches for a valid nffs file system among the specified areas. This function succeeds if a file system is detected among any subset of the supplied areas. If the area set does not contain a valid file system, a new one can be created via a separate call to nffs_format(). Arguments Argument Description area_descs The set of areas to search. This array must be terminated with a 0-length area. Returned values 0 on success FS_ECORRUPT if no valid file system was detected Other FS error code on failure Header file #include \"nffs/nffs.h\" Example /*** hw/hal/include/hal/flash_map.h */ /* * Flash area types */ #define FLASH_AREA_BOOTLOADER 0 #define FLASH_AREA_IMAGE_0 1 #define FLASH_AREA_IMAGE_1 2 #define FLASH_AREA_IMAGE_SCRATCH 3 #define FLASH_AREA_NFFS 4 /*** project/slinky/src/main.c */ int main ( int argc , char **argv ) { int rc ; int cnt ; /* NFFS_AREA_MAX is defined in the BSP-specified bsp.h header file. */ struct nffs_area_desc descs [ NFFS_AREA_MAX ]; /* Initialize nffs's internal state. */ rc = nffs_init (); assert ( rc == 0 ); /* Convert the set of flash blocks we intend to use for nffs into an array * of nffs area descriptors. */ cnt = NFFS_AREA_MAX ; rc = flash_area_to_nffs_desc ( FLASH_AREA_NFFS , &cnt , descs ); assert ( rc == 0 ); /* Attempt to restore an existing nffs file system from flash. */ if ( nffs_detect ( descs ) == FS_ECORRUPT ) { /* No valid nffs instance detected; format a new one. */ rc = nffs_format ( descs ); assert ( rc == 0 ); } /* [ ... ] */ }","title":"nffs_detect"},{"location":"os/modules/fs/nffs/nffs_detect/#nffs_detect","text":"int nffs_detect ( const struct nffs_area_desc *area_descs ) Searches for a valid nffs file system among the specified areas. This function succeeds if a file system is detected among any subset of the supplied areas. If the area set does not contain a valid file system, a new one can be created via a separate call to nffs_format().","title":"nffs_detect"},{"location":"os/modules/fs/nffs/nffs_detect/#arguments","text":"Argument Description area_descs The set of areas to search. This array must be terminated with a 0-length area.","title":"Arguments"},{"location":"os/modules/fs/nffs/nffs_detect/#returned-values","text":"0 on success FS_ECORRUPT if no valid file system was detected Other FS error code on failure","title":"Returned values"},{"location":"os/modules/fs/nffs/nffs_detect/#header-file","text":"#include \"nffs/nffs.h\"","title":"Header file"},{"location":"os/modules/fs/nffs/nffs_detect/#example","text":"/*** hw/hal/include/hal/flash_map.h */ /* * Flash area types */ #define FLASH_AREA_BOOTLOADER 0 #define FLASH_AREA_IMAGE_0 1 #define FLASH_AREA_IMAGE_1 2 #define FLASH_AREA_IMAGE_SCRATCH 3 #define FLASH_AREA_NFFS 4 /*** project/slinky/src/main.c */ int main ( int argc , char **argv ) { int rc ; int cnt ; /* NFFS_AREA_MAX is defined in the BSP-specified bsp.h header file. */ struct nffs_area_desc descs [ NFFS_AREA_MAX ]; /* Initialize nffs's internal state. */ rc = nffs_init (); assert ( rc == 0 ); /* Convert the set of flash blocks we intend to use for nffs into an array * of nffs area descriptors. */ cnt = NFFS_AREA_MAX ; rc = flash_area_to_nffs_desc ( FLASH_AREA_NFFS , &cnt , descs ); assert ( rc == 0 ); /* Attempt to restore an existing nffs file system from flash. */ if ( nffs_detect ( descs ) == FS_ECORRUPT ) { /* No valid nffs instance detected; format a new one. */ rc = nffs_format ( descs ); assert ( rc == 0 ); } /* [ ... ] */ }","title":"Example"},{"location":"os/modules/fs/nffs/nffs_format/","text":"nffs_format int nffs_format ( const struct nffs_area_desc *area_descs ) Erases all the specified areas and initializes them with a clean nffs file system. Arguments Argument Description area_descs The set of areas to format Returned values 0 on success FS error code on failure. Header file #include \"nffs/nffs.h\" Example /*** hw/hal/include/hal/flash_map.h */ /* * Flash area types */ #define FLASH_AREA_BOOTLOADER 0 #define FLASH_AREA_IMAGE_0 1 #define FLASH_AREA_IMAGE_1 2 #define FLASH_AREA_IMAGE_SCRATCH 3 #define FLASH_AREA_NFFS 4 /*** project/slinky/src/main.c */ int main ( int argc , char **argv ) { int rc ; int cnt ; /* NFFS_AREA_MAX is defined in the BSP-specified bsp.h header file. */ struct nffs_area_desc descs [ NFFS_AREA_MAX ]; /* Initialize nffs's internal state. */ rc = nffs_init (); assert ( rc == 0 ); /* Convert the set of flash blocks we intend to use for nffs into an array * of nffs area descriptors. */ cnt = NFFS_AREA_MAX ; rc = flash_area_to_nffs_desc ( FLASH_AREA_NFFS , &cnt , descs ); assert ( rc == 0 ); /* Attempt to restore an existing nffs file system from flash. */ if ( nffs_detect ( descs ) == FS_ECORRUPT ) { /* No valid nffs instance detected; format a new one. */ rc = nffs_format ( descs ); assert ( rc == 0 ); } /* [ ... ] */ }","title":"nffs_format"},{"location":"os/modules/fs/nffs/nffs_format/#nffs_format","text":"int nffs_format ( const struct nffs_area_desc *area_descs ) Erases all the specified areas and initializes them with a clean nffs file system.","title":"nffs_format"},{"location":"os/modules/fs/nffs/nffs_format/#arguments","text":"Argument Description area_descs The set of areas to format","title":"Arguments"},{"location":"os/modules/fs/nffs/nffs_format/#returned-values","text":"0 on success FS error code on failure.","title":"Returned values"},{"location":"os/modules/fs/nffs/nffs_format/#header-file","text":"#include \"nffs/nffs.h\"","title":"Header file"},{"location":"os/modules/fs/nffs/nffs_format/#example","text":"/*** hw/hal/include/hal/flash_map.h */ /* * Flash area types */ #define FLASH_AREA_BOOTLOADER 0 #define FLASH_AREA_IMAGE_0 1 #define FLASH_AREA_IMAGE_1 2 #define FLASH_AREA_IMAGE_SCRATCH 3 #define FLASH_AREA_NFFS 4 /*** project/slinky/src/main.c */ int main ( int argc , char **argv ) { int rc ; int cnt ; /* NFFS_AREA_MAX is defined in the BSP-specified bsp.h header file. */ struct nffs_area_desc descs [ NFFS_AREA_MAX ]; /* Initialize nffs's internal state. */ rc = nffs_init (); assert ( rc == 0 ); /* Convert the set of flash blocks we intend to use for nffs into an array * of nffs area descriptors. */ cnt = NFFS_AREA_MAX ; rc = flash_area_to_nffs_desc ( FLASH_AREA_NFFS , &cnt , descs ); assert ( rc == 0 ); /* Attempt to restore an existing nffs file system from flash. */ if ( nffs_detect ( descs ) == FS_ECORRUPT ) { /* No valid nffs instance detected; format a new one. */ rc = nffs_format ( descs ); assert ( rc == 0 ); } /* [ ... ] */ }","title":"Example"},{"location":"os/modules/fs/nffs/nffs_init/","text":"nffs_init int nffs_init ( void ) Initializes internal nffs memory and data structures. This must be called before any nffs operations are attempted. Returned values 0 on success FS error code on failure Header file #include \"nffs/nffs.h\"","title":"nffs_init"},{"location":"os/modules/fs/nffs/nffs_init/#nffs_init","text":"int nffs_init ( void ) Initializes internal nffs memory and data structures. This must be called before any nffs operations are attempted.","title":"nffs_init"},{"location":"os/modules/fs/nffs/nffs_init/#returned-values","text":"0 on success FS error code on failure","title":"Returned values"},{"location":"os/modules/fs/nffs/nffs_init/#header-file","text":"#include \"nffs/nffs.h\"","title":"Header file"},{"location":"os/modules/fs/nffs/nffs_internals/","text":"Internals of nffs Disk structure On disk, each area is prefixed with the following header: /** On-disk representation of an area header. */ struct nffs_disk_area { uint32_t nda_magic [ 4 ]; /* NFFS_AREA_MAGIC{0,1,2,3} */ uint32_t nda_length ; /* Total size of area, in bytes. */ uint8_t nda_ver ; /* Current nffs version: 0 */ uint8_t nda_gc_seq ; /* Garbage collection count. */ uint8_t reserved8 ; uint8_t nda_id ; /* 0xff if scratch area. */ }; Beyond its header, an area contains a sequence of disk objects, representing the contents of the file system. There are two types of objects: inodes and data blocks . An inode represents a file or directory; a data block represents part of a file's contents. /** On-disk representation of an inode (file or directory). */ struct nffs_disk_inode { uint32_t ndi_magic ; /* NFFS_INODE_MAGIC */ uint32_t ndi_id ; /* Unique object ID. */ uint32_t ndi_seq ; /* Sequence number; greater supersedes lesser. */ uint32_t ndi_parent_id ; /* Object ID of parent directory inode. */ uint8_t reserved8 ; uint8_t ndi_filename_len ; /* Length of filename, in bytes. */ uint16_t ndi_crc16 ; /* Covers rest of header and filename. */ /* Followed by filename. */ }; An inode filename's length cannot exceed 256 bytes. The filename is not null-terminated. The following ASCII characters are not allowed in a filename: / (slash character) \\0 (NUL character) /** On-disk representation of a data block. */ struct nffs_disk_block { uint32_t ndb_magic ; /* NFFS_BLOCK_MAGIC */ uint32_t ndb_id ; /* Unique object ID. */ uint32_t ndb_seq ; /* Sequence number; greater supersedes lesser. */ uint32_t ndb_inode_id ; /* Object ID of owning inode. */ uint32_t ndb_prev_id ; /* Object ID of previous block in file; NFFS_ID_NONE if this is the first block. */ uint16_t ndb_data_len ; /* Length of data contents, in bytes. */ uint16_t ndb_crc16 ; /* Covers rest of header and data. */ /* Followed by 'ndb_data_len' bytes of data. */ }; Each data block contains the ID of the previous data block in the file. Together, the set of blocks in a file form a reverse singly-linked list. The maximum number of data bytes that a block can contain is determined at initialization-time. The result is the greatest number which satisfies all of the following restrictions: No more than 2048. At least two maximum-sized blocks can fit in the smallest area. The 2048 number was chosen somewhat arbitrarily, and may change in the future. ID space All disk objects have a unique 32-bit ID. The ID space is partitioned as follows: ID range Node type 0x00000000 - 0x0fffffff Directory inodes 0x10000000 - 0x7fffffff File inodes 0x80000000 - 0xfffffffe Data blocks 0xffffffff Reserved (NFFS_ID_NONE) Scratch area A valid nffs file system must contain a single \"scratch area.\" The scratch area does not contain any objects of its own, and is only used during garbage collection. The scratch area must have a size greater than or equal to each of the other areas in flash. RAM representation Every object in the file system is stored in a 256-entry hash table. An object's hash key is derived from its 32-bit ID. Each list in the hash table is sorted by time of use; most-recently-used is at the front of the list. All objects are represented by the following structure: /** * What gets stored in the hash table. Each entry represents a data block or * an inode. */ struct nffs_hash_entry { SLIST_ENTRY ( nffs_hash_entry ) nhe_next ; uint32_t nhe_id ; /* 0 - 0x7fffffff if inode; else if block. */ uint32_t nhe_flash_loc ; /* Upper-byte = area idx; rest = area offset. */ }; For each data block, the above structure is all that is stored in RAM. To acquire more information about a data block, the block header must be read from flash. Inodes require a fuller RAM representation to capture the structure of the file system. There are two types of inodes: files and directories . Each inode hash entry is actually an instance of the following structure: /** Each inode hash entry is actually one of these. */ struct nffs_inode_entry { struct nffs_hash_entry nie_hash_entry ; SLIST_ENTRY ( nffs_inode_entry ) nie_sibling_next ; union { struct nffs_inode_list nie_child_list ; /* If directory */ struct nffs_hash_entry *nie_last_block_entry ; /* If file */ }; uint8_t nie_refcnt ; }; A directory inode contains a list of its child files and directories ( fie_child_list ). These entries are sorted alphabetically using the ASCII character set. A file inode contains a pointer to the last data block in the file ( nie_last_block_entry ). For most file operations, the reversed block list must be walked backwards. This introduces a number of speed inefficiencies: All data blocks must be read to determine the length of the file. Data blocks often need to be processed sequentially. The reversed nature of the block list transforms this from linear time to an O(n^2) operation. Furthermore, obtaining information about any constituent data block requires a separate flash read. Inode cache and Data Block cache The speed issues are addressed by a pair of caches. Cached inodes entries contain the file length and a much more convenient doubly-linked list of cached data blocks. The benefit of using caches is that the size of the caches need not be proportional to the size of the file system. In other words, caches can address speed efficiency concerns without negatively impacting the file system's scalability. nffs requires both caches during normal operation, so it is not possible to disable them. However, the cache sizes are configurable, and both caches can be configured with a size of one if RAM usage must be minimized. The following data structures are used in the inode and data block caches. /** Full data block representation; not stored permanently in RAM. */ struct nffs_block { struct nffs_hash_entry *nb_hash_entry ; /* Points to real block entry. */ uint32_t nb_seq ; /* Sequence number; greater supersedes lesser. */ struct nffs_inode_entry *nb_inode_entry ; /* Owning inode. */ struct nffs_hash_entry *nb_prev ; /* Previous block in file. */ uint16_t nb_data_len ; /* # of data bytes in block. */ uint16_t reserved16 ; }; /** Represents a single cached data block. */ struct nffs_cache_block { TAILQ_ENTRY ( nffs_cache_block ) ncb_link ; /* Next / prev cached block. */ struct nffs_block ncb_block ; /* Full data block. */ uint32_t ncb_file_offset ; /* File offset of this block. */ }; /** Full inode representation; not stored permanently in RAM. */ struct nffs_inode { struct nffs_inode_entry *ni_inode_entry ; /* Points to real inode entry. */ uint32_t ni_seq ; /* Sequence number; greater supersedes lesser. */ struct nffs_inode_entry *ni_parent ; /* Points to parent directory. */ uint8_t ni_filename_len ; /* # chars in filename. */ uint8_t ni_filename [ NFFS_SHORT_FILENAME_LEN ]; /* First 3 bytes. */ }; /** Doubly-linked tail queue of cached blocks; contained in cached inodes. */ TAILQ_HEAD ( nffs_block_cache_list , nffs_block_cache_entry ); /** Represents a single cached file inode. */ struct nffs_cache_inode { TAILQ_ENTRY ( nffs_cache_inode ) nci_link ; /* Sorted; LRU at tail. */ struct nffs_inode nci_inode ; /* Full inode. */ struct nffs_cache_block_list nci_block_list ; /* List of cached blocks. */ uint32_t nci_file_size ; /* Total file size. */ }; Only file inodes are cached; directory inodes are never cached. Within a cached inode, all cached data blocks are contiguous. E.g., if the start and end of a file are cached, then the middle must also be cached. A data block is only cached if its owning file is also cached. Internally, cached inodes are stored in a singly-linked list, ordered by time of use. The most-recently-used entry is the first element in the list. If a new inode needs to be cached, but the inode cache is full, the least-recently-used entry is freed to make room for the new one. The following operations cause an inode to be cached: Querying a file's length. Seeking within a file. Reading from a file. Writing to a file. The following operations cause a data block to be cached: Reading from the block. Writing to the block. If one of the above operations is applied to a data block that is not currently cached, nffs uses the following procedure to cache the necessary block: If none of the owning inode's blocks are currently cached, allocate a cached block entry corresponding to the requested block and insert it into the inode's list. Else if the requested file offset is less than that of the first cached block, bridge the gap between the inode's sequence of cached blocks and the block that now needs to be cached. This is accomplished by caching each block in the gap, finishing with the requested block. Else (the requested offset is beyond the end of the cache), If the requested offset belongs to the block that immediately follows the end of the cache, cache the block and append it to the list. Else, clear the cache, and populate it with the single entry corresponding to the requested block. If the system is unable to allocate a cached block entry at any point during the above procedure, the system frees up other blocks currently in the cache. This is accomplished as follows: Iterate the inode cache in reverse (i.e., start with the least-recently-used entry). For each entry: If the entry's cached block list is empty, advance to the next entry. Else, free all the cached blocks in the entry's list. Because the system imposes a minimum block cache size of one, the above procedure will always reclaim at least one cache block entry. The above procedure may result in the freeing of the block list that belongs to the very inode being operated on. This is OK, as the final block to get cached is always the block being requested. Detection The file system detection process consists of scanning a specified set of flash regions for valid nffs areas, and then populating the RAM representation of the file system with the detected objects. Detection is initiated with the nffs_detect() function. Not every area descriptor passed to nffs_detect() needs to reference a valid nffs area. Detection is successful as long as a complete file system is detected somewhere in the specified regions of flash. If an application is unsure where a file system might be located, it can initiate detection across the entire flash region. A detected file system is valid if: At least one non-scratch area is present. At least one scratch area is present (only the first gets used if there is more than one). The root directory inode is present. During detection, each indicated region of flash is checked for a valid area header. The contents of each valid non-scratch area are then restored into the nffs RAM representation. The following procedure is applied to each object in the area: Verify the object's integrity via a crc16 check. If invalid, the object is discarded and the procedure restarts on the next object in the area. Convert the disk object into its corresponding RAM representation and insert it into the hash table. If the object is an inode, its reference count is initialized to 1, indicating ownership by its parent directory. If an object with the same ID is already present, then one supersedes the other. Accept the object with the greater sequence number and discard the other. If the object references a nonexistent inode (parent directory in the case of an inode; owning file in the case of a data block), insert a temporary \"dummy\" inode into the hash table so that inter-object links can be maintained until the absent inode is eventually restored. Dummy inodes are identified by a reference count of 0. If a delete record for an inode is encountered, the inode's parent pointer is set to null to indicate that it should be removed from RAM. If nffs encounters an object that cannot be identified (i.e., its magic number is not valid), it scans the remainder of the flash area for the next valid magic number. Upon encountering a valid object, nffs resumes the procedure described above. After all areas have been restored, a sweep is performed across the entire RAM representation so that invalid inodes can be deleted from memory. For each directory inode: If its reference count is 0 (i.e., it is a dummy), migrate its children to the /lost+found directory, and delete it from the RAM representation. This should only happen in the case of file system corruption. If its parent reference is null (i.e., it was deleted), delete it and all its children from the RAM representation. For each file inode: If its reference count is 0 (i.e., it is a dummy), delete it from the RAM representation. This should only happen in the case of file system corruption. (We should try to migrate the file to the lost+found directory in this case, as mentioned in the todo section). When an object is deleted during this sweep, it is only deleted from the RAM representation; nothing is written to disk. When objects are migrated to the lost+found directory, their parent inode reference is permanently updated on the disk. In addition, a single scratch area is identified during the detection process. The first area whose fda_id value is set to 0xff is designated as the file system scratch area. If no valid scratch area is found, the cause could be that the system was restarted while a garbage collection cycle was in progress. Such a condition is identified by the presence of two areas with the same ID. In such a case, the shorter of the two areas is erased and designated as the scratch area. Formatting A new nffs file system is created via formatting. Formatting is achieved via the nffs_format() function. During a successful format, an area header is written to each of the specified locations. One of the areas in the set is designated as the initial scratch area. Flash writes The nffs implementation always writes in a strictly sequential fashion within an area. For each area, the system keeps track of the current offset. Whenever an object gets written to an area, it gets written to that area's current offset, and the offset is increased by the object's disk size. When a write needs to be performed, the nffs implementation selects the appropriate destination area by iterating though each area until one with sufficient free space is encountered. There is no write buffering. Each call to a write function results in a write operation being sent to the flash hardware. New objects Whenever a new object is written to disk, it is assigned the following properties: ID: A unique value is selected from the 32-bit ID space, as appropriate for the object's type. Sequence number: 0 When a new file or directory is created, a corresponding inode is written to flash. Likewise, a new data block also results in the writing of a corresponding disk object. Moving/Renaming files and directories When a file or directory is moved or renamed, its corresponding inode is rewritten to flash with the following properties: ID: Unchanged Sequence number: Previous value plus one. Parent inode: As specified by the move / rename operation. Filename: As specified by the move / rename operation. Because the inode's ID is unchanged, all dependent objects remain valid. Unlinking files and directories When a file or directory is unlinked from its parent directory, a deletion record for the unlinked inode gets written to flash. The deletion record is an inode with the following properties: ID: Unchanged Sequence number: Previous value plus one. Parent inode ID: NFFS_ID_NONE When an inode is unlinked, no deletion records need to be written for the inode's dependent objects (constituent data blocks or child inodes). During the next file system detection, it is recognized that the objects belong to a deleted inode, so they are not restored into the RAM representation. If a file has an open handle at the time it gets unlinked, application code can continued to use the file handle to read and write data. All files retain a reference count, and a file isn't deleted from the RAM representation until its reference code drops to 0. Any attempt to open an unlinked file fails, even if the file is referenced by other file handles. Writing to a file The following procedure is used whenever the application code writes to a file. First, if the write operation specifies too much data to fit into a single block, the operation is split into several separate write operations. Then, for each write operation: Determine which existing blocks the write operation overlaps (n = number of overwritten blocks). If n = 0 , this is an append operation. Write a data block with the following properties: ID: New unique value. Sequence number: 0. Else (n > 1) , this write overlaps existing data. For each block in [1, 2, ... n-1] , write a new block containing the updated contents. Each new block supersedes the block it overwrites. That is, each block has the following properties: ID: Unchanged Sequence number: Previous value plus one. Write the nth block. The nth block includes all appended data, if any. As with the other blocks, its ID is unchanged and its sequence number is incremented. Appended data can only be written to the end of the file. That is, \"holes\" are not supported. Garbage collection When the file system is too full to accommodate a write operation, the system must perform garbage collection to make room. The garbage collection procedure is described below: The non-scratch area with the lowest garbage collection sequence number is selected as the \"source area.\" If there are other areas with the same sequence number, the one with the smallest flash offset is selected. The source area's ID is written to the scratch area's header, transforming it into a non-scratch ID. This former scratch area is now known as the \"destination area.\" The RAM representation is exhaustively searched for collectible objects. The following procedure is applied to each inode in the system: If the inode is resident in the source area, copy the inode record to the destination area. If the inode is a file inode, walk the inode's list of data blocks, starting with the last block in the file. Each block that is resident in the source area is copied to the destination area. If there is a run of two or more blocks that are resident in the source area, they are consolidated and copied to the destination area as a single new block (subject to the maximum block size restriction). The source area is reformatted as a scratch sector (i.e., is is fully erased, and its header is rewritten with an ID of 0xff). The area's garbage collection sequence number is incremented prior to rewriting the header. This area is now the new scratch sector.","title":"Internals"},{"location":"os/modules/fs/nffs/nffs_internals/#internals-of-nffs","text":"","title":"Internals of nffs"},{"location":"os/modules/fs/nffs/nffs_internals/#disk-structure","text":"On disk, each area is prefixed with the following header: /** On-disk representation of an area header. */ struct nffs_disk_area { uint32_t nda_magic [ 4 ]; /* NFFS_AREA_MAGIC{0,1,2,3} */ uint32_t nda_length ; /* Total size of area, in bytes. */ uint8_t nda_ver ; /* Current nffs version: 0 */ uint8_t nda_gc_seq ; /* Garbage collection count. */ uint8_t reserved8 ; uint8_t nda_id ; /* 0xff if scratch area. */ }; Beyond its header, an area contains a sequence of disk objects, representing the contents of the file system. There are two types of objects: inodes and data blocks . An inode represents a file or directory; a data block represents part of a file's contents. /** On-disk representation of an inode (file or directory). */ struct nffs_disk_inode { uint32_t ndi_magic ; /* NFFS_INODE_MAGIC */ uint32_t ndi_id ; /* Unique object ID. */ uint32_t ndi_seq ; /* Sequence number; greater supersedes lesser. */ uint32_t ndi_parent_id ; /* Object ID of parent directory inode. */ uint8_t reserved8 ; uint8_t ndi_filename_len ; /* Length of filename, in bytes. */ uint16_t ndi_crc16 ; /* Covers rest of header and filename. */ /* Followed by filename. */ }; An inode filename's length cannot exceed 256 bytes. The filename is not null-terminated. The following ASCII characters are not allowed in a filename: / (slash character) \\0 (NUL character) /** On-disk representation of a data block. */ struct nffs_disk_block { uint32_t ndb_magic ; /* NFFS_BLOCK_MAGIC */ uint32_t ndb_id ; /* Unique object ID. */ uint32_t ndb_seq ; /* Sequence number; greater supersedes lesser. */ uint32_t ndb_inode_id ; /* Object ID of owning inode. */ uint32_t ndb_prev_id ; /* Object ID of previous block in file; NFFS_ID_NONE if this is the first block. */ uint16_t ndb_data_len ; /* Length of data contents, in bytes. */ uint16_t ndb_crc16 ; /* Covers rest of header and data. */ /* Followed by 'ndb_data_len' bytes of data. */ }; Each data block contains the ID of the previous data block in the file. Together, the set of blocks in a file form a reverse singly-linked list. The maximum number of data bytes that a block can contain is determined at initialization-time. The result is the greatest number which satisfies all of the following restrictions: No more than 2048. At least two maximum-sized blocks can fit in the smallest area. The 2048 number was chosen somewhat arbitrarily, and may change in the future.","title":"Disk structure"},{"location":"os/modules/fs/nffs/nffs_internals/#id-space","text":"All disk objects have a unique 32-bit ID. The ID space is partitioned as follows: ID range Node type 0x00000000 - 0x0fffffff Directory inodes 0x10000000 - 0x7fffffff File inodes 0x80000000 - 0xfffffffe Data blocks 0xffffffff Reserved (NFFS_ID_NONE)","title":"ID space"},{"location":"os/modules/fs/nffs/nffs_internals/#scratch-area","text":"A valid nffs file system must contain a single \"scratch area.\" The scratch area does not contain any objects of its own, and is only used during garbage collection. The scratch area must have a size greater than or equal to each of the other areas in flash.","title":"Scratch area"},{"location":"os/modules/fs/nffs/nffs_internals/#ram-representation","text":"Every object in the file system is stored in a 256-entry hash table. An object's hash key is derived from its 32-bit ID. Each list in the hash table is sorted by time of use; most-recently-used is at the front of the list. All objects are represented by the following structure: /** * What gets stored in the hash table. Each entry represents a data block or * an inode. */ struct nffs_hash_entry { SLIST_ENTRY ( nffs_hash_entry ) nhe_next ; uint32_t nhe_id ; /* 0 - 0x7fffffff if inode; else if block. */ uint32_t nhe_flash_loc ; /* Upper-byte = area idx; rest = area offset. */ }; For each data block, the above structure is all that is stored in RAM. To acquire more information about a data block, the block header must be read from flash. Inodes require a fuller RAM representation to capture the structure of the file system. There are two types of inodes: files and directories . Each inode hash entry is actually an instance of the following structure: /** Each inode hash entry is actually one of these. */ struct nffs_inode_entry { struct nffs_hash_entry nie_hash_entry ; SLIST_ENTRY ( nffs_inode_entry ) nie_sibling_next ; union { struct nffs_inode_list nie_child_list ; /* If directory */ struct nffs_hash_entry *nie_last_block_entry ; /* If file */ }; uint8_t nie_refcnt ; }; A directory inode contains a list of its child files and directories ( fie_child_list ). These entries are sorted alphabetically using the ASCII character set. A file inode contains a pointer to the last data block in the file ( nie_last_block_entry ). For most file operations, the reversed block list must be walked backwards. This introduces a number of speed inefficiencies: All data blocks must be read to determine the length of the file. Data blocks often need to be processed sequentially. The reversed nature of the block list transforms this from linear time to an O(n^2) operation. Furthermore, obtaining information about any constituent data block requires a separate flash read.","title":"RAM representation"},{"location":"os/modules/fs/nffs/nffs_internals/#inode-cache-and-data-block-cache","text":"The speed issues are addressed by a pair of caches. Cached inodes entries contain the file length and a much more convenient doubly-linked list of cached data blocks. The benefit of using caches is that the size of the caches need not be proportional to the size of the file system. In other words, caches can address speed efficiency concerns without negatively impacting the file system's scalability. nffs requires both caches during normal operation, so it is not possible to disable them. However, the cache sizes are configurable, and both caches can be configured with a size of one if RAM usage must be minimized. The following data structures are used in the inode and data block caches. /** Full data block representation; not stored permanently in RAM. */ struct nffs_block { struct nffs_hash_entry *nb_hash_entry ; /* Points to real block entry. */ uint32_t nb_seq ; /* Sequence number; greater supersedes lesser. */ struct nffs_inode_entry *nb_inode_entry ; /* Owning inode. */ struct nffs_hash_entry *nb_prev ; /* Previous block in file. */ uint16_t nb_data_len ; /* # of data bytes in block. */ uint16_t reserved16 ; }; /** Represents a single cached data block. */ struct nffs_cache_block { TAILQ_ENTRY ( nffs_cache_block ) ncb_link ; /* Next / prev cached block. */ struct nffs_block ncb_block ; /* Full data block. */ uint32_t ncb_file_offset ; /* File offset of this block. */ }; /** Full inode representation; not stored permanently in RAM. */ struct nffs_inode { struct nffs_inode_entry *ni_inode_entry ; /* Points to real inode entry. */ uint32_t ni_seq ; /* Sequence number; greater supersedes lesser. */ struct nffs_inode_entry *ni_parent ; /* Points to parent directory. */ uint8_t ni_filename_len ; /* # chars in filename. */ uint8_t ni_filename [ NFFS_SHORT_FILENAME_LEN ]; /* First 3 bytes. */ }; /** Doubly-linked tail queue of cached blocks; contained in cached inodes. */ TAILQ_HEAD ( nffs_block_cache_list , nffs_block_cache_entry ); /** Represents a single cached file inode. */ struct nffs_cache_inode { TAILQ_ENTRY ( nffs_cache_inode ) nci_link ; /* Sorted; LRU at tail. */ struct nffs_inode nci_inode ; /* Full inode. */ struct nffs_cache_block_list nci_block_list ; /* List of cached blocks. */ uint32_t nci_file_size ; /* Total file size. */ }; Only file inodes are cached; directory inodes are never cached. Within a cached inode, all cached data blocks are contiguous. E.g., if the start and end of a file are cached, then the middle must also be cached. A data block is only cached if its owning file is also cached. Internally, cached inodes are stored in a singly-linked list, ordered by time of use. The most-recently-used entry is the first element in the list. If a new inode needs to be cached, but the inode cache is full, the least-recently-used entry is freed to make room for the new one. The following operations cause an inode to be cached: Querying a file's length. Seeking within a file. Reading from a file. Writing to a file. The following operations cause a data block to be cached: Reading from the block. Writing to the block. If one of the above operations is applied to a data block that is not currently cached, nffs uses the following procedure to cache the necessary block: If none of the owning inode's blocks are currently cached, allocate a cached block entry corresponding to the requested block and insert it into the inode's list. Else if the requested file offset is less than that of the first cached block, bridge the gap between the inode's sequence of cached blocks and the block that now needs to be cached. This is accomplished by caching each block in the gap, finishing with the requested block. Else (the requested offset is beyond the end of the cache), If the requested offset belongs to the block that immediately follows the end of the cache, cache the block and append it to the list. Else, clear the cache, and populate it with the single entry corresponding to the requested block. If the system is unable to allocate a cached block entry at any point during the above procedure, the system frees up other blocks currently in the cache. This is accomplished as follows: Iterate the inode cache in reverse (i.e., start with the least-recently-used entry). For each entry: If the entry's cached block list is empty, advance to the next entry. Else, free all the cached blocks in the entry's list. Because the system imposes a minimum block cache size of one, the above procedure will always reclaim at least one cache block entry. The above procedure may result in the freeing of the block list that belongs to the very inode being operated on. This is OK, as the final block to get cached is always the block being requested.","title":"Inode cache and Data Block cache"},{"location":"os/modules/fs/nffs/nffs_internals/#detection","text":"The file system detection process consists of scanning a specified set of flash regions for valid nffs areas, and then populating the RAM representation of the file system with the detected objects. Detection is initiated with the nffs_detect() function. Not every area descriptor passed to nffs_detect() needs to reference a valid nffs area. Detection is successful as long as a complete file system is detected somewhere in the specified regions of flash. If an application is unsure where a file system might be located, it can initiate detection across the entire flash region. A detected file system is valid if: At least one non-scratch area is present. At least one scratch area is present (only the first gets used if there is more than one). The root directory inode is present. During detection, each indicated region of flash is checked for a valid area header. The contents of each valid non-scratch area are then restored into the nffs RAM representation. The following procedure is applied to each object in the area: Verify the object's integrity via a crc16 check. If invalid, the object is discarded and the procedure restarts on the next object in the area. Convert the disk object into its corresponding RAM representation and insert it into the hash table. If the object is an inode, its reference count is initialized to 1, indicating ownership by its parent directory. If an object with the same ID is already present, then one supersedes the other. Accept the object with the greater sequence number and discard the other. If the object references a nonexistent inode (parent directory in the case of an inode; owning file in the case of a data block), insert a temporary \"dummy\" inode into the hash table so that inter-object links can be maintained until the absent inode is eventually restored. Dummy inodes are identified by a reference count of 0. If a delete record for an inode is encountered, the inode's parent pointer is set to null to indicate that it should be removed from RAM. If nffs encounters an object that cannot be identified (i.e., its magic number is not valid), it scans the remainder of the flash area for the next valid magic number. Upon encountering a valid object, nffs resumes the procedure described above. After all areas have been restored, a sweep is performed across the entire RAM representation so that invalid inodes can be deleted from memory. For each directory inode: If its reference count is 0 (i.e., it is a dummy), migrate its children to the /lost+found directory, and delete it from the RAM representation. This should only happen in the case of file system corruption. If its parent reference is null (i.e., it was deleted), delete it and all its children from the RAM representation. For each file inode: If its reference count is 0 (i.e., it is a dummy), delete it from the RAM representation. This should only happen in the case of file system corruption. (We should try to migrate the file to the lost+found directory in this case, as mentioned in the todo section). When an object is deleted during this sweep, it is only deleted from the RAM representation; nothing is written to disk. When objects are migrated to the lost+found directory, their parent inode reference is permanently updated on the disk. In addition, a single scratch area is identified during the detection process. The first area whose fda_id value is set to 0xff is designated as the file system scratch area. If no valid scratch area is found, the cause could be that the system was restarted while a garbage collection cycle was in progress. Such a condition is identified by the presence of two areas with the same ID. In such a case, the shorter of the two areas is erased and designated as the scratch area.","title":"Detection"},{"location":"os/modules/fs/nffs/nffs_internals/#formatting","text":"A new nffs file system is created via formatting. Formatting is achieved via the nffs_format() function. During a successful format, an area header is written to each of the specified locations. One of the areas in the set is designated as the initial scratch area.","title":"Formatting"},{"location":"os/modules/fs/nffs/nffs_internals/#flash-writes","text":"The nffs implementation always writes in a strictly sequential fashion within an area. For each area, the system keeps track of the current offset. Whenever an object gets written to an area, it gets written to that area's current offset, and the offset is increased by the object's disk size. When a write needs to be performed, the nffs implementation selects the appropriate destination area by iterating though each area until one with sufficient free space is encountered. There is no write buffering. Each call to a write function results in a write operation being sent to the flash hardware.","title":"Flash writes"},{"location":"os/modules/fs/nffs/nffs_internals/#new-objects","text":"Whenever a new object is written to disk, it is assigned the following properties: ID: A unique value is selected from the 32-bit ID space, as appropriate for the object's type. Sequence number: 0 When a new file or directory is created, a corresponding inode is written to flash. Likewise, a new data block also results in the writing of a corresponding disk object.","title":"New objects"},{"location":"os/modules/fs/nffs/nffs_internals/#movingrenaming-files-and-directories","text":"When a file or directory is moved or renamed, its corresponding inode is rewritten to flash with the following properties: ID: Unchanged Sequence number: Previous value plus one. Parent inode: As specified by the move / rename operation. Filename: As specified by the move / rename operation. Because the inode's ID is unchanged, all dependent objects remain valid.","title":"Moving/Renaming files and directories"},{"location":"os/modules/fs/nffs/nffs_internals/#unlinking-files-and-directories","text":"When a file or directory is unlinked from its parent directory, a deletion record for the unlinked inode gets written to flash. The deletion record is an inode with the following properties: ID: Unchanged Sequence number: Previous value plus one. Parent inode ID: NFFS_ID_NONE When an inode is unlinked, no deletion records need to be written for the inode's dependent objects (constituent data blocks or child inodes). During the next file system detection, it is recognized that the objects belong to a deleted inode, so they are not restored into the RAM representation. If a file has an open handle at the time it gets unlinked, application code can continued to use the file handle to read and write data. All files retain a reference count, and a file isn't deleted from the RAM representation until its reference code drops to 0. Any attempt to open an unlinked file fails, even if the file is referenced by other file handles.","title":"Unlinking files and directories"},{"location":"os/modules/fs/nffs/nffs_internals/#writing-to-a-file","text":"The following procedure is used whenever the application code writes to a file. First, if the write operation specifies too much data to fit into a single block, the operation is split into several separate write operations. Then, for each write operation: Determine which existing blocks the write operation overlaps (n = number of overwritten blocks). If n = 0 , this is an append operation. Write a data block with the following properties: ID: New unique value. Sequence number: 0. Else (n > 1) , this write overlaps existing data. For each block in [1, 2, ... n-1] , write a new block containing the updated contents. Each new block supersedes the block it overwrites. That is, each block has the following properties: ID: Unchanged Sequence number: Previous value plus one. Write the nth block. The nth block includes all appended data, if any. As with the other blocks, its ID is unchanged and its sequence number is incremented. Appended data can only be written to the end of the file. That is, \"holes\" are not supported.","title":"Writing to a file"},{"location":"os/modules/fs/nffs/nffs_internals/#garbage-collection","text":"When the file system is too full to accommodate a write operation, the system must perform garbage collection to make room. The garbage collection procedure is described below: The non-scratch area with the lowest garbage collection sequence number is selected as the \"source area.\" If there are other areas with the same sequence number, the one with the smallest flash offset is selected. The source area's ID is written to the scratch area's header, transforming it into a non-scratch ID. This former scratch area is now known as the \"destination area.\" The RAM representation is exhaustively searched for collectible objects. The following procedure is applied to each inode in the system: If the inode is resident in the source area, copy the inode record to the destination area. If the inode is a file inode, walk the inode's list of data blocks, starting with the last block in the file. Each block that is resident in the source area is copied to the destination area. If there is a run of two or more blocks that are resident in the source area, they are consolidated and copied to the destination area as a single new block (subject to the maximum block size restriction). The source area is reformatted as a scratch sector (i.e., is is fully erased, and its header is rewritten with an ID of 0xff). The area's garbage collection sequence number is incremented prior to rewriting the header. This area is now the new scratch sector.","title":"Garbage collection"},{"location":"os/modules/hal/hal/","text":"Hardware Abstraction Layer Description The Hardware Abstraction Layer (HAL) includes a set of APIs (Application Programmer Interface) to connect to the underlying hardware components including MCU components and peripheral components. The goal is to allow libraries, modules and applications written for Mynewt to be shared within the Mynewt community and used across the variety of supported Mynewt platforms. A secondary goal is to provide a simple consistent API to commonly used MCU components and peripherals to make development easier. Nothing in the HAL precludes the user of the underlying physical devices, it only limits the portability of the end application. Example A Mynewt contributor might write a light-switch module ( libs/light ) that provides the functionality of an intelligent light switch. This might involve using a timer, a General Purpose Output (GPO) to set the light to the on or off state, and flash memory to log the times the lights were turned on or off. The contributor would like this module to work with as many different hardware platforms as possible, but can't possibly test across the complete set of hardware supported by Mynewt. Solution : The contributor uses the HAL APIs to control the peripherals. The Mynewt team ensures that the underlying HAL devices all work equivalently through the HAL APIs. The contributors library is independent of the specifics of the hardware. Dependency To include the HAL within your project, simply add it to your package dependencies as follows: pkg.deps: . . . hw/hal Platform Support Not all platforms (MCU and BSP) support all HAL devices. Consult your MCU or BSP documentation to find out if you have hardware support for the peripherals you are interested in using. Once you verify support, then consult the MCU implementation and see if the specific HAL interface you are using is in the mcu/xxx/src/hal_xxxx.c implementation. Finally, you can build your project and ensure that there are no unresolved hal_xxx externals. HAL Architecture Visit the HAL architecture page to get a understanding of our current hal and its evolution. Implementing HAL Interfaces It might be that a specific HAL interface is not supported on your MCU or platform. See the specific HAL documentation for that interface for tips on implementing this for your MCU.","title":"toc"},{"location":"os/modules/hal/hal/#hardware-abstraction-layer","text":"","title":"Hardware Abstraction Layer"},{"location":"os/modules/hal/hal/#description","text":"The Hardware Abstraction Layer (HAL) includes a set of APIs (Application Programmer Interface) to connect to the underlying hardware components including MCU components and peripheral components. The goal is to allow libraries, modules and applications written for Mynewt to be shared within the Mynewt community and used across the variety of supported Mynewt platforms. A secondary goal is to provide a simple consistent API to commonly used MCU components and peripherals to make development easier. Nothing in the HAL precludes the user of the underlying physical devices, it only limits the portability of the end application.","title":"Description"},{"location":"os/modules/hal/hal/#example","text":"A Mynewt contributor might write a light-switch module ( libs/light ) that provides the functionality of an intelligent light switch. This might involve using a timer, a General Purpose Output (GPO) to set the light to the on or off state, and flash memory to log the times the lights were turned on or off. The contributor would like this module to work with as many different hardware platforms as possible, but can't possibly test across the complete set of hardware supported by Mynewt. Solution : The contributor uses the HAL APIs to control the peripherals. The Mynewt team ensures that the underlying HAL devices all work equivalently through the HAL APIs. The contributors library is independent of the specifics of the hardware.","title":"Example"},{"location":"os/modules/hal/hal/#dependency","text":"To include the HAL within your project, simply add it to your package dependencies as follows: pkg.deps: . . . hw/hal","title":"Dependency"},{"location":"os/modules/hal/hal/#platform-support","text":"Not all platforms (MCU and BSP) support all HAL devices. Consult your MCU or BSP documentation to find out if you have hardware support for the peripherals you are interested in using. Once you verify support, then consult the MCU implementation and see if the specific HAL interface you are using is in the mcu/xxx/src/hal_xxxx.c implementation. Finally, you can build your project and ensure that there are no unresolved hal_xxx externals.","title":"Platform Support"},{"location":"os/modules/hal/hal/#hal-architecture","text":"Visit the HAL architecture page to get a understanding of our current hal and its evolution.","title":"HAL Architecture"},{"location":"os/modules/hal/hal/#implementing-hal-interfaces","text":"It might be that a specific HAL interface is not supported on your MCU or platform. See the specific HAL documentation for that interface for tips on implementing this for your MCU.","title":"Implementing HAL Interfaces"},{"location":"os/modules/hal/hal_api/","text":"HAL Interfaces The HAL supports separate interfaces for many peripherals. A brief description of the interfaces are shown below. Hal Name ** Interface File ** **Description ** adc hal_adc.h An interface for controlling Analog To Digital Converters. cputime hal_cputime.h An interface for getting the CPU uptime, an interface to set arbitrary timers based on the CPU time, and an interface for a blocking delay if CPU time. dac hal_dac.h An interface for controlling Digital to Analog Converters. flash hal_flash.h A blocking interface to access flash memory. flash map flash_map.h An interface to query information about the flash map (regions and sectors) gpio hal_gpio.h An interface for manipulating General Purpose Inputs and Outputs. i2c hal_i2c.h An interface for controlling Inter-Integrated-Circuit (i2c) devices. pwm hal_pwm.h An interface for controlling Pulse Width Modulator Devices. spi hal_spi.h An interface for controlling Serial Peripheral Interface (SPI) devices. system hal_system.h An interface for starting and resetting the system uart hal_uart.h An interface for communicating via asynchronous serial interface .","title":"Summary"},{"location":"os/modules/hal/hal_api/#hal-interfaces","text":"The HAL supports separate interfaces for many peripherals. A brief description of the interfaces are shown below. Hal Name ** Interface File ** **Description ** adc hal_adc.h An interface for controlling Analog To Digital Converters. cputime hal_cputime.h An interface for getting the CPU uptime, an interface to set arbitrary timers based on the CPU time, and an interface for a blocking delay if CPU time. dac hal_dac.h An interface for controlling Digital to Analog Converters. flash hal_flash.h A blocking interface to access flash memory. flash map flash_map.h An interface to query information about the flash map (regions and sectors) gpio hal_gpio.h An interface for manipulating General Purpose Inputs and Outputs. i2c hal_i2c.h An interface for controlling Inter-Integrated-Circuit (i2c) devices. pwm hal_pwm.h An interface for controlling Pulse Width Modulator Devices. spi hal_spi.h An interface for controlling Serial Peripheral Interface (SPI) devices. system hal_system.h An interface for starting and resetting the system uart hal_uart.h An interface for communicating via asynchronous serial interface .","title":"HAL Interfaces"},{"location":"os/modules/hal/hal_architecture/","text":"Hardware Abstraction Layer This page presents a picture of the HAL architecture in its current state. The Mynewt is pre-1.0, and we expect significant changes to the HAL as we add support for more functionality and platforms.","title":"Architecture"},{"location":"os/modules/hal/hal_architecture/#hardware-abstraction-layer","text":"This page presents a picture of the HAL architecture in its current state. The Mynewt is pre-1.0, and we expect significant changes to the HAL as we add support for more functionality and platforms.","title":"Hardware Abstraction Layer"},{"location":"os/modules/hal/hal_creation/","text":"Creating New HAL Interfaces HAL API A HAL always includes header file with function declarations for the HAL functionality in /hw/hal/include/hal . The first argument of all functions in the interface include the virtual device_id of the device you are controlling. For example, in hal_gpio.h the device enumeration is the first argument to all methods and called pin . void hal_gpio_set(int pin); The device_id (in this case called pin ) is not a physical device (actual hardware pin), but a virtual pin which is defined by the implementation of the HAL (and documented in the implementation of the HAL) Below this, there are two different paradigms for HAL interface. They are discussed below. Direct HAL Interface In one HAL paradigm called direct HAL , the header file is the only component of the HAL interface. Implementers of this HAL would create a source file that implements these methods. This has the advantage of being simple, small, and low execution overhead. It has the disadvantage that its not possible to have two different implementations of the same direct HAL within the same image. Said another way, if I create a direct HAL hal_foo.h , there can be many implementations of xxx/hal_foo.c but only one can be included in a project. For example, support there is an ADC attached directly to the MCU and an ADC that is attached via SPI. There would be no way in this simple paradigm to use both these devices from the HAL API at the same time. Current Direct HAL interfaces include: Hal Name ** Interface File ** [hal_gpio] hal_gpio.h [hal_uart] hal_uart.h [hal_cputime] hal_cputime.h This brings up the second paradigm. Indirect HAL Interface The second paradigm, indirect HAL preserves the simple function API with enumerated device_id but adds a small layer of code in the HAL to allow different implementations to connect at runtime. The abstract interface contains three components: A header file hal_foo.h that includes the API above with a device_id An implementation hal/hal_foo.c which maps the device_id to a driver interface structure. A driver interface structure that is defined for the underlying implementation Using this simple model, the user can be exposed to a simple function interface (without structures or function pointers) and the system can provide a different software implementation for each device id. Although the GPIO interface for Mynewt uses the direct HAL , we can describe what it might look like for an indirect HAL. The API hal_gpio.h is identical with a direct or indirect HAL. In the indirect HAL there is an additional header file hal_gpio_int.h which describes the driver interface for underlying implementations. It looks similar to the HAL API except is driven by function pointers. struct hal_gpio_funcs { void (*hgpio_set)(void); . . . }; struct hal_gpio_int { struct hal_gpio_funcs funcs; } const struct hal_gpio_int *bsp_gpio_dev(uint8_t pin); The BSP specific function is what will map the specific pin (device_id) to its implementation. This is different than the direct HAL which maps this virtual/physical device pairing in the MCU implementation. For the indirect HAL the mapping has to be done in the BSP since that is the place where multiple disparate devices can be enumerated into a single device_id space. An interface file hal/hal_gpio.c would perform the mapping as follows: void hal_gpio_set(int pin) { const struct hal_gpio_int *pgpio; pgpio = bsp_get_gpio_device(pin); if(pgpio) { pgpio->funcs.set(); } } The implementer of GPIO functionality (say in mcu/xxx/hal_gpio.c ) would implement the structure and provide the function pointers. void xxx_hal_gpio_set(void) { /* implementation for this particular gpio device */ . . . } struct hal_gpio_int xxx_hal_gpio = { .funcs.hgpio_set = xxx_hal_gpio_set; } This leaves the BSP implementation to complete the function const struct hal_gpio_int *bsp_gpio_dev(uint8_t pin) { switch(pin) { case 0: return &xxx_hal_gpio; case 1: return &yyy_hal_gpio; } return NULL; } NOTE : In this example there could be 10s of GPIO. It may be memory inefficient to have that many hal_gpio_int structures around to basically call the same functions. In Mynewt today, the hal_gpio is a direct HAL and does not have this overhead. More HAL paradigms may be added in the future to address the flexibility of the indirect HAL with the memory efficiency of the direct HAL Current Indirect HAL interfaces include: Hal Name ** Interface File ** hal_adc_int hal_adc_int.h hal_dac hal_dac_int.h hal_flash_int hal_flash_int.h hal_pwm_int hal_pwm_int.h hal_i2c_int hal_i2c_int.h hal_spi_int hal_spi_int.h","title":"Creating HAL"},{"location":"os/modules/hal/hal_creation/#creating-new-hal-interfaces","text":"","title":"Creating New HAL Interfaces"},{"location":"os/modules/hal/hal_creation/#hal-api","text":"A HAL always includes header file with function declarations for the HAL functionality in /hw/hal/include/hal . The first argument of all functions in the interface include the virtual device_id of the device you are controlling. For example, in hal_gpio.h the device enumeration is the first argument to all methods and called pin . void hal_gpio_set(int pin); The device_id (in this case called pin ) is not a physical device (actual hardware pin), but a virtual pin which is defined by the implementation of the HAL (and documented in the implementation of the HAL) Below this, there are two different paradigms for HAL interface. They are discussed below.","title":"HAL API"},{"location":"os/modules/hal/hal_creation/#direct-hal-interface","text":"In one HAL paradigm called direct HAL , the header file is the only component of the HAL interface. Implementers of this HAL would create a source file that implements these methods. This has the advantage of being simple, small, and low execution overhead. It has the disadvantage that its not possible to have two different implementations of the same direct HAL within the same image. Said another way, if I create a direct HAL hal_foo.h , there can be many implementations of xxx/hal_foo.c but only one can be included in a project. For example, support there is an ADC attached directly to the MCU and an ADC that is attached via SPI. There would be no way in this simple paradigm to use both these devices from the HAL API at the same time. Current Direct HAL interfaces include: Hal Name ** Interface File ** [hal_gpio] hal_gpio.h [hal_uart] hal_uart.h [hal_cputime] hal_cputime.h This brings up the second paradigm.","title":"Direct HAL Interface"},{"location":"os/modules/hal/hal_creation/#indirect-hal-interface","text":"The second paradigm, indirect HAL preserves the simple function API with enumerated device_id but adds a small layer of code in the HAL to allow different implementations to connect at runtime. The abstract interface contains three components: A header file hal_foo.h that includes the API above with a device_id An implementation hal/hal_foo.c which maps the device_id to a driver interface structure. A driver interface structure that is defined for the underlying implementation Using this simple model, the user can be exposed to a simple function interface (without structures or function pointers) and the system can provide a different software implementation for each device id. Although the GPIO interface for Mynewt uses the direct HAL , we can describe what it might look like for an indirect HAL. The API hal_gpio.h is identical with a direct or indirect HAL. In the indirect HAL there is an additional header file hal_gpio_int.h which describes the driver interface for underlying implementations. It looks similar to the HAL API except is driven by function pointers. struct hal_gpio_funcs { void (*hgpio_set)(void); . . . }; struct hal_gpio_int { struct hal_gpio_funcs funcs; } const struct hal_gpio_int *bsp_gpio_dev(uint8_t pin); The BSP specific function is what will map the specific pin (device_id) to its implementation. This is different than the direct HAL which maps this virtual/physical device pairing in the MCU implementation. For the indirect HAL the mapping has to be done in the BSP since that is the place where multiple disparate devices can be enumerated into a single device_id space. An interface file hal/hal_gpio.c would perform the mapping as follows: void hal_gpio_set(int pin) { const struct hal_gpio_int *pgpio; pgpio = bsp_get_gpio_device(pin); if(pgpio) { pgpio->funcs.set(); } } The implementer of GPIO functionality (say in mcu/xxx/hal_gpio.c ) would implement the structure and provide the function pointers. void xxx_hal_gpio_set(void) { /* implementation for this particular gpio device */ . . . } struct hal_gpio_int xxx_hal_gpio = { .funcs.hgpio_set = xxx_hal_gpio_set; } This leaves the BSP implementation to complete the function const struct hal_gpio_int *bsp_gpio_dev(uint8_t pin) { switch(pin) { case 0: return &xxx_hal_gpio; case 1: return &yyy_hal_gpio; } return NULL; } NOTE : In this example there could be 10s of GPIO. It may be memory inefficient to have that many hal_gpio_int structures around to basically call the same functions. In Mynewt today, the hal_gpio is a direct HAL and does not have this overhead. More HAL paradigms may be added in the future to address the flexibility of the indirect HAL with the memory efficiency of the direct HAL Current Indirect HAL interfaces include: Hal Name ** Interface File ** hal_adc_int hal_adc_int.h hal_dac hal_dac_int.h hal_flash_int hal_flash_int.h hal_pwm_int hal_pwm_int.h hal_i2c_int hal_i2c_int.h hal_spi_int hal_spi_int.h","title":"Indirect HAL Interface"},{"location":"os/modules/hal/hal_in_libraries/","text":"Using HAL in Your Libraries This page describes the recommended way to implement libraries that utilize HAL functionality. Consider the light switch example from the HAL overview page. The light switch module needs a GPIO pin to set the light switch to on or off. The module declares that the GPIO to control the light switch is declared elsewhere in one of two methods. extern const int light_switch_gpio; or extern int bsp_light_app_get_light_gpio(); Which method a library uses (extern const versus function) depends on what functionality the library might wish to declare. The extern const model uses the smallest code footprint, but since its constant cannot be changed at runtime (based on the configuration of the device say). The extern function call requires the BSP to implement a function which allows flexibility to assign the GPIO for the light switch to be determined at runtime with a small expense of slightly more code. Then the libs/light would go on to use the specified GPIO during its runtime execution. For example this shows both ways the library could interface to the bsp to get the right GPIO: void light_on(void) { . . . /* finally time to turn the light on */ hal_gpio_set(light_switch_gpio); } void light_on(void) { . . . int pin = bsp_light_app_get_light_gpio(); /* finally time to turn the light on */ hal_gpio_set(pin); } When you library user includes libs/light as a dependency and then builds with newt , they will get an unresolved external for either light_switch_gpio or bsp_light_app_get_light_gpio() and will need to add to their BSP. In their BSP, they can add const int light_switch_gpio = 5; or int bsp_light_app_get_light_gpio(void) { return my_configured_lightswitch_io(); } So where did the number 5 come from. Their BSP already includes the specific MCU that they are using. And their mcu/xxx/hal_gpio.c already defines the mapping between physical pins and the virtual device ids. The user can determine (when writing code) from their boards physical pinmap and from the hal_gpio.c MCU mapping which virtual device_id corresponds to the correct physical pin in their system.","title":"Using HAL"},{"location":"os/modules/hal/hal_in_libraries/#using-hal-in-your-libraries","text":"This page describes the recommended way to implement libraries that utilize HAL functionality. Consider the light switch example from the HAL overview page. The light switch module needs a GPIO pin to set the light switch to on or off. The module declares that the GPIO to control the light switch is declared elsewhere in one of two methods. extern const int light_switch_gpio; or extern int bsp_light_app_get_light_gpio(); Which method a library uses (extern const versus function) depends on what functionality the library might wish to declare. The extern const model uses the smallest code footprint, but since its constant cannot be changed at runtime (based on the configuration of the device say). The extern function call requires the BSP to implement a function which allows flexibility to assign the GPIO for the light switch to be determined at runtime with a small expense of slightly more code. Then the libs/light would go on to use the specified GPIO during its runtime execution. For example this shows both ways the library could interface to the bsp to get the right GPIO: void light_on(void) { . . . /* finally time to turn the light on */ hal_gpio_set(light_switch_gpio); } void light_on(void) { . . . int pin = bsp_light_app_get_light_gpio(); /* finally time to turn the light on */ hal_gpio_set(pin); } When you library user includes libs/light as a dependency and then builds with newt , they will get an unresolved external for either light_switch_gpio or bsp_light_app_get_light_gpio() and will need to add to their BSP. In their BSP, they can add const int light_switch_gpio = 5; or int bsp_light_app_get_light_gpio(void) { return my_configured_lightswitch_io(); } So where did the number 5 come from. Their BSP already includes the specific MCU that they are using. And their mcu/xxx/hal_gpio.c already defines the mapping between physical pins and the virtual device ids. The user can determine (when writing code) from their boards physical pinmap and from the hal_gpio.c MCU mapping which virtual device_id corresponds to the correct physical pin in their system.","title":"Using HAL in Your Libraries"},{"location":"os/modules/hal/hal_adc/hal_adc/","text":"hal_adc The hardware independent interface to Analog To Digital Controllers Description Analog to Digital converters (ADCs) read analog values (voltage) and convert them to digital values to be used in your applications. For a description of ADC, see wikipedia Definition hal_adc.h HAL_ADCs Theory Of Operation ADCs have different conversion rates, resolution (bits) and reference voltages. The HAL_ADC has APIs to allow the application or library to query the capabilities of a specific ADC. Method Name ** Description ** hal_adc_get_bits gets the resolution of the ADC in bits. For example if the ADC is 10 bits, a read will return a value from 0 through 2^10 - 1 = 1023. hal_adc_get_ref_mv gets the underlying reference voltage for the ADC in millivolts. For example, if the ADC is 10 bits and the reference voltage is 5000 mV a ADC reading of 1023 corresponds to 5V; a ADC reading of 0 corresponds to 0 volts. Given this information, the application or library could convert any reading to millivolts. Since this is a common operation, the HAL_ADC API has a helper function to perform this function: hal_adc_to_mv() . The current HAL_ADC API provides a blocking read command to initiate an ADC conversion, and return the result of that conversion. Conversion time is hardware dependent, but this is not an instantaneous operation. Libraries can use the hal_cputime APIs to time conversions if that is relevant to the application. Future HAL_ADC APIs will include periodic ADC conversion, non-blocking ADC conversion and direct-to-memory DMA conversion.","title":"ADC"},{"location":"os/modules/hal/hal_adc/hal_adc/#hal_adc","text":"The hardware independent interface to Analog To Digital Controllers","title":"hal_adc"},{"location":"os/modules/hal/hal_adc/hal_adc/#description","text":"Analog to Digital converters (ADCs) read analog values (voltage) and convert them to digital values to be used in your applications. For a description of ADC, see wikipedia","title":"Description"},{"location":"os/modules/hal/hal_adc/hal_adc/#definition","text":"hal_adc.h","title":"Definition"},{"location":"os/modules/hal/hal_adc/hal_adc/#hal_adcs-theory-of-operation","text":"ADCs have different conversion rates, resolution (bits) and reference voltages. The HAL_ADC has APIs to allow the application or library to query the capabilities of a specific ADC. Method Name ** Description ** hal_adc_get_bits gets the resolution of the ADC in bits. For example if the ADC is 10 bits, a read will return a value from 0 through 2^10 - 1 = 1023. hal_adc_get_ref_mv gets the underlying reference voltage for the ADC in millivolts. For example, if the ADC is 10 bits and the reference voltage is 5000 mV a ADC reading of 1023 corresponds to 5V; a ADC reading of 0 corresponds to 0 volts. Given this information, the application or library could convert any reading to millivolts. Since this is a common operation, the HAL_ADC API has a helper function to perform this function: hal_adc_to_mv() . The current HAL_ADC API provides a blocking read command to initiate an ADC conversion, and return the result of that conversion. Conversion time is hardware dependent, but this is not an instantaneous operation. Libraries can use the hal_cputime APIs to time conversions if that is relevant to the application. Future HAL_ADC APIs will include periodic ADC conversion, non-blocking ADC conversion and direct-to-memory DMA conversion.","title":"HAL_ADCs Theory Of Operation"},{"location":"os/modules/hal/hal_cputime/hal_cpu_timer/","text":"hal_cputime The hardware independent interface to system time. Description Contains several different interface. An interface to get the current CPU time Interfaces to convert between CPU time and clock time (microseconds etc.) An Interface to set up a software timer based on CPU time. Definition hal_cputime.h CPU Time The CPU time is not the same as the os_time . Typically, the os_time is set to a much slower tick rate than the CPU time. The CPU time should be used for timing real-time events at exact times. The os_time should be used for system level timeout etc that are not in fine time resolutions. In fact, cputime is not part of the os at all, but a hardware layer abstraction to high resolution timers. There are methods to get the cputime as 32-bit and 64-bit values. Both values may eventually wrap, but for timing short events a 32-bit value may be sufficient and would","title":"CPU timer"},{"location":"os/modules/hal/hal_cputime/hal_cpu_timer/#hal_cputime","text":"The hardware independent interface to system time.","title":"hal_cputime"},{"location":"os/modules/hal/hal_cputime/hal_cpu_timer/#description","text":"Contains several different interface. An interface to get the current CPU time Interfaces to convert between CPU time and clock time (microseconds etc.) An Interface to set up a software timer based on CPU time.","title":"Description"},{"location":"os/modules/hal/hal_cputime/hal_cpu_timer/#definition","text":"hal_cputime.h","title":"Definition"},{"location":"os/modules/hal/hal_cputime/hal_cpu_timer/#cpu-time","text":"The CPU time is not the same as the os_time . Typically, the os_time is set to a much slower tick rate than the CPU time. The CPU time should be used for timing real-time events at exact times. The os_time should be used for system level timeout etc that are not in fine time resolutions. In fact, cputime is not part of the os at all, but a hardware layer abstraction to high resolution timers. There are methods to get the cputime as 32-bit and 64-bit values. Both values may eventually wrap, but for timing short events a 32-bit value may be sufficient and would","title":"CPU Time"},{"location":"os/modules/hal/hal_dac/hal_dac/","text":"hal_dac The hardware independent interface to Digital To Analog Converters. Description For a description of Digital to Analog Converters, see wikipedia Definition hal_dac.h HAL_DAC Theory Of Operation DACs have differing conversion resolution (bits), reference voltages (Volts) and conversion times (sample rate). The hal_dac implements function to query some of these values from the BSP. Method Name ** Description ** hal_dac_get_bits gets the resolution of the DAC in bits. For example if the DAC is 10 bits, it supports setting of value from 0 through 2^10 - 1 = 1023. hal_dac_get_ref_mv gets the underlying reference voltage for the DAC in millivolts. For example, if the DAC is 10 bits and the reference voltage is 5000 mV setting the DAC value to 1023 corresponds to 5V; setting the DAC value to 0 corresponds to 0 volts. From these two pieces of information the application or library can determine how to set a specific output voltage. NOTE: each underlying hardware may return different values for these settings. The API to set the DAC output value is blocking. This means the function will return after the DAC value has been programmed. Future HAL_DAC APIs will include A DMA interface to automatically write DMA data to the DAC based in events. The Mynewt HAL also supports a PWM interface which can be used in conjunction with a low pass filter to set an analog output voltage.","title":"DAC"},{"location":"os/modules/hal/hal_dac/hal_dac/#hal_dac","text":"The hardware independent interface to Digital To Analog Converters.","title":"hal_dac"},{"location":"os/modules/hal/hal_dac/hal_dac/#description","text":"For a description of Digital to Analog Converters, see wikipedia","title":"Description"},{"location":"os/modules/hal/hal_dac/hal_dac/#definition","text":"hal_dac.h","title":"Definition"},{"location":"os/modules/hal/hal_dac/hal_dac/#hal_dac-theory-of-operation","text":"DACs have differing conversion resolution (bits), reference voltages (Volts) and conversion times (sample rate). The hal_dac implements function to query some of these values from the BSP. Method Name ** Description ** hal_dac_get_bits gets the resolution of the DAC in bits. For example if the DAC is 10 bits, it supports setting of value from 0 through 2^10 - 1 = 1023. hal_dac_get_ref_mv gets the underlying reference voltage for the DAC in millivolts. For example, if the DAC is 10 bits and the reference voltage is 5000 mV setting the DAC value to 1023 corresponds to 5V; setting the DAC value to 0 corresponds to 0 volts. From these two pieces of information the application or library can determine how to set a specific output voltage. NOTE: each underlying hardware may return different values for these settings. The API to set the DAC output value is blocking. This means the function will return after the DAC value has been programmed. Future HAL_DAC APIs will include A DMA interface to automatically write DMA data to the DAC based in events. The Mynewt HAL also supports a PWM interface which can be used in conjunction with a low pass filter to set an analog output voltage.","title":"HAL_DAC Theory Of Operation"},{"location":"os/modules/hal/hal_flash/hal_flash/","text":"","title":"Overview"},{"location":"os/modules/hal/hal_flash/hal_flash_int/","text":"","title":"flash_int"},{"location":"os/modules/hal/hal_flash/hal_flash_map/","text":"","title":"flash_map"},{"location":"os/modules/hal/hal_gpio/hal_gpio/","text":"hal_gpio This is the hardware independent GPIO (General Purpose Input Output) Interface for Mynewt. Description Contains the basic operations to set and read General Purpose Digital I/O Pins within a Mynewt system. Individual GPIOs are referenced in the APIs as pins . However, in this interface the pins are virtual GPIO pins. The MCU hal driver maps these virtual pins to the physical GPIO ports and pins. Typically, the BSP code may define named I/O pins in terms of these virtual pins to describe the devices attached to the physical pins. Here's a brief example so you can get the gist of the translation. Suppose my product uses the stm32F4xx processor. There already exists support for this processor within Mynewt. The processor has N ports (A,B,C..) of 16 GPIO pins per port. The MCU hal_gpio driver maps these to a set of virtual pins 0-N where port A maps to 0-15, Port B maps to 16-31, Port C maps to 32-47 and so on. The exact number of physical port (and virtual port pins) depends on the specific variant of the stm32F4xx. So if I want to turn on port B pin 3, that would be virtual pin 1*16 + 3 = 19. This translation is defined in the MCU implementation of hal_gpio.c for the stmf32F4xx. Each MCU will typically have a different translation method depending on its GPIO architecture. Now, when writing a BSP, it's common to give names to the relevant port pins that you are using. Thus, the BSP may define a mapping between a function and a virtual port pin. For example #define SYSTEM_LED (37) #define FLASH_SPI_CHIP_SELECT (3) would map the system indicator LED to virtual pin 37 which on the stm32F4xx would be Port C pin 5 and the chip select line for the external SPI flash to virtual pin 3 which on the stm32F4xxis port A pin 3. Said another way, in this specific system we get SYSTEM_LED --> hal_gpio virtual pin 37 --> port C pin 5 on the stm34F4xx Definition hal_gpio.h Examples Blinky Blinky uses the hal_gpio to blink the system LED. The blinky source code is available here . Examine how task1_handler initializes and toggles the GPIO to control the LED.","title":"GPIO"},{"location":"os/modules/hal/hal_gpio/hal_gpio/#hal_gpio","text":"This is the hardware independent GPIO (General Purpose Input Output) Interface for Mynewt.","title":"hal_gpio"},{"location":"os/modules/hal/hal_gpio/hal_gpio/#description","text":"Contains the basic operations to set and read General Purpose Digital I/O Pins within a Mynewt system. Individual GPIOs are referenced in the APIs as pins . However, in this interface the pins are virtual GPIO pins. The MCU hal driver maps these virtual pins to the physical GPIO ports and pins. Typically, the BSP code may define named I/O pins in terms of these virtual pins to describe the devices attached to the physical pins. Here's a brief example so you can get the gist of the translation. Suppose my product uses the stm32F4xx processor. There already exists support for this processor within Mynewt. The processor has N ports (A,B,C..) of 16 GPIO pins per port. The MCU hal_gpio driver maps these to a set of virtual pins 0-N where port A maps to 0-15, Port B maps to 16-31, Port C maps to 32-47 and so on. The exact number of physical port (and virtual port pins) depends on the specific variant of the stm32F4xx. So if I want to turn on port B pin 3, that would be virtual pin 1*16 + 3 = 19. This translation is defined in the MCU implementation of hal_gpio.c for the stmf32F4xx. Each MCU will typically have a different translation method depending on its GPIO architecture. Now, when writing a BSP, it's common to give names to the relevant port pins that you are using. Thus, the BSP may define a mapping between a function and a virtual port pin. For example #define SYSTEM_LED (37) #define FLASH_SPI_CHIP_SELECT (3) would map the system indicator LED to virtual pin 37 which on the stm32F4xx would be Port C pin 5 and the chip select line for the external SPI flash to virtual pin 3 which on the stm32F4xxis port A pin 3. Said another way, in this specific system we get SYSTEM_LED --> hal_gpio virtual pin 37 --> port C pin 5 on the stm34F4xx","title":"Description"},{"location":"os/modules/hal/hal_gpio/hal_gpio/#definition","text":"hal_gpio.h","title":"Definition"},{"location":"os/modules/hal/hal_gpio/hal_gpio/#examples","text":"","title":"Examples"},{"location":"os/modules/hal/hal_gpio/hal_gpio/#blinky","text":"Blinky uses the hal_gpio to blink the system LED. The blinky source code is available here . Examine how task1_handler initializes and toggles the GPIO to control the LED.","title":"Blinky"},{"location":"os/modules/hal/hal_i2c/hal_i2c/","text":"hal_i2c The hardware independent interface to I2C Devices. Description An Inter-Integrated Circuit (I\u00b2C ] I-squared-C) bus is a multi-master, multi-save serial interface used to connect components on a circuit board and often peripherals devices located off the circuit board. I2C is often though of as a 2-wire protocol because it uses two wires (SDA, SCL) to send data between devices. For a detailed description of I2C, see the I\u00b2C wikipedia page Definition hal_i2c.h HAL_I2C Theory Of Operation An I\u00b2C transaction typically involves acquiring the bus, sending and/or receiving data and release the bus. The bus acquisition portion is important because the bus is typically multi-master so other devices may be trying to read/write the same peripheral. HAL_I2C implements a master interface to the I\u00b2C bus. Typical usage of the interface would involve the following steps. initialize an I\u00b2C device using hal_i2c_init when you want to perform an I\u00b2C transaction: Issue the hal_i2c_begin() command. Issue one or more hal_i2c_read and/or hal_i2c_write commands Issue the hal_i2c_end() command. An addition API was added called hal_i2c_probe . This command combines hal_i2c_begin() , hal_i2c_read , and hal_i2c_end() to try to read 0-bytes from a specific bus address. its intended to provide an easy way to probe the bus for a specific device. NOTE: if the device is write-only, it will not appear with this command. HAL_I2C Data Data to read/write is passed to the hal_i2c APIs via the struct hal_i2c_master_data { uint8_t address; /* destination address */ uint16_t len; /* number of bytes to transmit or receive */ uint8_t *buffer; /* data buffer for transmit or receive */ }; buffer is a pointer to the data to send. len is the number of bytes to send over the bus. address is a 7-bit bus address of the device. When I\u00b2C builds its address, it uses the 7-bit address plus a 1-bit R/W (read/write) indicator to identify the device and direction of the transaction. Thus when using this API, you should use a 7-bit address in the data structure and ensure that address is a value between 0-127. As an example, consider an I\u00b2C device address that looks like this: B7 B6 B5 B4 B3 B2 B1 B0 1 0 0 0 1 1 0 R/W MSB LSB In the HAL_I2C API you would communicate with this device with address 0b1000110 , which is hex 0x46 or decimal 70. The I\u00b2C drive would add the R/W bit and transmit it as hex 0x8D or 0x8D depending whether it was a read or write command.","title":"I2C"},{"location":"os/modules/hal/hal_i2c/hal_i2c/#hal_i2c","text":"The hardware independent interface to I2C Devices.","title":"hal_i2c"},{"location":"os/modules/hal/hal_i2c/hal_i2c/#description","text":"An Inter-Integrated Circuit (I\u00b2C ] I-squared-C) bus is a multi-master, multi-save serial interface used to connect components on a circuit board and often peripherals devices located off the circuit board. I2C is often though of as a 2-wire protocol because it uses two wires (SDA, SCL) to send data between devices. For a detailed description of I2C, see the I\u00b2C wikipedia page","title":"Description"},{"location":"os/modules/hal/hal_i2c/hal_i2c/#definition","text":"hal_i2c.h","title":"Definition"},{"location":"os/modules/hal/hal_i2c/hal_i2c/#hal_i2c-theory-of-operation","text":"An I\u00b2C transaction typically involves acquiring the bus, sending and/or receiving data and release the bus. The bus acquisition portion is important because the bus is typically multi-master so other devices may be trying to read/write the same peripheral. HAL_I2C implements a master interface to the I\u00b2C bus. Typical usage of the interface would involve the following steps. initialize an I\u00b2C device using hal_i2c_init when you want to perform an I\u00b2C transaction: Issue the hal_i2c_begin() command. Issue one or more hal_i2c_read and/or hal_i2c_write commands Issue the hal_i2c_end() command. An addition API was added called hal_i2c_probe . This command combines hal_i2c_begin() , hal_i2c_read , and hal_i2c_end() to try to read 0-bytes from a specific bus address. its intended to provide an easy way to probe the bus for a specific device. NOTE: if the device is write-only, it will not appear with this command.","title":"HAL_I2C Theory Of Operation"},{"location":"os/modules/hal/hal_i2c/hal_i2c/#hal_i2c-data","text":"Data to read/write is passed to the hal_i2c APIs via the struct hal_i2c_master_data { uint8_t address; /* destination address */ uint16_t len; /* number of bytes to transmit or receive */ uint8_t *buffer; /* data buffer for transmit or receive */ }; buffer is a pointer to the data to send. len is the number of bytes to send over the bus. address is a 7-bit bus address of the device. When I\u00b2C builds its address, it uses the 7-bit address plus a 1-bit R/W (read/write) indicator to identify the device and direction of the transaction. Thus when using this API, you should use a 7-bit address in the data structure and ensure that address is a value between 0-127. As an example, consider an I\u00b2C device address that looks like this: B7 B6 B5 B4 B3 B2 B1 B0 1 0 0 0 1 1 0 R/W MSB LSB In the HAL_I2C API you would communicate with this device with address 0b1000110 , which is hex 0x46 or decimal 70. The I\u00b2C drive would add the R/W bit and transmit it as hex 0x8D or 0x8D depending whether it was a read or write command.","title":"HAL_I2C Data"},{"location":"os/modules/hal/hal_pwm/hal_pwm/","text":"hal_pwm The hardware independent interface to Pulse Width Modulators Description Pulse Width Modulators (PWMs) are hardware devices that output digital waveforms with programmable duty cycle and frequency. They use a digital waveform but can contiuously adjust the amount of power delivered to their load via duty cycle. They are often used to create analog waveforms via low pass filter, drive LEDs at various intensities, and control DC or servo motors. For a description of PSM, see wikipedia Definition hal_pwm.h HAL_PWM Theory Of Operation The HAL_PWM interface was designed with some specific use cases in mind. It was also designed to exploit a subset of the functionality provided by common PWM controllers. Fundamentally, a PWM has at it root an N-bit COUNTER, a CLOCK source, one or more CAPTURE registers, and sometimes a TOP register. The clock source feeds the COUNTER register which is continuously counting (up or down), When the COUNTER is less than the value of the CAPTURE register, the PWM outputs a logic HIGH. When the counter is greater than the CAPTURE register the PWM outputs logic LOW. When the counter reaches the TOP register, it wraps back to zero. If the PWM has no TOP register, it simply wraps back to zero after reaching 2^N-1. The HAL_PWM abstracts this implementation and provides methods to set the PWM frequency and duty cycle. The frequency is the rate at which the counter wraps back to zero. The duty cycle is the fraction of time the PWM is in logic HIGH state. The HAL_PWM API provides a few methods to get information on the PWM. Method Name ** Description ** hal_pwm_get_source_clock_freq gets the frequency of the CLOCK that is driving the COUNTER hal_pwm_get_resolution_bits gets the number of bits in the COUNTER To use a PWM via HAL_PWM, follow these simple steps. 1) initialize a PWM using hal_pwm_init -- this binds the driver to the device for the specific PWM you are using 2) Optionally set the frequency of the PWM using hal_pwm_set_frequency -- PWMs that support a TOP register have fine control over their frequency settings. If this command is not supported by the PWM it will return an error and its likely that there is no TOP register; the frequency resolution is not finely adjustable. See the BSP for coarse adjustment of the PWM frequency. 3) Enable the PWM to output a specific duty cycle using the hal_pwm_enable_duty_cycle API To change the duty cycle dynamically, just issue another hal_pwm_enable_duty_cycle command. To disable the PWM waveform, use hal_pwm_disable .","title":"PWM"},{"location":"os/modules/hal/hal_pwm/hal_pwm/#hal_pwm","text":"The hardware independent interface to Pulse Width Modulators","title":"hal_pwm"},{"location":"os/modules/hal/hal_pwm/hal_pwm/#description","text":"Pulse Width Modulators (PWMs) are hardware devices that output digital waveforms with programmable duty cycle and frequency. They use a digital waveform but can contiuously adjust the amount of power delivered to their load via duty cycle. They are often used to create analog waveforms via low pass filter, drive LEDs at various intensities, and control DC or servo motors. For a description of PSM, see wikipedia","title":"Description"},{"location":"os/modules/hal/hal_pwm/hal_pwm/#definition","text":"hal_pwm.h","title":"Definition"},{"location":"os/modules/hal/hal_pwm/hal_pwm/#hal_pwm-theory-of-operation","text":"The HAL_PWM interface was designed with some specific use cases in mind. It was also designed to exploit a subset of the functionality provided by common PWM controllers. Fundamentally, a PWM has at it root an N-bit COUNTER, a CLOCK source, one or more CAPTURE registers, and sometimes a TOP register. The clock source feeds the COUNTER register which is continuously counting (up or down), When the COUNTER is less than the value of the CAPTURE register, the PWM outputs a logic HIGH. When the counter is greater than the CAPTURE register the PWM outputs logic LOW. When the counter reaches the TOP register, it wraps back to zero. If the PWM has no TOP register, it simply wraps back to zero after reaching 2^N-1. The HAL_PWM abstracts this implementation and provides methods to set the PWM frequency and duty cycle. The frequency is the rate at which the counter wraps back to zero. The duty cycle is the fraction of time the PWM is in logic HIGH state. The HAL_PWM API provides a few methods to get information on the PWM. Method Name ** Description ** hal_pwm_get_source_clock_freq gets the frequency of the CLOCK that is driving the COUNTER hal_pwm_get_resolution_bits gets the number of bits in the COUNTER To use a PWM via HAL_PWM, follow these simple steps. 1) initialize a PWM using hal_pwm_init -- this binds the driver to the device for the specific PWM you are using 2) Optionally set the frequency of the PWM using hal_pwm_set_frequency -- PWMs that support a TOP register have fine control over their frequency settings. If this command is not supported by the PWM it will return an error and its likely that there is no TOP register; the frequency resolution is not finely adjustable. See the BSP for coarse adjustment of the PWM frequency. 3) Enable the PWM to output a specific duty cycle using the hal_pwm_enable_duty_cycle API To change the duty cycle dynamically, just issue another hal_pwm_enable_duty_cycle command. To disable the PWM waveform, use hal_pwm_disable .","title":"HAL_PWM Theory Of Operation"},{"location":"os/modules/hal/hal_spi/hal_spi/","text":"hal_spi SPI (Serial Peripheral Interface) is a synchronous 4-wire serial interface commonly used to connect components in embedded systems. For a detailed description of SPI, see Wikipedia . Description The Mynewt HAL interface supports the SPI master functionality only. Future version will support SPI slave functionality. Definition hal_spi.h HAL_SPI Theory Of Operation SPI is called a 4-wire interface because of the 4 signals, MISO, MOSI, CLK, and SS. The SS signal (slave select) is an active low signal that activates a SPI slave device. This is how a master \"addresses\" a particular slave device. Often this signal is also referred to as \"chip select\" as it selects particular slave device for communications. The Mynewt SPI HAL has blocking transfers. This means that the API call to transfer a byte will wait until the byte completes transmissions before the function returns. Since SPI is generally a shared communications bus, the hal_spi API allows SPI runtime configuration to be compatible with the data format and speed of the slave device. See the hal_spi_config method in the API above for a description of the available settings. These settings are critical to the operation of the slave device. The Mynewt SPI HAL does not include built-in SS signaling. Its up to the hal_spi user to control their own SS pins. Typically applications will do this with GPIO. An example of this would look like this (error handling excluded for brevity): /* each device may have different settings */ extern struct hal_spi_settings dev1; extern struct hal_spi_settings dev2; gpio_init_out(SS_DEV_1, 1); gpio_init_out(SS_DEV_2, 1); hal_spi *pspi = hal_spi_init(SPI0); ... /* write a single byte (0) to device 1 */ hal_spi_config(pspi, &dev1); gpio_clear(SS_DEV_1) rc = hal_spi_transfer(pspi, 0) gpio_set(SS_DEV_1) /* read a single byte from device 2 */ hal_spi_config(pspi, &dev2); gpio_clear(SS_DEV_2) val = hal_spi_transfer(pspi, 0) gpio_set(SS_DEV_2) Depending on the device's operation, it may be necessary or more efficient to write or read multiple bytes in a single transaction. An example is shown below ```no-highlight void spi_write_buf(struct hal_spi *pspi, uint8_t *buf, int len) { char *ptr = buf; hal_spi_config(pspi, &dev2); gpio_clear(SS_DEV_2) while(len-- > 0) { val = hal_spi_transfer(pspi, (uint16_t) *ptr++) } gpio_set(SS_DEV_2) }","title":"SPI"},{"location":"os/modules/hal/hal_spi/hal_spi/#hal_spi","text":"SPI (Serial Peripheral Interface) is a synchronous 4-wire serial interface commonly used to connect components in embedded systems. For a detailed description of SPI, see Wikipedia .","title":"hal_spi"},{"location":"os/modules/hal/hal_spi/hal_spi/#description","text":"The Mynewt HAL interface supports the SPI master functionality only. Future version will support SPI slave functionality.","title":"Description"},{"location":"os/modules/hal/hal_spi/hal_spi/#definition","text":"hal_spi.h","title":"Definition"},{"location":"os/modules/hal/hal_spi/hal_spi/#hal_spi-theory-of-operation","text":"SPI is called a 4-wire interface because of the 4 signals, MISO, MOSI, CLK, and SS. The SS signal (slave select) is an active low signal that activates a SPI slave device. This is how a master \"addresses\" a particular slave device. Often this signal is also referred to as \"chip select\" as it selects particular slave device for communications. The Mynewt SPI HAL has blocking transfers. This means that the API call to transfer a byte will wait until the byte completes transmissions before the function returns. Since SPI is generally a shared communications bus, the hal_spi API allows SPI runtime configuration to be compatible with the data format and speed of the slave device. See the hal_spi_config method in the API above for a description of the available settings. These settings are critical to the operation of the slave device. The Mynewt SPI HAL does not include built-in SS signaling. Its up to the hal_spi user to control their own SS pins. Typically applications will do this with GPIO. An example of this would look like this (error handling excluded for brevity): /* each device may have different settings */ extern struct hal_spi_settings dev1; extern struct hal_spi_settings dev2; gpio_init_out(SS_DEV_1, 1); gpio_init_out(SS_DEV_2, 1); hal_spi *pspi = hal_spi_init(SPI0); ... /* write a single byte (0) to device 1 */ hal_spi_config(pspi, &dev1); gpio_clear(SS_DEV_1) rc = hal_spi_transfer(pspi, 0) gpio_set(SS_DEV_1) /* read a single byte from device 2 */ hal_spi_config(pspi, &dev2); gpio_clear(SS_DEV_2) val = hal_spi_transfer(pspi, 0) gpio_set(SS_DEV_2) Depending on the device's operation, it may be necessary or more efficient to write or read multiple bytes in a single transaction. An example is shown below ```no-highlight void spi_write_buf(struct hal_spi *pspi, uint8_t *buf, int len) { char *ptr = buf; hal_spi_config(pspi, &dev2); gpio_clear(SS_DEV_2) while(len-- > 0) { val = hal_spi_transfer(pspi, (uint16_t) *ptr++) } gpio_set(SS_DEV_2) }","title":"HAL_SPI Theory Of Operation"},{"location":"os/modules/hal/hal_system/hal_sys/","text":"","title":"System"},{"location":"os/modules/hal/hal_uart/hal_uart/","text":"hal_uart The hardware independent UART interface for Mynewt. Description Contains the basic operations to send and receive data over a UART (Universal Asynchronous Receiver Transmitter). Definition hal_uart.h Examples This example shows a user writing a character to the uart /* write to the console with blocking */ { char *str = \"Hello World!\"; char *ptr = str; while(*ptr) { hal_uart_blocking_tx(MY_UART, *ptr++); } hal_uart_blocking_tx(MY_UART, '\\n'); }","title":"UART"},{"location":"os/modules/hal/hal_uart/hal_uart/#hal_uart","text":"The hardware independent UART interface for Mynewt.","title":"hal_uart"},{"location":"os/modules/hal/hal_uart/hal_uart/#description","text":"Contains the basic operations to send and receive data over a UART (Universal Asynchronous Receiver Transmitter).","title":"Description"},{"location":"os/modules/hal/hal_uart/hal_uart/#definition","text":"hal_uart.h","title":"Definition"},{"location":"os/modules/hal/hal_uart/hal_uart/#examples","text":"This example shows a user writing a character to the uart /* write to the console with blocking */ { char *str = \"Hello World!\"; char *ptr = str; while(*ptr) { hal_uart_blocking_tx(MY_UART, *ptr++); } hal_uart_blocking_tx(MY_UART, '\\n'); }","title":"Examples"},{"location":"os/modules/imgmgr/imgmgr/","text":"Image Manager Description This library accepts incoming image management commands from newtmgr and acts on them. Images can be uploaded, present images listed, and system can be told to switch to another image. Currently the package assumes that there are 2 image slots, one active one and another one in standby. When new image is uploaded, it replaces the one in standby slot. This is the model for scenario when MCU has internal flash only, it executes the code from that flash, and there is enough space to store 2 full images. Image manager interacts with bootloader by telling it to boot to a specific image. At the moment this has to be done by writing a file which contains a version number of the image to boot. Note that image manager itself does not replace the active image. Image manager also can upload files to filesystem as well as download them. Note that commands accessing filesystems (next boot target, file upload/download) will not be available unless project includes filesystem implementation. Data structures N/A. List of Functions The functions available in imgmgr are: Function Description imgmgr_module_init Registers image manager commands with newtmgr. imgr_ver_parse Parses character string containing specified image version number and writes that to given image_version struct. imgr_ver_str Takes version string from specified image_version struct and formats it into a printable string.","title":"toc"},{"location":"os/modules/imgmgr/imgmgr/#image-manager","text":"","title":"Image Manager"},{"location":"os/modules/imgmgr/imgmgr/#description","text":"This library accepts incoming image management commands from newtmgr and acts on them. Images can be uploaded, present images listed, and system can be told to switch to another image. Currently the package assumes that there are 2 image slots, one active one and another one in standby. When new image is uploaded, it replaces the one in standby slot. This is the model for scenario when MCU has internal flash only, it executes the code from that flash, and there is enough space to store 2 full images. Image manager interacts with bootloader by telling it to boot to a specific image. At the moment this has to be done by writing a file which contains a version number of the image to boot. Note that image manager itself does not replace the active image. Image manager also can upload files to filesystem as well as download them. Note that commands accessing filesystems (next boot target, file upload/download) will not be available unless project includes filesystem implementation.","title":"Description"},{"location":"os/modules/imgmgr/imgmgr/#data-structures","text":"N/A.","title":"Data structures"},{"location":"os/modules/imgmgr/imgmgr/#list-of-functions","text":"The functions available in imgmgr are: Function Description imgmgr_module_init Registers image manager commands with newtmgr. imgr_ver_parse Parses character string containing specified image version number and writes that to given image_version struct. imgr_ver_str Takes version string from specified image_version struct and formats it into a printable string.","title":"List of Functions"},{"location":"os/modules/imgmgr/imgmgr_module_init/","text":"imgmgr_module_init int imgmgr_module_init(void) Registers image manager commands with newtmgr. This function should be called while initializing the project, preferably after newtmgr itself has been initialized. Arguments N/A Returned values List any values returned. Error codes? Notes Example int main(int argc, char **argv) { ... nmgr_task_init(NEWTMGR_TASK_PRIO, newtmgr_stack, NEWTMGR_TASK_STACK_SIZE); imgmgr_module_init(); ... }","title":"imgmgr_module_init"},{"location":"os/modules/imgmgr/imgmgr_module_init/#imgmgr_module_init","text":"int imgmgr_module_init(void) Registers image manager commands with newtmgr. This function should be called while initializing the project, preferably after newtmgr itself has been initialized.","title":" imgmgr_module_init "},{"location":"os/modules/imgmgr/imgmgr_module_init/#arguments","text":"N/A","title":"Arguments"},{"location":"os/modules/imgmgr/imgmgr_module_init/#returned-values","text":"List any values returned. Error codes?","title":"Returned values"},{"location":"os/modules/imgmgr/imgmgr_module_init/#notes","text":"","title":"Notes"},{"location":"os/modules/imgmgr/imgmgr_module_init/#example","text":"int main(int argc, char **argv) { ... nmgr_task_init(NEWTMGR_TASK_PRIO, newtmgr_stack, NEWTMGR_TASK_STACK_SIZE); imgmgr_module_init(); ... }","title":"Example"},{"location":"os/modules/imgmgr/imgr_ver_parse/","text":"imgr_ver_parse int imgr_ver_parse(char *src, struct image_version *ver) Parses character string containing image version number src and writes that to ver . Version number string should be in format . . . . Major and minor numbers should be within range 0-255, revision between 0-65535 and build_number 0-4294967295. Arguments Arguments Description src Pointer to C string that contains version number being parsed ver Image version number structure containing the returned value Returned values 0 on success and <0 if version number string could not be parsed. Notes Numbers within the string are separated by . . The first number is the major number, and must be provided. Rest of the numbers (minor etc.) are optional. Example int main(int argc, char **argv) { struct image_version hdr_ver; int rc; ... rc = imgr_ver_parse(argv[3], &hdr_ver); if (rc != 0) { print_usage(stderr); return 1; } ... }","title":"imgr_ver_parse"},{"location":"os/modules/imgmgr/imgr_ver_parse/#imgr_ver_parse","text":"int imgr_ver_parse(char *src, struct image_version *ver) Parses character string containing image version number src and writes that to ver . Version number string should be in format . . . . Major and minor numbers should be within range 0-255, revision between 0-65535 and build_number 0-4294967295.","title":" imgr_ver_parse "},{"location":"os/modules/imgmgr/imgr_ver_parse/#arguments","text":"Arguments Description src Pointer to C string that contains version number being parsed ver Image version number structure containing the returned value","title":"Arguments"},{"location":"os/modules/imgmgr/imgr_ver_parse/#returned-values","text":"0 on success and <0 if version number string could not be parsed.","title":"Returned values"},{"location":"os/modules/imgmgr/imgr_ver_parse/#notes","text":"Numbers within the string are separated by . . The first number is the major number, and must be provided. Rest of the numbers (minor etc.) are optional.","title":"Notes"},{"location":"os/modules/imgmgr/imgr_ver_parse/#example","text":"int main(int argc, char **argv) { struct image_version hdr_ver; int rc; ... rc = imgr_ver_parse(argv[3], &hdr_ver); if (rc != 0) { print_usage(stderr); return 1; } ... }","title":"Example"},{"location":"os/modules/imgmgr/imgr_ver_str/","text":"imgr_ver_str int imgr_ver_str(struct image_version *ver, char *dst) Takes the version string from ver and formats that into a printable string to dst . Caller must make sure that dst contains enough space to hold maximum length version string. The convenience defininition for max length version string is named IMGMGR_MAX_VER_STR . Arguments Arguments Description ver Image version number structure containing the value being formatted dst Pointer to C string where results will be stored Returned values Function returns the number of characters filled into the destination string. Notes If build number is 0 in image version structure, it will be left out of the string. Example static void imgr_ver_jsonstr(struct json_encoder *enc, char *key, struct image_version *ver) { char ver_str[IMGMGR_MAX_VER_STR]; int ver_len; ... ver_len = imgr_ver_str(ver, ver_str) ... }","title":"imgr_ver_str"},{"location":"os/modules/imgmgr/imgr_ver_str/#imgr_ver_str","text":"int imgr_ver_str(struct image_version *ver, char *dst) Takes the version string from ver and formats that into a printable string to dst . Caller must make sure that dst contains enough space to hold maximum length version string. The convenience defininition for max length version string is named IMGMGR_MAX_VER_STR .","title":" imgr_ver_str "},{"location":"os/modules/imgmgr/imgr_ver_str/#arguments","text":"Arguments Description ver Image version number structure containing the value being formatted dst Pointer to C string where results will be stored","title":"Arguments"},{"location":"os/modules/imgmgr/imgr_ver_str/#returned-values","text":"Function returns the number of characters filled into the destination string.","title":"Returned values"},{"location":"os/modules/imgmgr/imgr_ver_str/#notes","text":"If build number is 0 in image version structure, it will be left out of the string.","title":"Notes"},{"location":"os/modules/imgmgr/imgr_ver_str/#example","text":"static void imgr_ver_jsonstr(struct json_encoder *enc, char *key, struct image_version *ver) { char ver_str[IMGMGR_MAX_VER_STR]; int ver_len; ... ver_len = imgr_ver_str(ver, ver_str) ... }","title":"Example"},{"location":"os/modules/json/json/","text":"JSON JSON is a data interchange format. The description of this format can be found from IETF RFC 4627. Description This package helps in converting between C data types and JSON data objects. It supports both encoding and decoding. Data structures Encoding /* Encoding functions */ typedef int ( *json_write_func_t )( void *buf , char *data , int len ); struct json_encoder { json_write_func_t je_write ; void *je_arg ; int je_wr_commas: 1 ; char je_encode_buf [ 64 ]; }; Here's the data structure encoder funtions use, and it must be initialized by the caller. The key element is je_write , which is a function pointer which gets called whenever encoding routine is ready with encoded data. The element je_arg is passed to je_write as the first argument. The rest of the structure contents are for internal state management. This function should collect all the data encoder function generates. It can collect this data to a flat buffer, chain of mbufs or even stream through. /** * For encode. The contents of a JSON value to encode. */ struct json_value { uint8_t jv_pad1 ; uint8_t jv_type ; uint16_t jv_len ; union { uint64_t u ; float fl ; char *str ; struct { char **keys ; struct json_value **values ; } composite ; } jv_val ; }; This data structure is filled with data to be encoded. It is best to fill this using the macros JSON_VALUE_STRING() or JSON_VALUE_STRINGN() when value is string, JSON_VALUE_INT() when value is an integer, and so forth. Decoding /* when you implement a json buffer, you must implement these functions */ /* returns the next character in the buffer or '\\0'*/ typedef char ( *json_buffer_read_next_byte_t )( struct json_buffer * ); /* returns the previous character in the buffer or '\\0' */ typedef char ( *json_buffer_read_prev_byte_t )( struct json_buffer * ); /* returns the number of characters read or zero */ typedef int ( *json_buffer_readn_t )( struct json_buffer * , char *buf , int n ); struct json_buffer { json_buffer_readn_t jb_readn ; json_buffer_read_next_byte_t jb_read_next ; json_buffer_read_prev_byte_t jb_read_prev ; }; Function pointers within this structure are used by decoder when it is reading in more data to decode. struct json_attr_t { char *attribute ; json_type type ; union { int *integer ; unsigned int *uinteger ; double *real ; char *string ; bool *boolean ; char *character ; struct json_array_t array ; size_t offset ; } addr ; union { int integer ; unsigned int uinteger ; double real ; bool boolean ; char character ; char *check ; } dflt ; size_t len ; const struct json_enum_t *map ; bool nodefault ; }; This structure tells the decoder about a particular name/value pair. Structure must be filled in before calling the decoder routine json_read_object() . Element Description attribute Name of the value type The type of the variable; see enum json_type addr Contains the address where value should be stored dflt Default value to fill in, if this name is not found len Max number of bytes to read in for value nodefault If set, default value is not copied name List of Functions Functions for encoding: Function Description json_encode_object_start This function starts the encoded JSON object. json_encode_object_key This function writes out a name for a field, followed by \":\" character. json_encode_object_entry This function writes out a name for a field, followed by \":\" character, and the value itself. json_encode_object_finish This function finalizes the encoded JSON object. Functions for decoding: Function Description json_read_object This function reads in JSON data stream, while looking for name/value pairs described in given attribites.","title":"toc"},{"location":"os/modules/json/json/#json","text":"JSON is a data interchange format. The description of this format can be found from IETF RFC 4627.","title":"JSON"},{"location":"os/modules/json/json/#description","text":"This package helps in converting between C data types and JSON data objects. It supports both encoding and decoding.","title":"Description"},{"location":"os/modules/json/json/#data-structures","text":"","title":"Data structures"},{"location":"os/modules/json/json/#encoding","text":"/* Encoding functions */ typedef int ( *json_write_func_t )( void *buf , char *data , int len ); struct json_encoder { json_write_func_t je_write ; void *je_arg ; int je_wr_commas: 1 ; char je_encode_buf [ 64 ]; }; Here's the data structure encoder funtions use, and it must be initialized by the caller. The key element is je_write , which is a function pointer which gets called whenever encoding routine is ready with encoded data. The element je_arg is passed to je_write as the first argument. The rest of the structure contents are for internal state management. This function should collect all the data encoder function generates. It can collect this data to a flat buffer, chain of mbufs or even stream through. /** * For encode. The contents of a JSON value to encode. */ struct json_value { uint8_t jv_pad1 ; uint8_t jv_type ; uint16_t jv_len ; union { uint64_t u ; float fl ; char *str ; struct { char **keys ; struct json_value **values ; } composite ; } jv_val ; }; This data structure is filled with data to be encoded. It is best to fill this using the macros JSON_VALUE_STRING() or JSON_VALUE_STRINGN() when value is string, JSON_VALUE_INT() when value is an integer, and so forth.","title":"Encoding"},{"location":"os/modules/json/json/#decoding","text":"/* when you implement a json buffer, you must implement these functions */ /* returns the next character in the buffer or '\\0'*/ typedef char ( *json_buffer_read_next_byte_t )( struct json_buffer * ); /* returns the previous character in the buffer or '\\0' */ typedef char ( *json_buffer_read_prev_byte_t )( struct json_buffer * ); /* returns the number of characters read or zero */ typedef int ( *json_buffer_readn_t )( struct json_buffer * , char *buf , int n ); struct json_buffer { json_buffer_readn_t jb_readn ; json_buffer_read_next_byte_t jb_read_next ; json_buffer_read_prev_byte_t jb_read_prev ; }; Function pointers within this structure are used by decoder when it is reading in more data to decode. struct json_attr_t { char *attribute ; json_type type ; union { int *integer ; unsigned int *uinteger ; double *real ; char *string ; bool *boolean ; char *character ; struct json_array_t array ; size_t offset ; } addr ; union { int integer ; unsigned int uinteger ; double real ; bool boolean ; char character ; char *check ; } dflt ; size_t len ; const struct json_enum_t *map ; bool nodefault ; }; This structure tells the decoder about a particular name/value pair. Structure must be filled in before calling the decoder routine json_read_object() . Element Description attribute Name of the value type The type of the variable; see enum json_type addr Contains the address where value should be stored dflt Default value to fill in, if this name is not found len Max number of bytes to read in for value nodefault If set, default value is not copied name","title":"Decoding"},{"location":"os/modules/json/json/#list-of-functions","text":"Functions for encoding: Function Description json_encode_object_start This function starts the encoded JSON object. json_encode_object_key This function writes out a name for a field, followed by \":\" character. json_encode_object_entry This function writes out a name for a field, followed by \":\" character, and the value itself. json_encode_object_finish This function finalizes the encoded JSON object. Functions for decoding: Function Description json_read_object This function reads in JSON data stream, while looking for name/value pairs described in given attribites.","title":"List of Functions"},{"location":"os/modules/json/json_encode_object_entry/","text":"json_encode_object_entry int json_encode_object_entry(struct json_encoder *encoder, char *key, struct json_value *val) This function writes out a name for a field, followed by \":\" character, and the value itself. How value is treated depends on the type of the value. Arguments Arguments Description encoder json_encoder to use key name to write out val value to write out Returned values 0 on success. Example static int imgr_list ( struct nmgr_jbuf *njb ) { struct json_encoder *enc ; struct json_value array ; ... json_encode_object_start ( enc ); json_encode_object_entry ( enc , \"images\" , &array ); json_encode_object_finish ( enc ); return 0 ; }","title":"json_encode_object_entry"},{"location":"os/modules/json/json_encode_object_entry/#json_encode_object_entry","text":"int json_encode_object_entry(struct json_encoder *encoder, char *key, struct json_value *val) This function writes out a name for a field, followed by \":\" character, and the value itself. How value is treated depends on the type of the value.","title":" json_encode_object_entry "},{"location":"os/modules/json/json_encode_object_entry/#arguments","text":"Arguments Description encoder json_encoder to use key name to write out val value to write out","title":"Arguments"},{"location":"os/modules/json/json_encode_object_entry/#returned-values","text":"0 on success.","title":"Returned values"},{"location":"os/modules/json/json_encode_object_entry/#example","text":"static int imgr_list ( struct nmgr_jbuf *njb ) { struct json_encoder *enc ; struct json_value array ; ... json_encode_object_start ( enc ); json_encode_object_entry ( enc , \"images\" , &array ); json_encode_object_finish ( enc ); return 0 ; }","title":"Example"},{"location":"os/modules/json/json_encode_object_finish/","text":"json_encode_object_finish int json_encode_object_finish(struct json_encoder *encoder) This function finalizes the encoded JSON object. This means writing out the last \"}\" character. Arguments Arguments Description encoder json_encoder to use Returned values 0 on success. Example static int imgr_list ( struct nmgr_jbuf *njb ) { struct json_encoder *enc ; struct json_value array ; ... json_encode_object_start ( enc ); json_encode_object_entry ( enc , \"images\" , &array ); json_encode_object_finish ( enc ); return 0 ; }","title":"json_encode_object_finish"},{"location":"os/modules/json/json_encode_object_finish/#json_encode_object_finish","text":"int json_encode_object_finish(struct json_encoder *encoder) This function finalizes the encoded JSON object. This means writing out the last \"}\" character.","title":" json_encode_object_finish "},{"location":"os/modules/json/json_encode_object_finish/#arguments","text":"Arguments Description encoder json_encoder to use","title":"Arguments"},{"location":"os/modules/json/json_encode_object_finish/#returned-values","text":"0 on success.","title":"Returned values"},{"location":"os/modules/json/json_encode_object_finish/#example","text":"static int imgr_list ( struct nmgr_jbuf *njb ) { struct json_encoder *enc ; struct json_value array ; ... json_encode_object_start ( enc ); json_encode_object_entry ( enc , \"images\" , &array ); json_encode_object_finish ( enc ); return 0 ; }","title":"Example"},{"location":"os/modules/json/json_encode_object_key/","text":"json_encode_object_key int json_encode_object_key(struct json_encoder *encoder, char *key) This function writes out a name for a field, followed by \":\" character. You would use this e.g. when the value that follows is a JSON object. Arguments Arguments Description encoder json_encoder to use key name to write out Returned values 0 on success. Example int nmgr_def_taskstat_read ( struct nmgr_jbuf *njb ) { ... struct json_value jv ; json_encode_object_start ( &njb->njb_enc ); JSON_VALUE_INT ( &jv , NMGR_ERR_EOK ); json_encode_object_entry ( &njb->njb_enc , \"rc\" , &jv ); json_encode_object_key ( &njb->njb_enc , \"tasks\" ); json_encode_object_start ( &njb->njb_enc ); ... }","title":"json_encode_object_key"},{"location":"os/modules/json/json_encode_object_key/#json_encode_object_key","text":"int json_encode_object_key(struct json_encoder *encoder, char *key) This function writes out a name for a field, followed by \":\" character. You would use this e.g. when the value that follows is a JSON object.","title":" json_encode_object_key "},{"location":"os/modules/json/json_encode_object_key/#arguments","text":"Arguments Description encoder json_encoder to use key name to write out","title":"Arguments"},{"location":"os/modules/json/json_encode_object_key/#returned-values","text":"0 on success.","title":"Returned values"},{"location":"os/modules/json/json_encode_object_key/#example","text":"int nmgr_def_taskstat_read ( struct nmgr_jbuf *njb ) { ... struct json_value jv ; json_encode_object_start ( &njb->njb_enc ); JSON_VALUE_INT ( &jv , NMGR_ERR_EOK ); json_encode_object_entry ( &njb->njb_enc , \"rc\" , &jv ); json_encode_object_key ( &njb->njb_enc , \"tasks\" ); json_encode_object_start ( &njb->njb_enc ); ... }","title":"Example"},{"location":"os/modules/json/json_encode_object_start/","text":"json_encode_object_start int json_encode_object_start(struct json_encoder *encoder) This function starts the encoded JSON object. Usually this means writing out the initial \"{\" character. Arguments Arguments Description encoder json_encoder to use Returned values 0 on success. Example static int imgr_list ( struct nmgr_jbuf *njb ) { struct json_encoder *enc ; struct json_value array ; ... json_encode_object_start ( enc ); json_encode_object_entry ( enc , \"images\" , &array ); json_encode_object_finish ( enc ); return 0 ; }","title":"json_encode_object_start"},{"location":"os/modules/json/json_encode_object_start/#json_encode_object_start","text":"int json_encode_object_start(struct json_encoder *encoder) This function starts the encoded JSON object. Usually this means writing out the initial \"{\" character.","title":" json_encode_object_start "},{"location":"os/modules/json/json_encode_object_start/#arguments","text":"Arguments Description encoder json_encoder to use","title":"Arguments"},{"location":"os/modules/json/json_encode_object_start/#returned-values","text":"0 on success.","title":"Returned values"},{"location":"os/modules/json/json_encode_object_start/#example","text":"static int imgr_list ( struct nmgr_jbuf *njb ) { struct json_encoder *enc ; struct json_value array ; ... json_encode_object_start ( enc ); json_encode_object_entry ( enc , \"images\" , &array ); json_encode_object_finish ( enc ); return 0 ; }","title":"Example"},{"location":"os/modules/json/json_read_object/","text":"json_read_object int json_read_object(struct json_buffer *jb, const struct json_attr_t *attrs) This function reads in JSON data stream, while looking for name/value pairs described in attrs . attrs is an array; end of the array is indicated by an entry with NULL as the name. Arguments Arguments Description jb json_decoder to use attrs array of attributes to look for Returned values 0 on success. Example static int imgr_upload ( struct nmgr_jbuf *njb ) { ... const struct json_attr_t off_attr [ 4 ] = { [ 0 ] = { . attribute = \"off\" , . type = t_uinteger , . addr . uinteger = &off , . nodefault = true }, [ 1 ] = { . attribute = \"data\" , . type = t_string , . addr . string = img_data , . len = sizeof ( img_data ) }, [ 2 ] = { . attribute = \"len\" , . type = t_uinteger , . addr . uinteger = &size , . nodefault = true } }; ... rc = json_read_object ( &njb->njb_buf , off_attr ); if ( rc || off == UINT_MAX ) { rc = OS_EINVAL ; goto err ; } ... }","title":"json_read_object"},{"location":"os/modules/json/json_read_object/#json_read_object","text":"int json_read_object(struct json_buffer *jb, const struct json_attr_t *attrs) This function reads in JSON data stream, while looking for name/value pairs described in attrs . attrs is an array; end of the array is indicated by an entry with NULL as the name.","title":" json_read_object "},{"location":"os/modules/json/json_read_object/#arguments","text":"Arguments Description jb json_decoder to use attrs array of attributes to look for","title":"Arguments"},{"location":"os/modules/json/json_read_object/#returned-values","text":"0 on success.","title":"Returned values"},{"location":"os/modules/json/json_read_object/#example","text":"static int imgr_upload ( struct nmgr_jbuf *njb ) { ... const struct json_attr_t off_attr [ 4 ] = { [ 0 ] = { . attribute = \"off\" , . type = t_uinteger , . addr . uinteger = &off , . nodefault = true }, [ 1 ] = { . attribute = \"data\" , . type = t_string , . addr . string = img_data , . len = sizeof ( img_data ) }, [ 2 ] = { . attribute = \"len\" , . type = t_uinteger , . addr . uinteger = &size , . nodefault = true } }; ... rc = json_read_object ( &njb->njb_buf , off_attr ); if ( rc || off == UINT_MAX ) { rc = OS_EINVAL ; goto err ; } ... }","title":"Example"},{"location":"os/modules/logs/logs/","text":"Mynewt Logging Apache Mynewt has a logging package ( apache-mynewt-core/sys/log ) to support logging of information within a Mynewt application. Description Logging API is provided in apache-mynewt-core/sys/log/include/log/log.h . It allows packages to define their own log streams with separate names. It also allows an application to control the output destinations of logs. Compile Time Settings To save space at compile time, there is a compile time log level that includes/excludes certain logs at compile time, saving image space. For example, during debug, you can have significant logs present, but disable these at compile time to ensure the code size limits are met. A compiler flag LOG_LEVEL can be set in your target.cflags or within your app pkg.cflags files to set the compile time log level. The log level are defined in apache-mynewt-core/sys/log/include/log/log.h but must be added by number to your yml file. For example: pkg.cflags -DLOG_LEVEL=8 or newt target set my_target cflags=-DLOG_LEVEL=8 would both set the compile-time log level to LOG_LEVEL_ERROR . All logs of less than LOG_LEVEL_ERROR severity would be disabled at compile time and take no space within the Mynewt application image. These compile time settings are applicable to all logs registered with the system. Log Each log stream requires a log structure to define its logging properties. It is typical for modules to extern this structure. Log Handler To use logs, a log-handler is required, which is responsible for handling the I/O from the log. The log package comes with two pre-built log handlers. console -- streams log events directly to the console port. Does not support walking and reading. cbmem -- writes/reads log events to a circular buffer. Supports walking and reading for access by newtmgr and shell commands. In addition, it is possible to create custom log handlers for other methods. Examples may include Flash file system Flat flash buffer Streamed over some other interface To use logging, you will not typically need to create your own log handler. You can use one of the two supplied above. In Mynewt today, each module will register its logs with a default log handler. Its up to the application to use or override this log handler for its specific purposes. See below for an example. Typical use of logging when writing an application When writing an application that is using other's log modules, you may want to override their log handlers and log levels. Add the logging to your package file. pkg.deps: - \"@apache-mynewt-core/sys/log\" Initialize the logs in your startup code. It may look like this #include <module1/module1.h> #include <module3/module2.h> #include <module3/module3.h> #include <log/log.h> /* log to console */ static struct log_handler app_log_handler ; /* this has to be after all the modules are * initialized and have registered * their log modules */ void app_log_init ( void ) { /* create a log handler for all logs . FOr this application ** send them directly to the console port */ log_console_handler_init ( &app_log_handler ); ... /* set up logging for the modules appropriately */ module1_log . log_level = LOG_LEVEL_WARN ; module2_log . log_level = LOG_LEVEL_INFO ; module3_log . log_level = LOG_LEVEL_DEBUG ; /* set up a single handler for all modules */ module1_log . log_handler = &app_log_handler ; module2_log . log_handler = &app_log_handler ; module3_log . log_handler = &app_log_handler ; } Typical use of Logging when writing a module When creating a package using its own logging, you can have this type of structure. /* my_package.h*/ /* pick a unique name here */ extern struct log my_log ; with an implementation in your module that looks like this: /* my_package.c */ struct log_handler log_console_handler ; struct log my_log ; { ... /* create a default handler for this log stream */ log_console_handler_init ( &log_console_handler ); /* register my log with a name to the system */ log_register ( \"log\" , &my_log , &log_console_handler ); /* set up default log level for my package */ my_log . log_level = LOG_LEVEL_DEBUG ; LOG_DEBUG ( &my_log , LOG_MODULE_DEFAULT , \"bla\" ); LOG_DEBUG ( &my_log , LOG_MODULE_DEFAULT , \"bab\" ); }","title":"toc"},{"location":"os/modules/logs/logs/#mynewt-logging","text":"Apache Mynewt has a logging package ( apache-mynewt-core/sys/log ) to support logging of information within a Mynewt application.","title":"Mynewt Logging"},{"location":"os/modules/logs/logs/#description","text":"Logging API is provided in apache-mynewt-core/sys/log/include/log/log.h . It allows packages to define their own log streams with separate names. It also allows an application to control the output destinations of logs.","title":"Description"},{"location":"os/modules/logs/logs/#compile-time-settings","text":"To save space at compile time, there is a compile time log level that includes/excludes certain logs at compile time, saving image space. For example, during debug, you can have significant logs present, but disable these at compile time to ensure the code size limits are met. A compiler flag LOG_LEVEL can be set in your target.cflags or within your app pkg.cflags files to set the compile time log level. The log level are defined in apache-mynewt-core/sys/log/include/log/log.h but must be added by number to your yml file. For example: pkg.cflags -DLOG_LEVEL=8 or newt target set my_target cflags=-DLOG_LEVEL=8 would both set the compile-time log level to LOG_LEVEL_ERROR . All logs of less than LOG_LEVEL_ERROR severity would be disabled at compile time and take no space within the Mynewt application image. These compile time settings are applicable to all logs registered with the system.","title":"Compile Time Settings"},{"location":"os/modules/logs/logs/#log","text":"Each log stream requires a log structure to define its logging properties. It is typical for modules to extern this structure.","title":"Log"},{"location":"os/modules/logs/logs/#log-handler","text":"To use logs, a log-handler is required, which is responsible for handling the I/O from the log. The log package comes with two pre-built log handlers. console -- streams log events directly to the console port. Does not support walking and reading. cbmem -- writes/reads log events to a circular buffer. Supports walking and reading for access by newtmgr and shell commands. In addition, it is possible to create custom log handlers for other methods. Examples may include Flash file system Flat flash buffer Streamed over some other interface To use logging, you will not typically need to create your own log handler. You can use one of the two supplied above. In Mynewt today, each module will register its logs with a default log handler. Its up to the application to use or override this log handler for its specific purposes. See below for an example.","title":"Log Handler"},{"location":"os/modules/logs/logs/#typical-use-of-logging-when-writing-an-application","text":"When writing an application that is using other's log modules, you may want to override their log handlers and log levels. Add the logging to your package file. pkg.deps: - \"@apache-mynewt-core/sys/log\" Initialize the logs in your startup code. It may look like this #include <module1/module1.h> #include <module3/module2.h> #include <module3/module3.h> #include <log/log.h> /* log to console */ static struct log_handler app_log_handler ; /* this has to be after all the modules are * initialized and have registered * their log modules */ void app_log_init ( void ) { /* create a log handler for all logs . FOr this application ** send them directly to the console port */ log_console_handler_init ( &app_log_handler ); ... /* set up logging for the modules appropriately */ module1_log . log_level = LOG_LEVEL_WARN ; module2_log . log_level = LOG_LEVEL_INFO ; module3_log . log_level = LOG_LEVEL_DEBUG ; /* set up a single handler for all modules */ module1_log . log_handler = &app_log_handler ; module2_log . log_handler = &app_log_handler ; module3_log . log_handler = &app_log_handler ; }","title":"Typical use of logging when writing an application"},{"location":"os/modules/logs/logs/#typical-use-of-logging-when-writing-a-module","text":"When creating a package using its own logging, you can have this type of structure. /* my_package.h*/ /* pick a unique name here */ extern struct log my_log ; with an implementation in your module that looks like this: /* my_package.c */ struct log_handler log_console_handler ; struct log my_log ; { ... /* create a default handler for this log stream */ log_console_handler_init ( &log_console_handler ); /* register my log with a name to the system */ log_register ( \"log\" , &my_log , &log_console_handler ); /* set up default log level for my package */ my_log . log_level = LOG_LEVEL_DEBUG ; LOG_DEBUG ( &my_log , LOG_MODULE_DEFAULT , \"bla\" ); LOG_DEBUG ( &my_log , LOG_MODULE_DEFAULT , \"bab\" ); }","title":"Typical use of Logging when writing a module"},{"location":"os/modules/shell/shell/","text":"Shell The shell is package sitting on top of console, handling 2 jobs: processing console input and implementing newtmgr line protocol over serial line. Shell runs on its own task. Description Shell's first job is directing incoming commands to other subsystems. It parses the incoming character string, and splits it into tokens. Then it looks for the subsystem to handle this command based on the first token of input. Subsystems register their command handlers using shell_cmd_register() . When shell calls the command handler, it passes the other tokens as arguments. A few commands are currently available in the shell - tasks , log , and stat stat . A $ prompt sign will be coming soon! Shell's second job is doing framing, encoding and decoding newtmgr protocol when it's carried over the console. Protocol handler (libs/newtmgr) registers itself using shell_nlip_input_register() , and shell calls the registered handler for every frame. Outgoing frames for the protocol are sent using shell_nlip_output() . Create a sim target to check out these commands available in shell. user@~/dev/larva$ newt target create blinky_sim Creating target blinky_sim Target blinky_sim successfully created! user@~/dev/larva$ newt target set blinky_sim name=blinky_sim Target blinky_sim successfully set name to blinky_sim user@~/dev/larva$ newt target set blinky_sim arch=sim Target blinky_sim successfully set arch to sim user@~/dev/larva$ newt target set blinky_sim project=blinky Target blinky_sim successfully set project to blinky user@~/dev/larva$ newt target set blinky_sim bsp=hw/bsp/native Target blinky_sim successfully set bsp to hw/bsp/native user@~/dev/larva$ newt target set blinky_sim compiler_def=debug Target blinky_sim successfully set compiler_def to debug user@~/dev/larva$ newt target set blinky_sim compiler=sim Target blinky_sim successfully set compiler to sim user@~/dev/larva$ newt target show blinky_sim arch: sim bsp: hw/bsp/native compiler: sim compiler_def: debug name: blinky_sim project: blinky user@~/dev/larva$ newt target build blinky_sim Building target blinky_sim (project = blinky) Compiling case.c Compiling suite.c Compiling testutil.c .. .. Building project blinky Linking blinky.elf Successfully run! user@~/dev/larva$ ./project/blinky/bin/blinky_sim/blinky.elf uart0 at /dev/ttys005 Open up a new terminal to run minicom, a text-based serial port control and terminal emulation program. Set device name to the serial port of the target. user@~$ minicom -D /dev/ttys005 Welcome to minicom 2.7 OPTIONS: Compiled on Nov 24 2015, 16:14:21. Port /dev/ttys005, 11:32:17 Press Meta-Z for help on special keys log 174578:[0] bla 174578:[0] bab tasks 217809:6 tasks: 217809: shell (prio: 3, nw: 0, flags: 0x0, ssize: 0, cswcnt: 59, tot_run_time: 0ms) 217840: idle (prio: 255, nw: 0, flags: 0x0, ssize: 0, cswcnt: 18763, tot_run_time: 217809ms) 217878: uart_poller (prio: 0, nw: 217819, flags: 0x0, ssize: 0, cswcnt: 18667, tot_run_time: 0ms) 217923: task1 (prio: 1, nw: 218710, flags: 0x0, ssize: 0, cswcnt: 218, tot_run_time: 0ms) 217953: os_sanity (prio: 254, nw: 218710, flags: 0x0, ssize: 0, cswcnt: 218, tot_run_time: 0ms) 218010: task2 (prio: 2, nw: 217709, flags: 0x3, ssize: 0, cswcnt: 218, tot_run_time: 0ms) stat stat 229881:s0: 1 Data structures This data structure is used in holding information about registered command handlers. struct shell_cmd { char *sc_cmd; shell_cmd_func_t sc_cmd_func; STAILQ_ENTRY(shell_cmd) sc_next; }; Element Description sc_cmd Character string of the command sc_cmd_func Pointer to the command handler sc_next Bookkeeping linkage internal for shell List of Functions The functions available in this OS feature are: Function Description shell_task_init Initializes the shell package. This creates a task for shell, and registers few commands on its own. shell_cmd_register Registers a handler for incoming console commands. shell_nlip_input_register Registers a handler for incoming newtmgr messages. shell_nlip_output Queue outgoing newtmgr message for transmission.","title":"toc"},{"location":"os/modules/shell/shell/#shell","text":"The shell is package sitting on top of console, handling 2 jobs: processing console input and implementing newtmgr line protocol over serial line. Shell runs on its own task.","title":"Shell"},{"location":"os/modules/shell/shell/#description","text":"Shell's first job is directing incoming commands to other subsystems. It parses the incoming character string, and splits it into tokens. Then it looks for the subsystem to handle this command based on the first token of input. Subsystems register their command handlers using shell_cmd_register() . When shell calls the command handler, it passes the other tokens as arguments. A few commands are currently available in the shell - tasks , log , and stat stat . A $ prompt sign will be coming soon! Shell's second job is doing framing, encoding and decoding newtmgr protocol when it's carried over the console. Protocol handler (libs/newtmgr) registers itself using shell_nlip_input_register() , and shell calls the registered handler for every frame. Outgoing frames for the protocol are sent using shell_nlip_output() . Create a sim target to check out these commands available in shell. user@~/dev/larva$ newt target create blinky_sim Creating target blinky_sim Target blinky_sim successfully created! user@~/dev/larva$ newt target set blinky_sim name=blinky_sim Target blinky_sim successfully set name to blinky_sim user@~/dev/larva$ newt target set blinky_sim arch=sim Target blinky_sim successfully set arch to sim user@~/dev/larva$ newt target set blinky_sim project=blinky Target blinky_sim successfully set project to blinky user@~/dev/larva$ newt target set blinky_sim bsp=hw/bsp/native Target blinky_sim successfully set bsp to hw/bsp/native user@~/dev/larva$ newt target set blinky_sim compiler_def=debug Target blinky_sim successfully set compiler_def to debug user@~/dev/larva$ newt target set blinky_sim compiler=sim Target blinky_sim successfully set compiler to sim user@~/dev/larva$ newt target show blinky_sim arch: sim bsp: hw/bsp/native compiler: sim compiler_def: debug name: blinky_sim project: blinky user@~/dev/larva$ newt target build blinky_sim Building target blinky_sim (project = blinky) Compiling case.c Compiling suite.c Compiling testutil.c .. .. Building project blinky Linking blinky.elf Successfully run! user@~/dev/larva$ ./project/blinky/bin/blinky_sim/blinky.elf uart0 at /dev/ttys005 Open up a new terminal to run minicom, a text-based serial port control and terminal emulation program. Set device name to the serial port of the target. user@~$ minicom -D /dev/ttys005 Welcome to minicom 2.7 OPTIONS: Compiled on Nov 24 2015, 16:14:21. Port /dev/ttys005, 11:32:17 Press Meta-Z for help on special keys log 174578:[0] bla 174578:[0] bab tasks 217809:6 tasks: 217809: shell (prio: 3, nw: 0, flags: 0x0, ssize: 0, cswcnt: 59, tot_run_time: 0ms) 217840: idle (prio: 255, nw: 0, flags: 0x0, ssize: 0, cswcnt: 18763, tot_run_time: 217809ms) 217878: uart_poller (prio: 0, nw: 217819, flags: 0x0, ssize: 0, cswcnt: 18667, tot_run_time: 0ms) 217923: task1 (prio: 1, nw: 218710, flags: 0x0, ssize: 0, cswcnt: 218, tot_run_time: 0ms) 217953: os_sanity (prio: 254, nw: 218710, flags: 0x0, ssize: 0, cswcnt: 218, tot_run_time: 0ms) 218010: task2 (prio: 2, nw: 217709, flags: 0x3, ssize: 0, cswcnt: 218, tot_run_time: 0ms) stat stat 229881:s0: 1","title":"Description"},{"location":"os/modules/shell/shell/#data-structures","text":"This data structure is used in holding information about registered command handlers. struct shell_cmd { char *sc_cmd; shell_cmd_func_t sc_cmd_func; STAILQ_ENTRY(shell_cmd) sc_next; }; Element Description sc_cmd Character string of the command sc_cmd_func Pointer to the command handler sc_next Bookkeeping linkage internal for shell","title":"Data structures"},{"location":"os/modules/shell/shell/#list-of-functions","text":"The functions available in this OS feature are: Function Description shell_task_init Initializes the shell package. This creates a task for shell, and registers few commands on its own. shell_cmd_register Registers a handler for incoming console commands. shell_nlip_input_register Registers a handler for incoming newtmgr messages. shell_nlip_output Queue outgoing newtmgr message for transmission.","title":"List of Functions"},{"location":"os/modules/shell/shell_cmd_register/","text":"shell_cmd_register int shell_cmd_register(struct shell_cmd *sc) Registers a handler for incoming console commands. Within the structure there is the command string and the handler for those commands. Caller must allocate the memory for this structure and keep it around as shell links this to its own internal data structures. Command handler is of type int(*shell_cmd_func_t)(int argc, char **argv) . Command line arguments are passed to it as an array of character pointers. Arguments Arguments Description sc Structure containing info about the command. Returned values Returns 0 on success. Non-zero on failure. Example static int fs_ls_cmd(int argc, char **argv); static struct shell_cmd fs_ls_struct = { .sc_cmd = \"ls\", .sc_cmd_func = fs_ls_cmd }; void fs_cli_init(void) { shell_cmd_register(&fs_ls_struct); .... }","title":"shell_cmd_register"},{"location":"os/modules/shell/shell_cmd_register/#shell_cmd_register","text":"int shell_cmd_register(struct shell_cmd *sc) Registers a handler for incoming console commands. Within the structure there is the command string and the handler for those commands. Caller must allocate the memory for this structure and keep it around as shell links this to its own internal data structures. Command handler is of type int(*shell_cmd_func_t)(int argc, char **argv) . Command line arguments are passed to it as an array of character pointers.","title":" shell_cmd_register "},{"location":"os/modules/shell/shell_cmd_register/#arguments","text":"Arguments Description sc Structure containing info about the command.","title":"Arguments"},{"location":"os/modules/shell/shell_cmd_register/#returned-values","text":"Returns 0 on success. Non-zero on failure.","title":"Returned values"},{"location":"os/modules/shell/shell_cmd_register/#example","text":"static int fs_ls_cmd(int argc, char **argv); static struct shell_cmd fs_ls_struct = { .sc_cmd = \"ls\", .sc_cmd_func = fs_ls_cmd }; void fs_cli_init(void) { shell_cmd_register(&fs_ls_struct); .... }","title":"Example"},{"location":"os/modules/shell/shell_nlip_input_register/","text":"shell_nlip_input_register int shell_nlip_input_register(shell_nlip_input_func_t nf, void *arg) Registers a handler for incoming newtmgr messages. Shell receives incoming data stream from UART and when it detects NLIP frame, it decodes it and passes it on by calling the function nf . Handler function is of type int (*shell_nlip_input_func_t)(struct os_mbuf *m, void *arg) . Shell passes the incoming newtmgr message inside os_mbuf m , and arg is the argument that was passed in during handler registration. Arguments Arguments Description nf Handler for incoming newtmgr datagrams. arg Argument that gets passed to this handler, along with the datagram Returned values Returns 0 on success. Example static int nmgr_shell_in(struct os_mbuf *m, void *arg) { .... } int nmgr_task_init(uint8_t prio, os_stack_t *stack_ptr, uint16_t stack_len) { int rc; .... rc = shell_nlip_input_register(nmgr_shell_in, (void *) &g_nmgr_shell_transport); if (rc != 0) { goto err; } .... }","title":"shell_nlip_input_register"},{"location":"os/modules/shell/shell_nlip_input_register/#shell_nlip_input_register","text":"int shell_nlip_input_register(shell_nlip_input_func_t nf, void *arg) Registers a handler for incoming newtmgr messages. Shell receives incoming data stream from UART and when it detects NLIP frame, it decodes it and passes it on by calling the function nf . Handler function is of type int (*shell_nlip_input_func_t)(struct os_mbuf *m, void *arg) . Shell passes the incoming newtmgr message inside os_mbuf m , and arg is the argument that was passed in during handler registration.","title":" shell_nlip_input_register "},{"location":"os/modules/shell/shell_nlip_input_register/#arguments","text":"Arguments Description nf Handler for incoming newtmgr datagrams. arg Argument that gets passed to this handler, along with the datagram","title":"Arguments"},{"location":"os/modules/shell/shell_nlip_input_register/#returned-values","text":"Returns 0 on success.","title":"Returned values"},{"location":"os/modules/shell/shell_nlip_input_register/#example","text":"static int nmgr_shell_in(struct os_mbuf *m, void *arg) { .... } int nmgr_task_init(uint8_t prio, os_stack_t *stack_ptr, uint16_t stack_len) { int rc; .... rc = shell_nlip_input_register(nmgr_shell_in, (void *) &g_nmgr_shell_transport); if (rc != 0) { goto err; } .... }","title":"Example"},{"location":"os/modules/shell/shell_nlip_output/","text":"shell_nlip_output int shell_nlip_output(struct os_mbuf *m) Queue outgoing newtmgr message for transmission. Shell package will encode this and frame it while sending it out via console. Arguments Arguments Description m os_mbuf containing the message Returned values Returns 0 on success. Example static int nmgr_shell_out(struct nmgr_transport *nt, struct os_mbuf *m) { int rc; rc = shell_nlip_output(m); if (rc != 0) { goto err; } return (0); err: return (rc); }","title":"shell_nlip_output"},{"location":"os/modules/shell/shell_nlip_output/#shell_nlip_output","text":"int shell_nlip_output(struct os_mbuf *m) Queue outgoing newtmgr message for transmission. Shell package will encode this and frame it while sending it out via console.","title":" shell_nlip_output "},{"location":"os/modules/shell/shell_nlip_output/#arguments","text":"Arguments Description m os_mbuf containing the message","title":"Arguments"},{"location":"os/modules/shell/shell_nlip_output/#returned-values","text":"Returns 0 on success.","title":"Returned values"},{"location":"os/modules/shell/shell_nlip_output/#example","text":"static int nmgr_shell_out(struct nmgr_transport *nt, struct os_mbuf *m) { int rc; rc = shell_nlip_output(m); if (rc != 0) { goto err; } return (0); err: return (rc); }","title":"Example"},{"location":"os/modules/shell/shell_task_init/","text":"shell_task_init int shell_task_init(uint8_t prio, os_stack_t *stack, uint16_t stack_size, int max_input_length); Initializes the shell package. This creates a task for shell, and registers few commands on its own ( echo , ? , for example). It also allocates memory for buffering console input. Arguments Arguments Description prio Priority of the shell task stack Pointer to shell tasks's stack stack_size Size of the aforementioned stack (in units of os_stack_t) max_input_length the maximum expected length of line for input Returned values Returns 0 on success; nonzero on failure. Notes You can register commands before calling this, but only if OS has not been started. Example Here's an example of stand-alone code which allows the user to execute regression tests for sys/config package only. #define SHELL_TASK_PRIO (3) #define SHELL_MAX_INPUT_LEN (256) #define SHELL_TASK_STACK_SIZE (OS_STACK_ALIGN(384)) os_stack_t shell_stack[SHELL_TASK_STACK_SIZE]; int main(int argc, char **argv) { .... shell_task_init(SHELL_TASK_PRIO, shell_stack, SHELL_TASK_STACK_SIZE, SHELL_MAX_INPUT_LEN); .... }","title":"shell_task_init"},{"location":"os/modules/shell/shell_task_init/#shell_task_init","text":"int shell_task_init(uint8_t prio, os_stack_t *stack, uint16_t stack_size, int max_input_length); Initializes the shell package. This creates a task for shell, and registers few commands on its own ( echo , ? , for example). It also allocates memory for buffering console input.","title":" shell_task_init"},{"location":"os/modules/shell/shell_task_init/#arguments","text":"Arguments Description prio Priority of the shell task stack Pointer to shell tasks's stack stack_size Size of the aforementioned stack (in units of os_stack_t) max_input_length the maximum expected length of line for input","title":"Arguments"},{"location":"os/modules/shell/shell_task_init/#returned-values","text":"Returns 0 on success; nonzero on failure.","title":"Returned values"},{"location":"os/modules/shell/shell_task_init/#notes","text":"You can register commands before calling this, but only if OS has not been started.","title":"Notes"},{"location":"os/modules/shell/shell_task_init/#example","text":"Here's an example of stand-alone code which allows the user to execute regression tests for sys/config package only. #define SHELL_TASK_PRIO (3) #define SHELL_MAX_INPUT_LEN (256) #define SHELL_TASK_STACK_SIZE (OS_STACK_ALIGN(384)) os_stack_t shell_stack[SHELL_TASK_STACK_SIZE]; int main(int argc, char **argv) { .... shell_task_init(SHELL_TASK_PRIO, shell_stack, SHELL_TASK_STACK_SIZE, SHELL_MAX_INPUT_LEN); .... }","title":"Example"},{"location":"os/modules/stats/stats/","text":"Statistics Module The statistics module allows application, libraries, or drivers to record statistics that can be shown via the Newtmgr tool and console. This allows easy integration of statistics for troubleshooting, maintenance, and usage monitoring. By creating and registering your statistics, they are automatically included in the Newtmgr shell and console APIs. Implementation Details A statistic is an unsigned integer that can be set by the code. When building stats, the implementer chooses the size of the statistic depending on the frequency of the statistic and the resolution required before the counter wraps. Typically the stats are incremented upon code events; however, they are not limted to that purpose. Stats are organized into sections. Each section of stats has its own name and can be queried separately through the API. Each section of stats also has its own statistic size, allowing the user to separate large (64-bit) statistics from small (16 bit statistics). NOTE: It is not currently possible to group different size stats into the same section. Please ensure all stats in a section have the same size. Stats sections are currently stored in a single global stats group. Statistics are stored in a simple structure which contains a small stats header followed by a list of stats. The stats header contains: struct stats_hdr { char *s_name ; uint8_t s_size ; uint8_t s_cnt ; uint16_t s_pad1 ; #ifdef STATS_NAME_ENABLE struct stats_name_map *s_map ; int s_map_cnt ; #endif STAILQ_ENTRY ( stats_hdr ) s_next ; }; Compile Time Options When building your app, there is a single compile time option for statistics. When querying statistics, they are always queried by number, but if you want to see the results by name, you need to define STATS_NAME_ENABLE . This is defined using pkg.clfags: -DSTATS_NAME_ENABLE in your apps pkg.yml file or target.clfags: -DSTATS_NAME_ENABLE in your target definition. Enabling stat names provides better descriptions in the reported stats, but takes code space to store the strings within the image. Adding Stats to your code. Creating new stats table requires the following steps. Include the stats header file Define a stats section Declare an instance of the section Define the stat sections names table Implement stat in your code Initialize the stats Register the stats Include the stats header file Add the stats library to your pkg.yml file for your package or app by adding this line to your package dependencies. pkg.deps: - \"@apache-mynewt-core/sys/stats\" Add this include directive to code files using the stats library. #include <stats/stats.h> Define a stats section You must use the stats.h macros to define your stats table. A stats section definition looks like this. STATS_SECT_START(my_stat_section) STATS_SECT_ENTRY(attempt_stat) STATS_SECT_ENTRY(error_stat) STATS_SECT_END In this case we chose to make the stats 32-bits each. stats.h supports three different stats sizes through the following macros: STATS_SIZE_16 -- stats are 16 bits (wraps at 65536) STATS_SIZE_32 -- stats are 32 bits (wraps at 4294967296) STATS_SIZE_64 -- stats are 64-bits When this compiles/pre-processes, it produces a structure definition like this struct stats_my_stat_section { struct stats_hdr s_hdr; uint32_t sattempt_stat; uint32_t serror_stat; }; You can see that the defined structure has a small stats structure header and the two stats we have defined. Depending on whether these stats are used in multiple modules, you may need to include this definition in a header file. Declaring a variable to hold the stats Declare the global variable to hold your statistics. Since it is possible to have multiple copies of the same section (for example a stat section for each of 5 identical peripherals), the variable name of the stats section must be unique. STATS_SECT_DECL(my_stat_section) g_mystat; Again, if your stats section is used in multiple C files you will need to include the above definition in one of the C files and 'extern' this declaration in your header file. extern STATS_SECT_DECL(my_stat_section) g_mystat; Define the stats section name table Whether or not you are using STATS_NAME_ENABLE , you must define a stats name table. If STATS_NAME_ENABLE is not enabled, this will not take any code space or image size. /* define a few stats for querying */ STATS_NAME_START(my_stat_section) STATS_NAME(my_stat_section, attempt_stat) STATS_NAME(my_stat_section, error_stat) STATS_NAME_END(my_stat_section) When compiled by the preprocessor, it creates a structure that looks like this. struct stats_name_map g_stats_map_my_stat_section[] = { { __builtin_offsetof (struct stats_my_stat_section, sattempt_stat), \"attempt_stat\" }, { __builtin_offsetof (struct stats_my_stat_section, serror_stat), \"error_stat\" }, }; This table will allow the UI components to find a nice string name for the stat. Implement stats in your code. You can use the STATS_INC or STATS_INCN macros to increment your statistics within your C-code. For example, your code may do this: STATS_INC(g_mystat, attempt_stat); rc = do_task(); if(rc == ERR) { STATS_INC(g_mystat, error_stat); } Initialize the statistics You must initialize the stats so they can be operated on by the stats library. As per our example above, it would look like the following. This tells the system how large each statistic is and the number of statistics in the section. It also initialize the name information for the statistics if enabled as shown above. rc = stats_init( STATS_HDR(g_mystat), STATS_SIZE_INIT_PARMS(g_mystat, STATS_SIZE_32), STATS_NAME_INIT_PARMS(my_stat_section)); assert(rc == 0); Register the statistic section If you want the system to know about your stats, you must register them. rc = stats_register(\"my_stats\", STATS_HDR(g_mystat)); assert(rc == 0); There is also a method that does initialization and registration at the same time, called stats_init_and_reg . Retrieving stats through console or Newtmgr If you enable console in your project you can see stats through the serial port defined. This is the stats as shown from the example above with names enabled. stat my_stats 12274:attempt_stat: 3 12275:error_stat: 0 This is the stats as shown from the example without names enabled. stat my_stats 29149:s0: 3 29150:s1: 0 A note on multiple stats sections If you are implementing a device with multiple instances, you may want multiple stats sections with the exact same format. For example, suppose I write a driver for an external distance sensor. My driver supports up to 5 sensors and I want to record the stats of each device separately. This works identically to the example above, except you would need to register each one separately with a unique name. The stats system will not let two sections be entered with the same name.","title":"toc"},{"location":"os/modules/stats/stats/#statistics-module","text":"The statistics module allows application, libraries, or drivers to record statistics that can be shown via the Newtmgr tool and console. This allows easy integration of statistics for troubleshooting, maintenance, and usage monitoring. By creating and registering your statistics, they are automatically included in the Newtmgr shell and console APIs.","title":"Statistics Module"},{"location":"os/modules/stats/stats/#implementation-details","text":"A statistic is an unsigned integer that can be set by the code. When building stats, the implementer chooses the size of the statistic depending on the frequency of the statistic and the resolution required before the counter wraps. Typically the stats are incremented upon code events; however, they are not limted to that purpose. Stats are organized into sections. Each section of stats has its own name and can be queried separately through the API. Each section of stats also has its own statistic size, allowing the user to separate large (64-bit) statistics from small (16 bit statistics). NOTE: It is not currently possible to group different size stats into the same section. Please ensure all stats in a section have the same size. Stats sections are currently stored in a single global stats group. Statistics are stored in a simple structure which contains a small stats header followed by a list of stats. The stats header contains: struct stats_hdr { char *s_name ; uint8_t s_size ; uint8_t s_cnt ; uint16_t s_pad1 ; #ifdef STATS_NAME_ENABLE struct stats_name_map *s_map ; int s_map_cnt ; #endif STAILQ_ENTRY ( stats_hdr ) s_next ; };","title":"Implementation Details"},{"location":"os/modules/stats/stats/#compile-time-options","text":"When building your app, there is a single compile time option for statistics. When querying statistics, they are always queried by number, but if you want to see the results by name, you need to define STATS_NAME_ENABLE . This is defined using pkg.clfags: -DSTATS_NAME_ENABLE in your apps pkg.yml file or target.clfags: -DSTATS_NAME_ENABLE in your target definition. Enabling stat names provides better descriptions in the reported stats, but takes code space to store the strings within the image.","title":"Compile Time Options"},{"location":"os/modules/stats/stats/#adding-stats-to-your-code","text":"Creating new stats table requires the following steps. Include the stats header file Define a stats section Declare an instance of the section Define the stat sections names table Implement stat in your code Initialize the stats Register the stats","title":"Adding Stats to your code."},{"location":"os/modules/stats/stats/#include-the-stats-header-file","text":"Add the stats library to your pkg.yml file for your package or app by adding this line to your package dependencies. pkg.deps: - \"@apache-mynewt-core/sys/stats\" Add this include directive to code files using the stats library. #include <stats/stats.h>","title":"Include the stats header file"},{"location":"os/modules/stats/stats/#define-a-stats-section","text":"You must use the stats.h macros to define your stats table. A stats section definition looks like this. STATS_SECT_START(my_stat_section) STATS_SECT_ENTRY(attempt_stat) STATS_SECT_ENTRY(error_stat) STATS_SECT_END In this case we chose to make the stats 32-bits each. stats.h supports three different stats sizes through the following macros: STATS_SIZE_16 -- stats are 16 bits (wraps at 65536) STATS_SIZE_32 -- stats are 32 bits (wraps at 4294967296) STATS_SIZE_64 -- stats are 64-bits When this compiles/pre-processes, it produces a structure definition like this struct stats_my_stat_section { struct stats_hdr s_hdr; uint32_t sattempt_stat; uint32_t serror_stat; }; You can see that the defined structure has a small stats structure header and the two stats we have defined. Depending on whether these stats are used in multiple modules, you may need to include this definition in a header file.","title":"Define a stats section"},{"location":"os/modules/stats/stats/#declaring-a-variable-to-hold-the-stats","text":"Declare the global variable to hold your statistics. Since it is possible to have multiple copies of the same section (for example a stat section for each of 5 identical peripherals), the variable name of the stats section must be unique. STATS_SECT_DECL(my_stat_section) g_mystat; Again, if your stats section is used in multiple C files you will need to include the above definition in one of the C files and 'extern' this declaration in your header file. extern STATS_SECT_DECL(my_stat_section) g_mystat;","title":"Declaring a variable to hold the stats"},{"location":"os/modules/stats/stats/#define-the-stats-section-name-table","text":"Whether or not you are using STATS_NAME_ENABLE , you must define a stats name table. If STATS_NAME_ENABLE is not enabled, this will not take any code space or image size. /* define a few stats for querying */ STATS_NAME_START(my_stat_section) STATS_NAME(my_stat_section, attempt_stat) STATS_NAME(my_stat_section, error_stat) STATS_NAME_END(my_stat_section) When compiled by the preprocessor, it creates a structure that looks like this. struct stats_name_map g_stats_map_my_stat_section[] = { { __builtin_offsetof (struct stats_my_stat_section, sattempt_stat), \"attempt_stat\" }, { __builtin_offsetof (struct stats_my_stat_section, serror_stat), \"error_stat\" }, }; This table will allow the UI components to find a nice string name for the stat.","title":"Define the stats section name table"},{"location":"os/modules/stats/stats/#implement-stats-in-your-code","text":"You can use the STATS_INC or STATS_INCN macros to increment your statistics within your C-code. For example, your code may do this: STATS_INC(g_mystat, attempt_stat); rc = do_task(); if(rc == ERR) { STATS_INC(g_mystat, error_stat); }","title":"Implement stats in your code."},{"location":"os/modules/stats/stats/#initialize-the-statistics","text":"You must initialize the stats so they can be operated on by the stats library. As per our example above, it would look like the following. This tells the system how large each statistic is and the number of statistics in the section. It also initialize the name information for the statistics if enabled as shown above. rc = stats_init( STATS_HDR(g_mystat), STATS_SIZE_INIT_PARMS(g_mystat, STATS_SIZE_32), STATS_NAME_INIT_PARMS(my_stat_section)); assert(rc == 0);","title":"Initialize the statistics"},{"location":"os/modules/stats/stats/#register-the-statistic-section","text":"If you want the system to know about your stats, you must register them. rc = stats_register(\"my_stats\", STATS_HDR(g_mystat)); assert(rc == 0); There is also a method that does initialization and registration at the same time, called stats_init_and_reg .","title":"Register the statistic section"},{"location":"os/modules/stats/stats/#retrieving-stats-through-console-or-newtmgr","text":"If you enable console in your project you can see stats through the serial port defined. This is the stats as shown from the example above with names enabled. stat my_stats 12274:attempt_stat: 3 12275:error_stat: 0 This is the stats as shown from the example without names enabled. stat my_stats 29149:s0: 3 29150:s1: 0","title":"Retrieving stats through console or Newtmgr"},{"location":"os/modules/stats/stats/#a-note-on-multiple-stats-sections","text":"If you are implementing a device with multiple instances, you may want multiple stats sections with the exact same format. For example, suppose I write a driver for an external distance sensor. My driver supports up to 5 sensors and I want to record the stats of each device separately. This works identically to the example above, except you would need to register each one separately with a unique name. The stats system will not let two sections be entered with the same name.","title":"A note on multiple stats sections"},{"location":"os/modules/testutil/test_assert/","text":"TEST_ASSERT TEST_ASSERT(expression, fail_msg, ...) TEST_ASSERT_FATAL(expression, fail_msg, ...) Asserts that the specified condition is true. If the expression is true, nothing gets reported. fail_msg will be printed out if the expression is false. The expression argument is mandatory; the rest are optional. The fail_msg argument is a printf format string which specifies how the remaining arguments are parsed. TEST_ASSERT_FATAL() causes the current test case to be aborted, if expression fails. Arguments Arguments Description expression Condition being tested. If it fails, test is considered a failure, and a message is printed out. fail_msg Pointer to C string that contains a format string that follows the same specifications as format in printf. ... Depending on the format string, the function may expect either a sequence of additional arguments to be used to replace a format specifier in the format string or a variable arguments list. va_list is a special type defined in in stdarg.h. Returned values None Notes While console_printf , with its well understood formatting options in C, is more convenient and easy on the eyes than the raw output of console_write , the associated code size is considerably larger. Example Example #1: TEST_CASE(config_test_insert) { int rc; rc = conf_register(&config_test_handler); TEST_ASSERT(rc == 0); } Example #2: TEST_CASE(nffs_test_unlink) { int rc; .... rc = nffs_format(nffs_area_descs); TEST_ASSERT_FATAL(rc == 0); .... } Example #3: static int cbmem_test_case_1_walk(struct cbmem *cbmem, struct cbmem_entry_hdr *hdr, void *arg) { .... rc = cbmem_read(cbmem, hdr, &actual, 0, sizeof(actual)); TEST_ASSERT_FATAL(rc == 1, \"Couldn't read 1 byte from cbmem\"); TEST_ASSERT_FATAL(actual == expected, \"Actual doesn't equal expected (%d = %d)\", actual, expected); .... }","title":"TEST_ASSERT"},{"location":"os/modules/testutil/test_assert/#test_assert","text":"TEST_ASSERT(expression, fail_msg, ...) TEST_ASSERT_FATAL(expression, fail_msg, ...) Asserts that the specified condition is true. If the expression is true, nothing gets reported. fail_msg will be printed out if the expression is false. The expression argument is mandatory; the rest are optional. The fail_msg argument is a printf format string which specifies how the remaining arguments are parsed. TEST_ASSERT_FATAL() causes the current test case to be aborted, if expression fails.","title":" TEST_ASSERT"},{"location":"os/modules/testutil/test_assert/#arguments","text":"Arguments Description expression Condition being tested. If it fails, test is considered a failure, and a message is printed out. fail_msg Pointer to C string that contains a format string that follows the same specifications as format in printf. ... Depending on the format string, the function may expect either a sequence of additional arguments to be used to replace a format specifier in the format string or a variable arguments list. va_list is a special type defined in in stdarg.h.","title":"Arguments"},{"location":"os/modules/testutil/test_assert/#returned-values","text":"None","title":"Returned values"},{"location":"os/modules/testutil/test_assert/#notes","text":"While console_printf , with its well understood formatting options in C, is more convenient and easy on the eyes than the raw output of console_write , the associated code size is considerably larger.","title":"Notes"},{"location":"os/modules/testutil/test_assert/#example","text":"Example #1: TEST_CASE(config_test_insert) { int rc; rc = conf_register(&config_test_handler); TEST_ASSERT(rc == 0); } Example #2: TEST_CASE(nffs_test_unlink) { int rc; .... rc = nffs_format(nffs_area_descs); TEST_ASSERT_FATAL(rc == 0); .... } Example #3: static int cbmem_test_case_1_walk(struct cbmem *cbmem, struct cbmem_entry_hdr *hdr, void *arg) { .... rc = cbmem_read(cbmem, hdr, &actual, 0, sizeof(actual)); TEST_ASSERT_FATAL(rc == 1, \"Couldn't read 1 byte from cbmem\"); TEST_ASSERT_FATAL(actual == expected, \"Actual doesn't equal expected (%d = %d)\", actual, expected); .... }","title":"Example"},{"location":"os/modules/testutil/test_case/","text":"TEST_CASE TEST_CASE(test_case_name) Defines a test case function with the following type int test_case_name(void) . This can then be called from regression test's TEST_SUITE() function. Arguments Arguments Description test_case_name Used as the function name for this test case. Returned values Return value is 0 if the test case passed; nonzero if it failed. Generally, the return code is not used. It is expected that the case will pass/fail with tests done using TEST_ASSERT() . Example TEST_CASE(config_test_insert) { .... }","title":"TEST_CASE"},{"location":"os/modules/testutil/test_case/#test_case","text":"TEST_CASE(test_case_name) Defines a test case function with the following type int test_case_name(void) . This can then be called from regression test's TEST_SUITE() function.","title":" TEST_CASE "},{"location":"os/modules/testutil/test_case/#arguments","text":"Arguments Description test_case_name Used as the function name for this test case.","title":"Arguments"},{"location":"os/modules/testutil/test_case/#returned-values","text":"Return value is 0 if the test case passed; nonzero if it failed. Generally, the return code is not used. It is expected that the case will pass/fail with tests done using TEST_ASSERT() .","title":"Returned values"},{"location":"os/modules/testutil/test_case/#example","text":"TEST_CASE(config_test_insert) { .... }","title":"Example"},{"location":"os/modules/testutil/test_decl/","text":"TEST_CASE_DECL TEST_CASE_DECL(test_case_name) Declares a test case function with the following type int test_case_name(void) . This can then be called from regression test's TEST_SUITE() function. This is only required if the test case function exists in a different file than the test suite. This will allow the test suite to find the test case Arguments Arguments Description test_case_name Used as the function name for this test case. Returned values Return value is 0 if the test case passed; nonzero if it failed. Generally, the return code is not used. It is expected that the case will pass/fail with tests done using TEST_ASSERT() . Example file test_cases.h TEST_CASE_DECL(test_case_1) TEST_CASE_DECL(test_case_2) TEST_CASE_DECL(test_case_3)","title":"TEST_CASE_DECL"},{"location":"os/modules/testutil/test_decl/#test_case_decl","text":"TEST_CASE_DECL(test_case_name) Declares a test case function with the following type int test_case_name(void) . This can then be called from regression test's TEST_SUITE() function. This is only required if the test case function exists in a different file than the test suite. This will allow the test suite to find the test case","title":" TEST_CASE_DECL "},{"location":"os/modules/testutil/test_decl/#arguments","text":"Arguments Description test_case_name Used as the function name for this test case.","title":"Arguments"},{"location":"os/modules/testutil/test_decl/#returned-values","text":"Return value is 0 if the test case passed; nonzero if it failed. Generally, the return code is not used. It is expected that the case will pass/fail with tests done using TEST_ASSERT() .","title":"Returned values"},{"location":"os/modules/testutil/test_decl/#example-file-test_casesh","text":"TEST_CASE_DECL(test_case_1) TEST_CASE_DECL(test_case_2) TEST_CASE_DECL(test_case_3)","title":"Example file test_cases.h"},{"location":"os/modules/testutil/test_pass/","text":"TEST_PASS TEST_PASS(msg, ...) Reports a success result for the current test. This function is not normally needed, as all successful tests automatically write an empty pass result at completion. It is only needed when the success result report should contain text. The msg argument is a printf format string which specifies how the remaining arguments are parsed. The result file produced by this function contains the following text: |<file>:<line-number>| manual pass <msg> Arguments Arguments Description msg This is a printf format string which specifies how the remaining arguments are parsed ... Depending on the format string, the function may expect either a sequence of additional arguments to be used to replace a format specifier in the format string or a variable arguments list. va_list is a special type defined in in stdarg.h. Returned values None Notes After this function is called, the remainder of the test case is not executed.","title":"TEST_PASS"},{"location":"os/modules/testutil/test_pass/#test_pass","text":"TEST_PASS(msg, ...) Reports a success result for the current test. This function is not normally needed, as all successful tests automatically write an empty pass result at completion. It is only needed when the success result report should contain text. The msg argument is a printf format string which specifies how the remaining arguments are parsed. The result file produced by this function contains the following text: |<file>:<line-number>| manual pass <msg>","title":" TEST_PASS "},{"location":"os/modules/testutil/test_pass/#arguments","text":"Arguments Description msg This is a printf format string which specifies how the remaining arguments are parsed ... Depending on the format string, the function may expect either a sequence of additional arguments to be used to replace a format specifier in the format string or a variable arguments list. va_list is a special type defined in in stdarg.h.","title":"Arguments"},{"location":"os/modules/testutil/test_pass/#returned-values","text":"None","title":"Returned values"},{"location":"os/modules/testutil/test_pass/#notes","text":"After this function is called, the remainder of the test case is not executed.","title":"Notes"},{"location":"os/modules/testutil/test_suite/","text":"TEST_SUITE TEST_SUITE(test_suite_name) Declares a test suite function with the following type int test_suite_name(void) . This can then be called from either project/test , or from main routine for package specific regression test. Arguments Arguments Description test_suite_name Used as the function name for this test suite. Returned values Return value is 0 if the test suite passed; nonzero if it failed. Generally, the return code is not used. It is expected that the individual test cases will pass/fail with tests done using TEST_ASSERT() . Example TEST_SUITE(os_sem_test_suite) { os_sem_test_basic(); os_sem_test_case_1(); os_sem_test_case_2(); os_sem_test_case_3(); os_sem_test_case_4(); }","title":"TEST_SUITE"},{"location":"os/modules/testutil/test_suite/#test_suite","text":"TEST_SUITE(test_suite_name) Declares a test suite function with the following type int test_suite_name(void) . This can then be called from either project/test , or from main routine for package specific regression test.","title":" TEST_SUITE "},{"location":"os/modules/testutil/test_suite/#arguments","text":"Arguments Description test_suite_name Used as the function name for this test suite.","title":"Arguments"},{"location":"os/modules/testutil/test_suite/#returned-values","text":"Return value is 0 if the test suite passed; nonzero if it failed. Generally, the return code is not used. It is expected that the individual test cases will pass/fail with tests done using TEST_ASSERT() .","title":"Returned values"},{"location":"os/modules/testutil/test_suite/#example","text":"TEST_SUITE(os_sem_test_suite) { os_sem_test_basic(); os_sem_test_case_1(); os_sem_test_case_2(); os_sem_test_case_3(); os_sem_test_case_4(); }","title":"Example"},{"location":"os/modules/testutil/testutil/","text":"testutil The testutil package is a test framework that provides facilities for specifying test cases and recording test results. You would use it to build regression tests for your library. Description A package may optionally contain a set of test cases. Test cases are not normally compiled and linked when a package is built; they are only included when the \"test\" identity is specified. All of a package's test code goes in its src/test directory. For example, the nffs package's test code is located in the following directory: * fs/nffs/src/test/ This directory contains the source and header files that implement the nffs test code. The test code has access to all the header files in the following directories: * src * src/arch/<target-arch> * include * src/test * src/test/arch/<target-arch> * include directories of all package dependencies Package test code typically depends on the testutil package, described later in this document. Some test cases or test initialization code may be platform-specific. In such cases, the platform-specific function definitions are placed in arch subdirectories within the package test directory. While building the test code (i.e., when the test identity is specified), the newt tool defines the TEST macro. This macro is defined during compilation of all C source files in all projects and packages. Tests are structured according to the following hierarchy: [test] / \\ [suite] [suite] / \\ / \\ [case] [case] [case] [case] I.e., a test consists of test suites, and a test suite consists of test cases. The test code uses testutil to define test suites and test cases. Regression test can then be executed using 'newt target test' command, or by including a call to your test suite from project/test/src/test.c . Example This Tutorial shows how to create a test suite for a Mynewt package. Data structures struct tu_config { int tc_print_results; int tc_system_assert; tu_case_init_fn_t *tc_case_init_cb; void *tc_case_init_arg; tu_case_report_fn_t *tc_case_fail_cb; void *tc_case_fail_arg; tu_case_report_fn_t *tc_case_pass_cb; void *tc_case_pass_arg; tu_suite_init_fn_t *tc_suite_init_cb; void *tc_suite_init_arg; tu_restart_fn_t *tc_restart_cb; void *tc_restart_arg; }; extern struct tu_config tu_config; The global tu_config struct contains all the testutil package's settings. This should be populated before tu_init() is called. List of Functions The functions, and macros available in testutil are: Function Description tu_init Initializes the test framework according to the contents of the tu_config struct. TEST_ASSERT Asserts that the specified condition is true. TEST_PASS Reports a success result for the current test. TEST_SUITE Declares a test suite function. TEST_CASE Defines a test case function. TEST_CASE_DECL Declares a test case function. his is only required if the test case function exists in a different file than the test suite. tu_restart This function is used when a system reset is necessary to proceed with testing.","title":"toc"},{"location":"os/modules/testutil/testutil/#testutil","text":"The testutil package is a test framework that provides facilities for specifying test cases and recording test results. You would use it to build regression tests for your library.","title":"testutil"},{"location":"os/modules/testutil/testutil/#description","text":"A package may optionally contain a set of test cases. Test cases are not normally compiled and linked when a package is built; they are only included when the \"test\" identity is specified. All of a package's test code goes in its src/test directory. For example, the nffs package's test code is located in the following directory: * fs/nffs/src/test/ This directory contains the source and header files that implement the nffs test code. The test code has access to all the header files in the following directories: * src * src/arch/<target-arch> * include * src/test * src/test/arch/<target-arch> * include directories of all package dependencies Package test code typically depends on the testutil package, described later in this document. Some test cases or test initialization code may be platform-specific. In such cases, the platform-specific function definitions are placed in arch subdirectories within the package test directory. While building the test code (i.e., when the test identity is specified), the newt tool defines the TEST macro. This macro is defined during compilation of all C source files in all projects and packages. Tests are structured according to the following hierarchy: [test] / \\ [suite] [suite] / \\ / \\ [case] [case] [case] [case] I.e., a test consists of test suites, and a test suite consists of test cases. The test code uses testutil to define test suites and test cases. Regression test can then be executed using 'newt target test' command, or by including a call to your test suite from project/test/src/test.c .","title":"Description"},{"location":"os/modules/testutil/testutil/#example","text":"This Tutorial shows how to create a test suite for a Mynewt package.","title":"Example"},{"location":"os/modules/testutil/testutil/#data-structures","text":"struct tu_config { int tc_print_results; int tc_system_assert; tu_case_init_fn_t *tc_case_init_cb; void *tc_case_init_arg; tu_case_report_fn_t *tc_case_fail_cb; void *tc_case_fail_arg; tu_case_report_fn_t *tc_case_pass_cb; void *tc_case_pass_arg; tu_suite_init_fn_t *tc_suite_init_cb; void *tc_suite_init_arg; tu_restart_fn_t *tc_restart_cb; void *tc_restart_arg; }; extern struct tu_config tu_config; The global tu_config struct contains all the testutil package's settings. This should be populated before tu_init() is called.","title":"Data structures"},{"location":"os/modules/testutil/testutil/#list-of-functions","text":"The functions, and macros available in testutil are: Function Description tu_init Initializes the test framework according to the contents of the tu_config struct. TEST_ASSERT Asserts that the specified condition is true. TEST_PASS Reports a success result for the current test. TEST_SUITE Declares a test suite function. TEST_CASE Defines a test case function. TEST_CASE_DECL Declares a test case function. his is only required if the test case function exists in a different file than the test suite. tu_restart This function is used when a system reset is necessary to proceed with testing.","title":"List of Functions"},{"location":"os/modules/testutil/tu_init/","text":"tu_init int tu_init(void) Initializes the test framework according to the contents of the tu_config struct. This function must be called before any tests are run. Arguments N/A Returned values Returns 0 on success; nonzero on failure. Example Here's an example of stand-alone code which allows the user to execute regression tests for sys/config package only. #ifdef PKG_TEST int main(int argc, char **argv) { tu_config.tc_print_results = 1; tu_init(); conf_init(); config_test_all(); return tu_any_failed; } #endif","title":"tu_init"},{"location":"os/modules/testutil/tu_init/#tu_init","text":"int tu_init(void) Initializes the test framework according to the contents of the tu_config struct. This function must be called before any tests are run.","title":" tu_init"},{"location":"os/modules/testutil/tu_init/#arguments","text":"N/A","title":"Arguments"},{"location":"os/modules/testutil/tu_init/#returned-values","text":"Returns 0 on success; nonzero on failure.","title":"Returned values"},{"location":"os/modules/testutil/tu_init/#example","text":"Here's an example of stand-alone code which allows the user to execute regression tests for sys/config package only. #ifdef PKG_TEST int main(int argc, char **argv) { tu_config.tc_print_results = 1; tu_init(); conf_init(); config_test_all(); return tu_any_failed; } #endif","title":"Example"},{"location":"os/modules/testutil/tu_restart/","text":"tu_restart void tu_restart(void) This function is used when a system reset is necessary to proceed with testing. For example, the OS is designed to run forever once started, so a test which creates several OS tasks and then starts the OS has no means of completing. This function, when called from such a test, gracefully ends the current test case and proceeds to the next test case. The particulars of this function depend on whether it is called from a simulated environment. In a simulated environment, this function uses a longjmp() call to break out of the current test case. Arguments N/A Returned values Returns 0 on success; nonzero on failure. Example void os_test_restart(void) { .... tu_restart(); } #endif","title":"tu_restart"},{"location":"os/modules/testutil/tu_restart/#tu_restart","text":"void tu_restart(void) This function is used when a system reset is necessary to proceed with testing. For example, the OS is designed to run forever once started, so a test which creates several OS tasks and then starts the OS has no means of completing. This function, when called from such a test, gracefully ends the current test case and proceeds to the next test case. The particulars of this function depend on whether it is called from a simulated environment. In a simulated environment, this function uses a longjmp() call to break out of the current test case.","title":" tu_restart "},{"location":"os/modules/testutil/tu_restart/#arguments","text":"N/A","title":"Arguments"},{"location":"os/modules/testutil/tu_restart/#returned-values","text":"Returns 0 on success; nonzero on failure.","title":"Returned values"},{"location":"os/modules/testutil/tu_restart/#example","text":"void os_test_restart(void) { .... tu_restart(); } #endif","title":"Example"},{"location":"os/tutorials/STM32F303/","text":"Blinky, your \"Hello World!\", on STM32F303 Discovery Objective Learn how to use packages from a default application repository of Mynewt to build your first Hello World application (Blinky) on a target board. Once built using the newt tool, this application will blink the LED lights on the target board. Create a project with a simple app that blinks an LED on the stmf303 discovery board. In the process import some external libraries into your project. Download the application to the target and watch it blink! What you need Discovery kit with STM32F303VC MCU Laptop running Mac OSX. It is assumed you have already installed newt tool. It is assumed you already installed native tools as described here Also, we assume that you're familiar with UNIX shells. Let's gets started! Create a project Create a new project to hold your work. For a deeper understanding, you can read about project creation in Get Started -- Creating Your First Project or just follow the commands below. If you've already created a project from another tutorial, you can re-use that project. $ mkdir ~/dev $ cd ~/dev $ newt new myproj Downloading project skeleton from apache/incubator-mynewt-blinky... Installing skeleton in myproj... Project myproj successfully created. $ cd myproj Note: Don't forget to change into the myproj directory. Import External STM32F3 Library support The STM32F303 support for Mynewt lives in an external repository. It's necessary to add another repository to the project. To do this, edit the file project.yml in the root directory of your project myproj This requires two changes to this file. You must define the properties of the external repository that you want to add You must include the repository in your project. Edit the file project.yml with your favorite editor and add the following repository details in the file (after the core repository). This gives newt the information to contact the repository and extract its contents. In this case, the repository is on github in the runtimeinc collection. Its name is mynewt-stm32f3 and we will accept any version up to the latest. You can look at the contents here . repository.mynewt_stm32f3: type: github vers: 0-latest user: runtimeinc repo: mynewt_stm32f3 In the same file, add the following highlighted line to the project.repositories variable. This tells newt to download the repository contents into your project. project.repositories: - apache-mynewt-core - mynewt_stm32f3 Install dependencies Now you can install this into the project using: $ newt install -v Downloading repository description for apache-mynewt-core... success! ... apache-mynewt-core successfully installed version 0.7.9-none ... Downloading repository description for mynewt_stm32f3... success! Downloading repository mynewt_stm32f3 ... Resolving deltas: 100% (65/65), done. Checking connectivity... done. mynewt_stm32f3 successfully installed version 0.0.0-none Create targets Create two targets to build using the stmf3 board support package and the app blinky example from mynewt. The output of these commands are not shown here for brevity. The first target is the application image itself. The second target is the bootloader which allows you to upgrade your mynewt applications. $ newt target create stmf3_blinky $ newt target set stmf3_blinky build_profile=optimized $ newt target set stmf3_blinky bsp=@mynewt_stm32f3/hw/bsp/stm32f3discovery $ newt target set stmf3_blinky app=apps/blinky $ newt target create stmf3_boot $ newt target set stmf3_boot app=@apache-mynewt-core/apps/boot $ newt target set stmf3_boot bsp=@mynewt_stm32f3/hw/bsp/stm32f3discovery $ newt target set stmf3_boot build_profile=optimized $ newt target show targets/stmf3_blinky app=apps/blinky bsp=@mynewt_stm32f3/hw/bsp/stm32f3discovery build_profile=optimized targets/stmf3_boot app=apps/boot bsp=@mynewt_stm32f3/hw/bsp/stm32f3discovery build_profile=optimized Build the target executables To build the images, use the newt build command below. $ newt build stmf3_blinky ... Archiving stm32f3discovery.a Linking blinky.elf App successfully built: ~/dev/myproj/bin/stmf3_blinky/apps/blinky/blinky.elf $ newt build stmf3_boot Compiling log_shell.c Archiving log.a Linking boot.elf App successfully built: ~/dev/myproj/bin/stmf3_boot/apps/boot/boot.elf Sign and create the blinky application image You must sign and version your application image to download it using newt. Use the newt create-image command to perform this action. Here we assign this image an arbitrary version 1.2.3 . $ newt create-image stmf3_blinky 1.2.3 App image successfully generated: ~/dev/myproj/bin/stmf3_blinky/apps/blinky/blinky.img Build manifest:~/dev/myproj/bin/stmf3_blinky/apps/blinky/manifest.json Configure the hardware The STM32F3DISCOVERY board includes an ST-LINK/V2 embedded debug tool interface that will be used to program/debug the board. To program the MCU on the board, simply plug in the two jumpers on CN4, as shown in the picture in red. If you want to learn more about the board you will find the User Manual at http://www.st.com/st-web-ui/static/active/jp/resource/technical/document/user_manual/DM00063382.pdf Download the Images Use the newt load command to download the images to the target board. $ newt -v load stmf3_boot $ newt -v load stmf3_blinky Watch the LED blink Congratulations! You have built, downloaded, and run your first application using mynewt for the stm32f3 discovery board. One of the LEDs on the LED wheel should be blinking at 1 Hz. Want more? Want to make your board do something a little more exciting with the LEDs? Then try making the modifications to the Blinky app to make it a pin-wheel app and you can light all the LEDs in a pin-wheel fashion. We have more fun tutorials for you to get your hands dirty. Be bold and try other Blinky-like tutorials or try enabling additional functionality such as remote comms on the current board. If you see anything missing or want to send us feedback, please do so by signing up for appropriate mailing lists on our Community Page . Keep on hacking and blinking!","title":"toc"},{"location":"os/tutorials/STM32F303/#blinky-your-hello-world-on-stm32f303-discovery","text":"","title":"Blinky, your \"Hello World!\", on STM32F303 Discovery"},{"location":"os/tutorials/STM32F303/#objective","text":"Learn how to use packages from a default application repository of Mynewt to build your first Hello World application (Blinky) on a target board. Once built using the newt tool, this application will blink the LED lights on the target board. Create a project with a simple app that blinks an LED on the stmf303 discovery board. In the process import some external libraries into your project. Download the application to the target and watch it blink!","title":"Objective"},{"location":"os/tutorials/STM32F303/#what-you-need","text":"Discovery kit with STM32F303VC MCU Laptop running Mac OSX. It is assumed you have already installed newt tool. It is assumed you already installed native tools as described here Also, we assume that you're familiar with UNIX shells. Let's gets started!","title":"What you need"},{"location":"os/tutorials/STM32F303/#create-a-project","text":"Create a new project to hold your work. For a deeper understanding, you can read about project creation in Get Started -- Creating Your First Project or just follow the commands below. If you've already created a project from another tutorial, you can re-use that project. $ mkdir ~/dev $ cd ~/dev $ newt new myproj Downloading project skeleton from apache/incubator-mynewt-blinky... Installing skeleton in myproj... Project myproj successfully created. $ cd myproj Note: Don't forget to change into the myproj directory.","title":"Create a project"},{"location":"os/tutorials/STM32F303/#import-external-stm32f3-library-support","text":"The STM32F303 support for Mynewt lives in an external repository. It's necessary to add another repository to the project. To do this, edit the file project.yml in the root directory of your project myproj This requires two changes to this file. You must define the properties of the external repository that you want to add You must include the repository in your project. Edit the file project.yml with your favorite editor and add the following repository details in the file (after the core repository). This gives newt the information to contact the repository and extract its contents. In this case, the repository is on github in the runtimeinc collection. Its name is mynewt-stm32f3 and we will accept any version up to the latest. You can look at the contents here . repository.mynewt_stm32f3: type: github vers: 0-latest user: runtimeinc repo: mynewt_stm32f3 In the same file, add the following highlighted line to the project.repositories variable. This tells newt to download the repository contents into your project. project.repositories: - apache-mynewt-core - mynewt_stm32f3","title":"Import External STM32F3 Library support"},{"location":"os/tutorials/STM32F303/#install-dependencies","text":"Now you can install this into the project using: $ newt install -v Downloading repository description for apache-mynewt-core... success! ... apache-mynewt-core successfully installed version 0.7.9-none ... Downloading repository description for mynewt_stm32f3... success! Downloading repository mynewt_stm32f3 ... Resolving deltas: 100% (65/65), done. Checking connectivity... done. mynewt_stm32f3 successfully installed version 0.0.0-none","title":"Install dependencies"},{"location":"os/tutorials/STM32F303/#create-targets","text":"Create two targets to build using the stmf3 board support package and the app blinky example from mynewt. The output of these commands are not shown here for brevity. The first target is the application image itself. The second target is the bootloader which allows you to upgrade your mynewt applications. $ newt target create stmf3_blinky $ newt target set stmf3_blinky build_profile=optimized $ newt target set stmf3_blinky bsp=@mynewt_stm32f3/hw/bsp/stm32f3discovery $ newt target set stmf3_blinky app=apps/blinky $ newt target create stmf3_boot $ newt target set stmf3_boot app=@apache-mynewt-core/apps/boot $ newt target set stmf3_boot bsp=@mynewt_stm32f3/hw/bsp/stm32f3discovery $ newt target set stmf3_boot build_profile=optimized $ newt target show targets/stmf3_blinky app=apps/blinky bsp=@mynewt_stm32f3/hw/bsp/stm32f3discovery build_profile=optimized targets/stmf3_boot app=apps/boot bsp=@mynewt_stm32f3/hw/bsp/stm32f3discovery build_profile=optimized","title":"Create targets"},{"location":"os/tutorials/STM32F303/#build-the-target-executables","text":"To build the images, use the newt build command below. $ newt build stmf3_blinky ... Archiving stm32f3discovery.a Linking blinky.elf App successfully built: ~/dev/myproj/bin/stmf3_blinky/apps/blinky/blinky.elf $ newt build stmf3_boot Compiling log_shell.c Archiving log.a Linking boot.elf App successfully built: ~/dev/myproj/bin/stmf3_boot/apps/boot/boot.elf","title":"Build the target executables"},{"location":"os/tutorials/STM32F303/#sign-and-create-the-blinky-application-image","text":"You must sign and version your application image to download it using newt. Use the newt create-image command to perform this action. Here we assign this image an arbitrary version 1.2.3 . $ newt create-image stmf3_blinky 1.2.3 App image successfully generated: ~/dev/myproj/bin/stmf3_blinky/apps/blinky/blinky.img Build manifest:~/dev/myproj/bin/stmf3_blinky/apps/blinky/manifest.json","title":"Sign and create the blinky application image"},{"location":"os/tutorials/STM32F303/#configure-the-hardware","text":"The STM32F3DISCOVERY board includes an ST-LINK/V2 embedded debug tool interface that will be used to program/debug the board. To program the MCU on the board, simply plug in the two jumpers on CN4, as shown in the picture in red. If you want to learn more about the board you will find the User Manual at http://www.st.com/st-web-ui/static/active/jp/resource/technical/document/user_manual/DM00063382.pdf","title":"Configure the hardware"},{"location":"os/tutorials/STM32F303/#download-the-images","text":"Use the newt load command to download the images to the target board. $ newt -v load stmf3_boot $ newt -v load stmf3_blinky","title":"Download the Images"},{"location":"os/tutorials/STM32F303/#watch-the-led-blink","text":"Congratulations! You have built, downloaded, and run your first application using mynewt for the stm32f3 discovery board. One of the LEDs on the LED wheel should be blinking at 1 Hz.","title":"Watch the LED blink"},{"location":"os/tutorials/STM32F303/#want-more","text":"Want to make your board do something a little more exciting with the LEDs? Then try making the modifications to the Blinky app to make it a pin-wheel app and you can light all the LEDs in a pin-wheel fashion. We have more fun tutorials for you to get your hands dirty. Be bold and try other Blinky-like tutorials or try enabling additional functionality such as remote comms on the current board. If you see anything missing or want to send us feedback, please do so by signing up for appropriate mailing lists on our Community Page . Keep on hacking and blinking!","title":"Want more?"},{"location":"os/tutorials/air_quality_sensor/","text":"Air quality sensor project Setting up source tree for stuff you need To start with, you need to create a new project under which you will do this development. So you type in: $ mkdir $HOME/src $ cd $HOME/src $ newt new air_quality Let's say you are using STM32F3discovery board as the platform. You know you need the board support package for that hardware. You can look up its location, add it your project, and fetch that along with the core OS components. To make this happen, you'll need to modify the project.yml in your project's root directory. [user@IsMyLaptop:~/src/air_quality]$ emacs project.yml & [user@IsMyLaptop:~/src/air_quality]$ cat project.yml project.name: \"air_quality\" project.repositories: - apache-mynewt-core - mynewt_stm32f3 # Use github's distribution mechanism for core ASF libraries. # This provides mirroring automatically for us. # repository.apache-mynewt-core: type: github vers: 0-latest user: apache repo: incubator-mynewt-core repository.mynewt_stm32f3: type: github vers: 0-latest user: runtimeinc repo: mynewt_stm32f3 [user@IsMyLaptop:~/src/air_quality]$ newt install apache-mynewt-core mynewt_stm32f3 [user@IsMyLaptop:~/src/air_quality]$ ls repos/ apache-mynewt-core mynewt_stm32f3 Good. You want to make sure you have all the needed bits for supporting your board; so you decide to build the blinky project for the platform first. Now create a target for it and build it. Easiest way to proceed is to copy the existing target for blinky, and modify it to build for STM32F3Discovery board. [user@IsMyLaptop:~/src/air_quality]$ newt target copy my_blinky_sim blink_f3 Target successfully copied; targets/my_blinky_sim --> targets/blink_f3 [user@IsMyLaptop:~/src/air_quality]$ newt target set blink_f3 bsp=@mynewt_stm32f3/hw/bsp/stm32f3discovery Target targets/blink_f3 successfully set target.bsp to @mynewt_stm32f3/hw/bsp/stm32f3discovery [user@IsMyLaptop:~/src/air_quality]$ newt build blink_f3 Compiling hal_bsp.c ... Linking blinky.elf App successfully built: /Users/user/src/air_quality/bin/blink_f3/apps/blinky/blinky.elf Good. You know that this platform uses bootloader, which means you have to create a target for that too. [user@IsMyLaptop:~/src/air_quality]$ newt target create boot_f3 Target targets/boot_f3 successfully created [user@IsMyLaptop:~/src/air_quality]$ newt target show @apache-mynewt-core/targets/unittest bsp=hw/bsp/native build_profile=debug compiler=compiler/sim targets/blink_f3 app=apps/blinky bsp=@mynewt_stm32f3/hw/bsp/stm32f3discovery build_profile=debug targets/boot_f3 targets/my_blinky_sim app=apps/blinky bsp=@apache-mynewt-core/hw/bsp/native build_profile=debug [user@IsMyLaptop:~/src/air_quality]$ newt target set boot_f3 bsp=@mynewt_stm32f3/hw/bsp/stm32f3discovery Target targets/boot_f3 successfully set target.bsp to @mynewt_stm32f3/hw/bsp/stm32f3discovery [user@IsMyLaptop:~/src/air_quality]$ newt target set boot_f3 app=@apache-mynewt-core/apps/boot Target targets/boot_f3 successfully set target.app to @apache-mynewt-core/apps/boot [user@IsMyLaptop:~/src/air_quality]$ newt target set boot_f3 build_profile=optimized Target targets/boot_f3 successfully set target.build_profile to optimized And then build it, and load it onto the board. newt build boot_f3 .... Linking boot.elf App successfully built: /Users/user/src/air_quality/bin/boot_f3/apps/boot/boot.elf [user@IsMyLaptop:~/src/air_quality] $ newt load boot_f3 Next you must download the targets to board, and see that the LED actually blinks. You plug in the STM32F3 discovery board to your laptop, and say: [user@IsMyLaptop:~/src/air_quality]$ newt load blink_f3 Downloading /Users/user/src/air_quality/bin/blink_f3/apps/blinky/blinky.img to 0x08009000 Open On-Chip Debugger 0.9.0 (2015-05-28-12:05) .... xPSR: 0x01000000 pc: 0x0800026c msp: 0x10002000 auto erase enabled Error: couldn't open /Users/user/src/air_quality/bin/blink_f3/apps/blinky/blinky.img Error: exit status 1 load - Load app image to target for <target-name>. Usage: newt load [flags] Examples: newt load <target-name> Global Flags: -l, --loglevel string Log level, defaults to WARN. (default \"WARN\") -o, --outfile string Filename to tee log output to -q, --quiet Be quiet; only display error output. -s, --silent Be silent; don't output anything. -v, --verbose Enable verbose output when executing commands. exit status 1 Ah. Forgot to create an image out of the blinky binary. Note that every time you want to build and load a new firmware image to target board, you need to run 'create-image' on it. [user@IsMyLaptop:~/src/air_quality]$ newt create-image blink_f3 0.0.1 App image successfully generated: /Users/user/src/air_quality/bin/blink_f3/apps/blinky/blinky.img Build manifest: /Users/user/src/air_quality/bin/blink_f3/apps/blinky/manifest.json [user@IsMyLaptop:~/src/air_quality]$ newt load blink_f3 0.0.1 And it's blinking. Shortcut for doing build/create-image/load/debug steps all in one is 'newt run' command. Check out the usage from command line help. Create test project Now that you have your system setup, you can start creating your own stuff. First you want to create a project for yourself - you can start by getting project template from blinky, as it pretty much has what you want. [user@IsMyLaptop:~/src/air_quality]$ mkdir apps/air_quality [user@IsMyLaptop:~/src/air_quality]$ cp repos/apache-mynewt-core/apps/blinky/pkg.yml apps/air_quality/ [user@IsMyLaptop:~/src/air_quality]$ mkdir apps/air_quality/src [user@IsMyLaptop:~/src/air_quality]$ cp repos/apache-mynewt-core/apps/blinky/src/main.c apps/air_quality/src/ Then you modify the apps/air_quality/pkg.yml for air_quality in order to change the pkg.name to be apps/air_quality . You also need to point the package dependencies to point to packages in apache-mynewt-core repository. STM32F3discovery board has limited amount of memory, so you must also switch your libc to be baselibc, instead of the standard one. [user@IsMyLaptop:~/src/air_quality]$ cat apps/air_quality/pkg.yml pkg.name: apps/air_quality pkg.type: app pkg.description: Air quality sensor test pkg.keywords: pkg.deps: - \"@apache-mynewt-core/libs/console/full\" - \"@apache-mynewt-core/libs/newtmgr\" - \"@apache-mynewt-core/libs/os\" - \"@apache-mynewt-core/libs/shell\" - \"@apache-mynewt-core/sys/config\" - \"@apache-mynewt-core/sys/log\" - \"@apache-mynewt-core/sys/stats\" - \"@apache-mynewt-core/libs/baselibc\" And create a target for it: [user@IsMyLaptop:~/src/air_quality]$ newt target create air_q Target targets/air_q successfully created [user@IsMyLaptop:~/src/air_quality]$ newt target set air_q bsp=@mynewt_stm32f3/hw/bsp/stm32f3discovery Target targets/air_q successfully set target.bsp to @mynewt_stm32f3/hw/bsp/stm32f3discovery [user@IsMyLaptop:~/src/air_quality]$ newt target set air_q app=apps/air_quality Target targets/air_q successfully set target.app to apps/air_quality [user@IsMyLaptop:~/src/air_quality]$ newt target set air_q build_profile=debug Target targets/air_q successfully set target.build_profile to debug [user@IsMyLaptop:~/src/air_quality]$ newt build air_q .... Linking air_quality.elf App successfully built: /Users/user/src/air_quality/bin/air_q/apps/air_quality/air_quality.elf Create packages for drivers One of the sensors you want to enable is SenseAir K30, which will connect to the board over serial port. To start development of the driver, you first need to create a package description for it, and add stubs for sources. So you add few files. pkg.yml to describe the driver, and then header stub followed by source stub. [user@IsMyLaptop:~/src/air_quality]$ cat libs/my_drivers/senseair/pkg.yml # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # \"License\"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http: //www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # pkg . name: libs/my_drivers/senseair pkg . deps: - \"@apache-mynewt-core/hw/hal\" [user@IsMyLaptop:~/src/air_quality]$ cat libs/my_drivers/senseair/include/senseair/senseair.h /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * \"License\"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef _SENSEAIR_H_ #define _SENSEAIR_H_ void senseair_init ( void ); #endif /* _SENSEAIR_H_ */ [user@IsMyLaptop:~/src/air_quality]$ cat libs/my_drivers/senseair/src/senseair.c /** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * \"License\"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ void senseair_init ( void ) { } And add dependency to this package in my project yml file. Here's from apps/air_quality/pkg.yml pkg.name: apps/air_quality pkg.type: app pkg.description: Air quality sensor test pkg.keywords: pkg.deps: - \"@apache-mynewt-core/libs/console/full\" - \"@apache-mynewt-core/libs/newtmgr\" - \"@apache-mynewt-core/libs/os\" - \"@apache-mynewt-core/libs/shell\" - \"@apache-mynewt-core/sys/config\" - \"@apache-mynewt-core/sys/log\" - \"@apache-mynewt-core/sys/stats\" - \"@apache-mynewt-core/libs/baselibc\" - libs/my_drivers/senseair And add a call to your main() to initialize this driver. [user@IsMyLaptop:~/src/air_quality]$ diff project/blinky/src/main.c project/air_quality/src/main.c 28a29 > #include <senseair/senseair.h> 190a192 > senseair_init(); [user@IsMyLaptop:~/src/air_quality And then build it to make sure all goes well. [user@IsMyLaptop:~/src/air_quality]$ newt build air_q Compiling senseair.c Archiving senseair.a Linking air_quality.elf App successfully built: /Users/user/src/air_quality/bin/air_q/apps/air_quality/air_quality.elf All looks good. Add CLI commands for testing drivers While developing the driver, you want to issue operations from console asking it to do stuff. The way to do this is to register your command handler with shell. Whenever your custom command is issued, you can respond to it. The way you do this is first adding a dependency to shell package for your senseair driver. So you change libs/my_drivers/senseair/pkg.yml to have the following: pkg.name: libs/my_drivers/senseair pkg.deps: - \"@apache-mynewt-core/hw/hal\" - \"@apache-mynewt-core/libs/shell\" And then register your shell command in senseair_init() . [user@IsMyLaptop:~/src/air_quality]$ cat libs/my_drivers/senseair/src/senseair.c .... #include <shell/shell.h> #include <console/console.h> static int senseair_shell_func ( int argc , char **argv ); static struct shell_cmd senseair_cmd = { . sc_cmd = \"senseair\" , . sc_cmd_func = senseair_shell_func , }; void senseair_init ( void ) { int rc ; rc = shell_cmd_register ( &senseair_cmd ); assert ( rc == 0 ); } static int senseair_shell_func ( int argc , char **argv ) { console_printf ( \"Yay! Somebody called!\\n\" ); return 0 ; } Then you build this, download to target, and start minicom on your console port. You'll need to wire up your Board to a Serial converter first. On the STM32F3-Discovery Board pin PA9 is TX and pin PA10 is RX so wire PA9 to RX on your serial board, and PA10 to TX on your serial board. [user@IsMyLaptop:~]$ minicom -D /dev/tty.usbserial-AH02MIE2 Welcome to minicom 2.7 OPTIONS: Compiled on Oct 12 2015, 07:48:30. Port /dev/tty.usbserial-AH02MIE2, 13:44:40 Press CTRL-X Z for help on special keys ? 141964:Unknown command ? ? 143804:config log echo ? tasks mempools 143806:stat senseair senseair 150644:Yay! Somebody called! Now that's great. You can connect the hardware to board and start developing code for the driver itself. Use of HAL for drivers The sensor has a serial port connection, and that's how you are going to connect to it. Your original BSP, hw/bsp/stm32f3discovery, has only one UART set up (as specified in src/hal_bsp.c, include/hal/bsp.h). Therefore, you need to create your own bsp which has configuration for this added hardware. So in the shell you make a copy of the original BSP, and then change the package file a little. [user@IsMyLaptop:~/src/air_quality]$ mkdir hw [user@IsMyLaptop:~/src/air_quality]$ mkdir hw/bsp [user@IsMyLaptop:~/src/air_quality]$ cp -R repos/mynewt_stm32f3/hw/bsp/stm32f3discovery hw/bsp/stm32f3discovery_with_senseair Then you modify the pkg.yml in the copied BSP to assign name for this package. And modify the dependency for MCU package to point to mynewt_stm32f3 repository. [user@IsMyLaptop:~/src/air_quality]$ grep pkg.name hw/bsp/stm32f3discovery_with_senseair/pkg.yml pkg.name: \"hw/bsp/stm32f3discovery_with_senseair\" [user@IsMyLaptop:~/src/air_quality]$ tail -2 hw/bsp/stm32f3discovery_with_senseair/pkg.yml pkg.deps: - \"@mynewt_stm32f3/hw/mcu/stm/stm32f3xx\" And you want to use this BSP with my target. So you change the BSP in the target definition. Here's your new target. [user@IsMyLaptop:~/src/air_quality]$ newt target show air_q targets/air_q app=apps/air_quality bsp=hw/bsp/stm32f3discovery_with_senseair build_profile=debug You add the 2nd serial port to my new BSP. Go to hw/bsp/stm32f3discovery_with_senseair directory to do this. Modify the include/hal/bsp.h to increase UART_CNT to 2, and add a definition of the 2nd logical UART. You will use this in your sensor driver. static const struct stm32f3_uart_cfg uart_cfg [ UART_CNT ] = { [ 0 ] = { . suc_uart = USART1 , . suc_rcc_cmd = RCC_APB2PeriphClockCmd , . suc_rcc_dev = RCC_APB2Periph_USART1 , . suc_pin_tx = 9 , . suc_pin_rx = 10 , . suc_pin_rts = 12 , . suc_pin_cts = 11 , . suc_pin_af = GPIO_AF_7 , . suc_irqn = USART1_IRQn }, [ 1 ] = { . suc_uart = USART2 , . suc_rcc_cmd = RCC_APB1PeriphClockCmd , . suc_rcc_dev = RCC_APB1Periph_USART2 , . suc_pin_tx = 19 , /* PB3 */ . suc_pin_rx = 20 , /* PB4 */ . suc_pin_rts = 1 , . suc_pin_cts = 0 , . suc_pin_af = GPIO_AF_7 , . suc_irqn = USART2_IRQn } }; With this in place, you can refer to serial port where your SenseAir sensor is by a logical number. This makes the code more platform independent - you could connect this sensor to another board, like Olimex. You will also use the HAL UART abstraction to do the UART port setup and data transfer. That way you don't need to have any platform dependent pieces within your little driver. You will now see what the driver code ends up looking like. Here's the header file, filled in from stub you created earlier. /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * \"License\"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef _SENSEAIR_H_ #define _SENSEAIR_H_ enum senseair_read_type { SENSEAIR_CO2 , SENSEAIR_TEMPERATURE , SENSEAIR_HUMIDITY }; int senseair_init ( int uartno ); int senseair_read ( enum senseair_read_type ); #endif /* _SENSEAIR_H_ */ As you can see, logical UART number has been added to the init routine. A 'read' function has been added, which is a blocking read. If you were making a commercial product, you would probably have a callback for reporting the results. And here is the source for the driver. /** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * \"License\"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include <string.h> #include <shell/shell.h> #include <console/console.h> #include <os/os.h> #include <hal/hal_uart.h> #include \"senseair/senseair.h\" static const uint8_t cmd_read_co2 [] = { 0xFE , 0X44 , 0X00 , 0X08 , 0X02 , 0X9F , 0X25 }; static const uint8_t cmd_read_temp [] = { 0xFE , 0X44 , 0X00 , 0X12 , 0X02 , 0X94 , 0X45 }; static const uint8_t cmd_read_humidity [] = { 0xFE , 0x44 , 0x00 , 0x14 , 0x02 , 0x97 , 0xE5 }; static int senseair_shell_func ( int argc , char **argv ); static struct shell_cmd senseair_cmd = { . sc_cmd = \"senseair\" , . sc_cmd_func = senseair_shell_func , }; struct senseair { int uart ; struct os_sem sema ; const uint8_t *tx_data ; int tx_off ; int tx_len ; uint8_t rx_data [ 32 ]; int rx_off ; int value ; } senseair ; static int senseair_tx_char ( void *arg ) { struct senseair *s = &senseair ; int rc ; if ( s->tx_off >= s->tx_len ) { /* * Command tx finished. */ s->tx_data = NULL ; return -1 ; } rc = s->tx_data [ s->tx_off ]; s->tx_off++ ; return rc ; } /* * CRC for modbus over serial port. */ static const uint16_t mb_crc_tbl [] = { 0x0000 , 0xcc01 , 0xd801 , 0x1400 , 0xf001 , 0x3c00 , 0x2800 , 0xe401 , 0xa001 , 0x6c00 , 0x7800 , 0xb401 , 0x5000 , 0x9c01 , 0x8801 , 0x4400 }; static uint16_t mb_crc ( const uint8_t *data , int len , uint16_t crc ) { while ( len-- > 0 ) { crc ^= *data++ ; crc = ( crc >> 4 ) ^ mb_crc_tbl [ crc & 0xf ]; crc = ( crc >> 4 ) ^ mb_crc_tbl [ crc & 0xf ]; } return crc ; } static int mb_crc_check ( const void *pkt , int len ) { uint16_t crc , cmp ; uint8_t *bp = ( uint8_t * ) pkt ; if ( len < sizeof ( crc ) + 1 ) { return -1 ; } crc = mb_crc ( pkt , len - 2 , 0xffff ); cmp = bp [ len - 2 ] | ( bp [ len - 1 ] << 8 ); if ( crc != cmp ) { return -1 ; } else { return 0 ; } } static int senseair_rx_char ( void *arg , uint8_t data ) { struct senseair *s = ( struct senseair * ) arg ; int rc ; if ( s->rx_off >= sizeof ( s->rx_data )) { s->rx_off = 0 ; } s->rx_data [ s->rx_off ] = data ; s->rx_off++ ; if ( s->rx_off == 7 ) { rc = mb_crc_check ( s->rx_data , s->rx_off ); if ( rc == 0 ) { s->value = s->rx_data [ 3 ] * 256 + s->rx_data [ 4 ]; os_sem_release ( &s->sema ); } } return 0 ; } void senseair_tx ( struct senseair *s , const uint8_t *tx_data , int data_len ) { s->tx_data = tx_data ; s->tx_len = data_len ; s->tx_off = 0 ; s->rx_off = 0 ; hal_uart_start_tx ( s->uart ); } int senseair_read ( enum senseair_read_type type ) { struct senseair *s = &senseair ; const uint8_t *cmd ; int cmd_len ; int rc ; if ( s->tx_data ) { /* * busy */ return -1 ; } switch ( type ) { case SENSEAIR_CO2 : cmd = cmd_read_co2 ; cmd_len = sizeof ( cmd_read_co2 ); break ; case SENSEAIR_TEMPERATURE : cmd = cmd_read_temp ; cmd_len = sizeof ( cmd_read_temp ); break ; case SENSEAIR_HUMIDITY : cmd = cmd_read_humidity ; cmd_len = sizeof ( cmd_read_humidity ); break ; default : return -1 ; } senseair_tx ( s , cmd , cmd_len ); rc = os_sem_pend ( &s->sema , OS_TICKS_PER_SEC / 2 ); if ( rc == OS_TIMEOUT ) { /* * timeout */ return -2 ; } return s->value ; } static int senseair_shell_func ( int argc , char **argv ) { int value ; enum senseair_read_type type ; if ( argc < 2 ) { usage : console_printf ( \"%s <co2|temp|humidity>\\n\" , argv [ 0 ]); return 0 ; } if ( !strcmp ( argv [ 1 ], \"co2\" )) { type = SENSEAIR_CO2 ; } else if ( !strcmp ( argv [ 1 ], \"temp\" )) { type = SENSEAIR_TEMPERATURE ; } else if ( !strcmp ( argv [ 1 ], \"humidity\" )) { /* * timeout */ return -2 ; } return s->value ; } static int senseair_shell_func ( int argc , char **argv ) { int value ; enum senseair_read_type type ; if ( argc < 2 ) { usage : console_printf ( \"%s <co2|temp|humidity>\\n\" , argv [ 0 ]); return 0 ; } if ( !strcmp ( argv [ 1 ], \"co2\" )) { type = SENSEAIR_CO2 ; } else if ( !strcmp ( argv [ 1 ], \"temp\" )) { type = SENSEAIR_TEMPERATURE ; } else if ( !strcmp ( argv [ 1 ], \"humidity\" )) { type = SENSEAIR_HUMIDITY ; } else { goto usage ; } value = senseair_read ( type ); if ( value >= 0 ) { console_printf ( \"Got %d\\n\" , value ); } else { console_printf ( \"Error while reading: %d\\n\" , value ); } return 0 ; } int senseair_init ( int uartno ) { int rc ; struct senseair *s = &senseair ; rc = shell_cmd_register ( &senseair_cmd ); if ( rc ) { return rc ; } rc = os_sem_init ( &s->sema , 1 ); if ( rc ) { return rc ; } rc = hal_uart_init_cbs ( uartno , senseair_tx_char , NULL , senseair_rx_char , &senseair ); if ( rc ) { return rc ; } rc = hal_uart_config ( uartno , 9600 , 8 , 1 , HAL_UART_PARITY_NONE , HAL_UART_FLOW_CTL_NONE ); if ( rc ) { return rc ; } s->uart = uartno ; return 0 ; } And you modified your main() for senseair driver init. int main ( int argc , char **argv ) { .... senseair_init ( 1 ); .... } You can see from the code that you are using the HAL interface to open a UART port, and using OS semaphore as a way of blocking the task when waiting for read response to come back from the sensor.","title":"Air-quality Sensor project"},{"location":"os/tutorials/air_quality_sensor/#air-quality-sensor-project","text":"","title":"Air quality sensor project"},{"location":"os/tutorials/air_quality_sensor/#setting-up-source-tree-for-stuff-you-need","text":"To start with, you need to create a new project under which you will do this development. So you type in: $ mkdir $HOME/src $ cd $HOME/src $ newt new air_quality Let's say you are using STM32F3discovery board as the platform. You know you need the board support package for that hardware. You can look up its location, add it your project, and fetch that along with the core OS components. To make this happen, you'll need to modify the project.yml in your project's root directory. [user@IsMyLaptop:~/src/air_quality]$ emacs project.yml & [user@IsMyLaptop:~/src/air_quality]$ cat project.yml project.name: \"air_quality\" project.repositories: - apache-mynewt-core - mynewt_stm32f3 # Use github's distribution mechanism for core ASF libraries. # This provides mirroring automatically for us. # repository.apache-mynewt-core: type: github vers: 0-latest user: apache repo: incubator-mynewt-core repository.mynewt_stm32f3: type: github vers: 0-latest user: runtimeinc repo: mynewt_stm32f3 [user@IsMyLaptop:~/src/air_quality]$ newt install apache-mynewt-core mynewt_stm32f3 [user@IsMyLaptop:~/src/air_quality]$ ls repos/ apache-mynewt-core mynewt_stm32f3 Good. You want to make sure you have all the needed bits for supporting your board; so you decide to build the blinky project for the platform first. Now create a target for it and build it. Easiest way to proceed is to copy the existing target for blinky, and modify it to build for STM32F3Discovery board. [user@IsMyLaptop:~/src/air_quality]$ newt target copy my_blinky_sim blink_f3 Target successfully copied; targets/my_blinky_sim --> targets/blink_f3 [user@IsMyLaptop:~/src/air_quality]$ newt target set blink_f3 bsp=@mynewt_stm32f3/hw/bsp/stm32f3discovery Target targets/blink_f3 successfully set target.bsp to @mynewt_stm32f3/hw/bsp/stm32f3discovery [user@IsMyLaptop:~/src/air_quality]$ newt build blink_f3 Compiling hal_bsp.c ... Linking blinky.elf App successfully built: /Users/user/src/air_quality/bin/blink_f3/apps/blinky/blinky.elf Good. You know that this platform uses bootloader, which means you have to create a target for that too. [user@IsMyLaptop:~/src/air_quality]$ newt target create boot_f3 Target targets/boot_f3 successfully created [user@IsMyLaptop:~/src/air_quality]$ newt target show @apache-mynewt-core/targets/unittest bsp=hw/bsp/native build_profile=debug compiler=compiler/sim targets/blink_f3 app=apps/blinky bsp=@mynewt_stm32f3/hw/bsp/stm32f3discovery build_profile=debug targets/boot_f3 targets/my_blinky_sim app=apps/blinky bsp=@apache-mynewt-core/hw/bsp/native build_profile=debug [user@IsMyLaptop:~/src/air_quality]$ newt target set boot_f3 bsp=@mynewt_stm32f3/hw/bsp/stm32f3discovery Target targets/boot_f3 successfully set target.bsp to @mynewt_stm32f3/hw/bsp/stm32f3discovery [user@IsMyLaptop:~/src/air_quality]$ newt target set boot_f3 app=@apache-mynewt-core/apps/boot Target targets/boot_f3 successfully set target.app to @apache-mynewt-core/apps/boot [user@IsMyLaptop:~/src/air_quality]$ newt target set boot_f3 build_profile=optimized Target targets/boot_f3 successfully set target.build_profile to optimized And then build it, and load it onto the board. newt build boot_f3 .... Linking boot.elf App successfully built: /Users/user/src/air_quality/bin/boot_f3/apps/boot/boot.elf [user@IsMyLaptop:~/src/air_quality] $ newt load boot_f3 Next you must download the targets to board, and see that the LED actually blinks. You plug in the STM32F3 discovery board to your laptop, and say: [user@IsMyLaptop:~/src/air_quality]$ newt load blink_f3 Downloading /Users/user/src/air_quality/bin/blink_f3/apps/blinky/blinky.img to 0x08009000 Open On-Chip Debugger 0.9.0 (2015-05-28-12:05) .... xPSR: 0x01000000 pc: 0x0800026c msp: 0x10002000 auto erase enabled Error: couldn't open /Users/user/src/air_quality/bin/blink_f3/apps/blinky/blinky.img Error: exit status 1 load - Load app image to target for <target-name>. Usage: newt load [flags] Examples: newt load <target-name> Global Flags: -l, --loglevel string Log level, defaults to WARN. (default \"WARN\") -o, --outfile string Filename to tee log output to -q, --quiet Be quiet; only display error output. -s, --silent Be silent; don't output anything. -v, --verbose Enable verbose output when executing commands. exit status 1 Ah. Forgot to create an image out of the blinky binary. Note that every time you want to build and load a new firmware image to target board, you need to run 'create-image' on it. [user@IsMyLaptop:~/src/air_quality]$ newt create-image blink_f3 0.0.1 App image successfully generated: /Users/user/src/air_quality/bin/blink_f3/apps/blinky/blinky.img Build manifest: /Users/user/src/air_quality/bin/blink_f3/apps/blinky/manifest.json [user@IsMyLaptop:~/src/air_quality]$ newt load blink_f3 0.0.1 And it's blinking. Shortcut for doing build/create-image/load/debug steps all in one is 'newt run' command. Check out the usage from command line help.","title":"Setting up source tree for stuff you need"},{"location":"os/tutorials/air_quality_sensor/#create-test-project","text":"Now that you have your system setup, you can start creating your own stuff. First you want to create a project for yourself - you can start by getting project template from blinky, as it pretty much has what you want. [user@IsMyLaptop:~/src/air_quality]$ mkdir apps/air_quality [user@IsMyLaptop:~/src/air_quality]$ cp repos/apache-mynewt-core/apps/blinky/pkg.yml apps/air_quality/ [user@IsMyLaptop:~/src/air_quality]$ mkdir apps/air_quality/src [user@IsMyLaptop:~/src/air_quality]$ cp repos/apache-mynewt-core/apps/blinky/src/main.c apps/air_quality/src/ Then you modify the apps/air_quality/pkg.yml for air_quality in order to change the pkg.name to be apps/air_quality . You also need to point the package dependencies to point to packages in apache-mynewt-core repository. STM32F3discovery board has limited amount of memory, so you must also switch your libc to be baselibc, instead of the standard one. [user@IsMyLaptop:~/src/air_quality]$ cat apps/air_quality/pkg.yml pkg.name: apps/air_quality pkg.type: app pkg.description: Air quality sensor test pkg.keywords: pkg.deps: - \"@apache-mynewt-core/libs/console/full\" - \"@apache-mynewt-core/libs/newtmgr\" - \"@apache-mynewt-core/libs/os\" - \"@apache-mynewt-core/libs/shell\" - \"@apache-mynewt-core/sys/config\" - \"@apache-mynewt-core/sys/log\" - \"@apache-mynewt-core/sys/stats\" - \"@apache-mynewt-core/libs/baselibc\" And create a target for it: [user@IsMyLaptop:~/src/air_quality]$ newt target create air_q Target targets/air_q successfully created [user@IsMyLaptop:~/src/air_quality]$ newt target set air_q bsp=@mynewt_stm32f3/hw/bsp/stm32f3discovery Target targets/air_q successfully set target.bsp to @mynewt_stm32f3/hw/bsp/stm32f3discovery [user@IsMyLaptop:~/src/air_quality]$ newt target set air_q app=apps/air_quality Target targets/air_q successfully set target.app to apps/air_quality [user@IsMyLaptop:~/src/air_quality]$ newt target set air_q build_profile=debug Target targets/air_q successfully set target.build_profile to debug [user@IsMyLaptop:~/src/air_quality]$ newt build air_q .... Linking air_quality.elf App successfully built: /Users/user/src/air_quality/bin/air_q/apps/air_quality/air_quality.elf","title":"Create test project"},{"location":"os/tutorials/air_quality_sensor/#create-packages-for-drivers","text":"One of the sensors you want to enable is SenseAir K30, which will connect to the board over serial port. To start development of the driver, you first need to create a package description for it, and add stubs for sources. So you add few files. pkg.yml to describe the driver, and then header stub followed by source stub. [user@IsMyLaptop:~/src/air_quality]$ cat libs/my_drivers/senseair/pkg.yml # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # \"License\"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http: //www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # pkg . name: libs/my_drivers/senseair pkg . deps: - \"@apache-mynewt-core/hw/hal\" [user@IsMyLaptop:~/src/air_quality]$ cat libs/my_drivers/senseair/include/senseair/senseair.h /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * \"License\"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef _SENSEAIR_H_ #define _SENSEAIR_H_ void senseair_init ( void ); #endif /* _SENSEAIR_H_ */ [user@IsMyLaptop:~/src/air_quality]$ cat libs/my_drivers/senseair/src/senseair.c /** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * \"License\"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ void senseair_init ( void ) { } And add dependency to this package in my project yml file. Here's from apps/air_quality/pkg.yml pkg.name: apps/air_quality pkg.type: app pkg.description: Air quality sensor test pkg.keywords: pkg.deps: - \"@apache-mynewt-core/libs/console/full\" - \"@apache-mynewt-core/libs/newtmgr\" - \"@apache-mynewt-core/libs/os\" - \"@apache-mynewt-core/libs/shell\" - \"@apache-mynewt-core/sys/config\" - \"@apache-mynewt-core/sys/log\" - \"@apache-mynewt-core/sys/stats\" - \"@apache-mynewt-core/libs/baselibc\" - libs/my_drivers/senseair And add a call to your main() to initialize this driver. [user@IsMyLaptop:~/src/air_quality]$ diff project/blinky/src/main.c project/air_quality/src/main.c 28a29 > #include <senseair/senseair.h> 190a192 > senseair_init(); [user@IsMyLaptop:~/src/air_quality And then build it to make sure all goes well. [user@IsMyLaptop:~/src/air_quality]$ newt build air_q Compiling senseair.c Archiving senseair.a Linking air_quality.elf App successfully built: /Users/user/src/air_quality/bin/air_q/apps/air_quality/air_quality.elf All looks good.","title":"Create packages for drivers"},{"location":"os/tutorials/air_quality_sensor/#add-cli-commands-for-testing-drivers","text":"While developing the driver, you want to issue operations from console asking it to do stuff. The way to do this is to register your command handler with shell. Whenever your custom command is issued, you can respond to it. The way you do this is first adding a dependency to shell package for your senseair driver. So you change libs/my_drivers/senseair/pkg.yml to have the following: pkg.name: libs/my_drivers/senseair pkg.deps: - \"@apache-mynewt-core/hw/hal\" - \"@apache-mynewt-core/libs/shell\" And then register your shell command in senseair_init() . [user@IsMyLaptop:~/src/air_quality]$ cat libs/my_drivers/senseair/src/senseair.c .... #include <shell/shell.h> #include <console/console.h> static int senseair_shell_func ( int argc , char **argv ); static struct shell_cmd senseair_cmd = { . sc_cmd = \"senseair\" , . sc_cmd_func = senseair_shell_func , }; void senseair_init ( void ) { int rc ; rc = shell_cmd_register ( &senseair_cmd ); assert ( rc == 0 ); } static int senseair_shell_func ( int argc , char **argv ) { console_printf ( \"Yay! Somebody called!\\n\" ); return 0 ; } Then you build this, download to target, and start minicom on your console port. You'll need to wire up your Board to a Serial converter first. On the STM32F3-Discovery Board pin PA9 is TX and pin PA10 is RX so wire PA9 to RX on your serial board, and PA10 to TX on your serial board. [user@IsMyLaptop:~]$ minicom -D /dev/tty.usbserial-AH02MIE2 Welcome to minicom 2.7 OPTIONS: Compiled on Oct 12 2015, 07:48:30. Port /dev/tty.usbserial-AH02MIE2, 13:44:40 Press CTRL-X Z for help on special keys ? 141964:Unknown command ? ? 143804:config log echo ? tasks mempools 143806:stat senseair senseair 150644:Yay! Somebody called! Now that's great. You can connect the hardware to board and start developing code for the driver itself.","title":"Add CLI commands for testing drivers"},{"location":"os/tutorials/air_quality_sensor/#use-of-hal-for-drivers","text":"The sensor has a serial port connection, and that's how you are going to connect to it. Your original BSP, hw/bsp/stm32f3discovery, has only one UART set up (as specified in src/hal_bsp.c, include/hal/bsp.h). Therefore, you need to create your own bsp which has configuration for this added hardware. So in the shell you make a copy of the original BSP, and then change the package file a little. [user@IsMyLaptop:~/src/air_quality]$ mkdir hw [user@IsMyLaptop:~/src/air_quality]$ mkdir hw/bsp [user@IsMyLaptop:~/src/air_quality]$ cp -R repos/mynewt_stm32f3/hw/bsp/stm32f3discovery hw/bsp/stm32f3discovery_with_senseair Then you modify the pkg.yml in the copied BSP to assign name for this package. And modify the dependency for MCU package to point to mynewt_stm32f3 repository. [user@IsMyLaptop:~/src/air_quality]$ grep pkg.name hw/bsp/stm32f3discovery_with_senseair/pkg.yml pkg.name: \"hw/bsp/stm32f3discovery_with_senseair\" [user@IsMyLaptop:~/src/air_quality]$ tail -2 hw/bsp/stm32f3discovery_with_senseair/pkg.yml pkg.deps: - \"@mynewt_stm32f3/hw/mcu/stm/stm32f3xx\" And you want to use this BSP with my target. So you change the BSP in the target definition. Here's your new target. [user@IsMyLaptop:~/src/air_quality]$ newt target show air_q targets/air_q app=apps/air_quality bsp=hw/bsp/stm32f3discovery_with_senseair build_profile=debug You add the 2nd serial port to my new BSP. Go to hw/bsp/stm32f3discovery_with_senseair directory to do this. Modify the include/hal/bsp.h to increase UART_CNT to 2, and add a definition of the 2nd logical UART. You will use this in your sensor driver. static const struct stm32f3_uart_cfg uart_cfg [ UART_CNT ] = { [ 0 ] = { . suc_uart = USART1 , . suc_rcc_cmd = RCC_APB2PeriphClockCmd , . suc_rcc_dev = RCC_APB2Periph_USART1 , . suc_pin_tx = 9 , . suc_pin_rx = 10 , . suc_pin_rts = 12 , . suc_pin_cts = 11 , . suc_pin_af = GPIO_AF_7 , . suc_irqn = USART1_IRQn }, [ 1 ] = { . suc_uart = USART2 , . suc_rcc_cmd = RCC_APB1PeriphClockCmd , . suc_rcc_dev = RCC_APB1Periph_USART2 , . suc_pin_tx = 19 , /* PB3 */ . suc_pin_rx = 20 , /* PB4 */ . suc_pin_rts = 1 , . suc_pin_cts = 0 , . suc_pin_af = GPIO_AF_7 , . suc_irqn = USART2_IRQn } }; With this in place, you can refer to serial port where your SenseAir sensor is by a logical number. This makes the code more platform independent - you could connect this sensor to another board, like Olimex. You will also use the HAL UART abstraction to do the UART port setup and data transfer. That way you don't need to have any platform dependent pieces within your little driver. You will now see what the driver code ends up looking like. Here's the header file, filled in from stub you created earlier. /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * \"License\"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #ifndef _SENSEAIR_H_ #define _SENSEAIR_H_ enum senseair_read_type { SENSEAIR_CO2 , SENSEAIR_TEMPERATURE , SENSEAIR_HUMIDITY }; int senseair_init ( int uartno ); int senseair_read ( enum senseair_read_type ); #endif /* _SENSEAIR_H_ */ As you can see, logical UART number has been added to the init routine. A 'read' function has been added, which is a blocking read. If you were making a commercial product, you would probably have a callback for reporting the results. And here is the source for the driver. /** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * \"License\"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include <string.h> #include <shell/shell.h> #include <console/console.h> #include <os/os.h> #include <hal/hal_uart.h> #include \"senseair/senseair.h\" static const uint8_t cmd_read_co2 [] = { 0xFE , 0X44 , 0X00 , 0X08 , 0X02 , 0X9F , 0X25 }; static const uint8_t cmd_read_temp [] = { 0xFE , 0X44 , 0X00 , 0X12 , 0X02 , 0X94 , 0X45 }; static const uint8_t cmd_read_humidity [] = { 0xFE , 0x44 , 0x00 , 0x14 , 0x02 , 0x97 , 0xE5 }; static int senseair_shell_func ( int argc , char **argv ); static struct shell_cmd senseair_cmd = { . sc_cmd = \"senseair\" , . sc_cmd_func = senseair_shell_func , }; struct senseair { int uart ; struct os_sem sema ; const uint8_t *tx_data ; int tx_off ; int tx_len ; uint8_t rx_data [ 32 ]; int rx_off ; int value ; } senseair ; static int senseair_tx_char ( void *arg ) { struct senseair *s = &senseair ; int rc ; if ( s->tx_off >= s->tx_len ) { /* * Command tx finished. */ s->tx_data = NULL ; return -1 ; } rc = s->tx_data [ s->tx_off ]; s->tx_off++ ; return rc ; } /* * CRC for modbus over serial port. */ static const uint16_t mb_crc_tbl [] = { 0x0000 , 0xcc01 , 0xd801 , 0x1400 , 0xf001 , 0x3c00 , 0x2800 , 0xe401 , 0xa001 , 0x6c00 , 0x7800 , 0xb401 , 0x5000 , 0x9c01 , 0x8801 , 0x4400 }; static uint16_t mb_crc ( const uint8_t *data , int len , uint16_t crc ) { while ( len-- > 0 ) { crc ^= *data++ ; crc = ( crc >> 4 ) ^ mb_crc_tbl [ crc & 0xf ]; crc = ( crc >> 4 ) ^ mb_crc_tbl [ crc & 0xf ]; } return crc ; } static int mb_crc_check ( const void *pkt , int len ) { uint16_t crc , cmp ; uint8_t *bp = ( uint8_t * ) pkt ; if ( len < sizeof ( crc ) + 1 ) { return -1 ; } crc = mb_crc ( pkt , len - 2 , 0xffff ); cmp = bp [ len - 2 ] | ( bp [ len - 1 ] << 8 ); if ( crc != cmp ) { return -1 ; } else { return 0 ; } } static int senseair_rx_char ( void *arg , uint8_t data ) { struct senseair *s = ( struct senseair * ) arg ; int rc ; if ( s->rx_off >= sizeof ( s->rx_data )) { s->rx_off = 0 ; } s->rx_data [ s->rx_off ] = data ; s->rx_off++ ; if ( s->rx_off == 7 ) { rc = mb_crc_check ( s->rx_data , s->rx_off ); if ( rc == 0 ) { s->value = s->rx_data [ 3 ] * 256 + s->rx_data [ 4 ]; os_sem_release ( &s->sema ); } } return 0 ; } void senseair_tx ( struct senseair *s , const uint8_t *tx_data , int data_len ) { s->tx_data = tx_data ; s->tx_len = data_len ; s->tx_off = 0 ; s->rx_off = 0 ; hal_uart_start_tx ( s->uart ); } int senseair_read ( enum senseair_read_type type ) { struct senseair *s = &senseair ; const uint8_t *cmd ; int cmd_len ; int rc ; if ( s->tx_data ) { /* * busy */ return -1 ; } switch ( type ) { case SENSEAIR_CO2 : cmd = cmd_read_co2 ; cmd_len = sizeof ( cmd_read_co2 ); break ; case SENSEAIR_TEMPERATURE : cmd = cmd_read_temp ; cmd_len = sizeof ( cmd_read_temp ); break ; case SENSEAIR_HUMIDITY : cmd = cmd_read_humidity ; cmd_len = sizeof ( cmd_read_humidity ); break ; default : return -1 ; } senseair_tx ( s , cmd , cmd_len ); rc = os_sem_pend ( &s->sema , OS_TICKS_PER_SEC / 2 ); if ( rc == OS_TIMEOUT ) { /* * timeout */ return -2 ; } return s->value ; } static int senseair_shell_func ( int argc , char **argv ) { int value ; enum senseair_read_type type ; if ( argc < 2 ) { usage : console_printf ( \"%s <co2|temp|humidity>\\n\" , argv [ 0 ]); return 0 ; } if ( !strcmp ( argv [ 1 ], \"co2\" )) { type = SENSEAIR_CO2 ; } else if ( !strcmp ( argv [ 1 ], \"temp\" )) { type = SENSEAIR_TEMPERATURE ; } else if ( !strcmp ( argv [ 1 ], \"humidity\" )) { /* * timeout */ return -2 ; } return s->value ; } static int senseair_shell_func ( int argc , char **argv ) { int value ; enum senseair_read_type type ; if ( argc < 2 ) { usage : console_printf ( \"%s <co2|temp|humidity>\\n\" , argv [ 0 ]); return 0 ; } if ( !strcmp ( argv [ 1 ], \"co2\" )) { type = SENSEAIR_CO2 ; } else if ( !strcmp ( argv [ 1 ], \"temp\" )) { type = SENSEAIR_TEMPERATURE ; } else if ( !strcmp ( argv [ 1 ], \"humidity\" )) { type = SENSEAIR_HUMIDITY ; } else { goto usage ; } value = senseair_read ( type ); if ( value >= 0 ) { console_printf ( \"Got %d\\n\" , value ); } else { console_printf ( \"Error while reading: %d\\n\" , value ); } return 0 ; } int senseair_init ( int uartno ) { int rc ; struct senseair *s = &senseair ; rc = shell_cmd_register ( &senseair_cmd ); if ( rc ) { return rc ; } rc = os_sem_init ( &s->sema , 1 ); if ( rc ) { return rc ; } rc = hal_uart_init_cbs ( uartno , senseair_tx_char , NULL , senseair_rx_char , &senseair ); if ( rc ) { return rc ; } rc = hal_uart_config ( uartno , 9600 , 8 , 1 , HAL_UART_PARITY_NONE , HAL_UART_FLOW_CTL_NONE ); if ( rc ) { return rc ; } s->uart = uartno ; return 0 ; } And you modified your main() for senseair driver init. int main ( int argc , char **argv ) { .... senseair_init ( 1 ); .... } You can see from the code that you are using the HAL interface to open a UART port, and using OS semaphore as a way of blocking the task when waiting for read response to come back from the sensor.","title":"Use of HAL for drivers"},{"location":"os/tutorials/arduino_zero/","text":"Blinky, your \"Hello World!\", on Arduino Zero Learn how to use packages from a default application repository of Mynewt to build your first Hello World application (Blinky) on a target board. Once built using the newt tool, this application will blink the LED lights on the target board. This tutorial describes how to run Mynewt OS on Arduino Zero. Follow these simple steps and your board will be blinking in no time! Prerequisites Before tackling this tutorial, it's best to read about Mynewt in the Introduction section of this documentation. Equipment You will need the following equipment An Arduino Zero board. NOTE: There are many flavors of Arduino. Ensure that you have an Arduino Zero. See below for the versions of Arduino Zero that are compatible with this tutorial A computer that can connect to the Arduino Zero over USB A USB cable (Type A to micro B) that can connect the computer to the Arduino The Mynewt Release This tutorial has been tested on the following three Arduino Zero boards - Zero, M0 Pro, and Zero-Pro. Mynewt has not been tested on Arduino M0 which has no internal debugger support. Install Mynewt and Newt If you have not already done so, install Newt as shown in the Newt install tutorial If you have not already done so, create a project as shown in the Quick Start guide on how to Create Your First Project . Skip the testing and building the project steps in that tutorial since you will be defining a target for your Arduino board in this tutorial. Fetch External Packages Mynewt uses source code provided directly from the chip manufacturer for low level operations. Sometimes this code is licensed only for the specific manufacturer of the chipset and cannot live in the Apache Mynewt repository. That happens to be the case for the Arduino Zero board which uses Atmel SAMD21. Runtime's github repository hosts such external third-party packages and the Newt tool can fetch them. To fetch the package with MCU support for Atmel SAMD21 for Arduino Zero from the Runtime git repository, you need to add the repository to the project.yml file in your base project directory. Here is an example project.yml file with the Arduino Zero repository added. The sections with mynewt_arduino_zero that need to be added to your project file are highlighted. $ more project.yml project.name: \"my_project\" project.repositories: - apache-mynewt-core - mynewt_arduino_zero repository.apache-mynewt-core: type: github vers: 0-latest user: apache repo: incubator-mynewt-core repository.mynewt_arduino_zero: type: github vers: 0-latest user: runtimeinc repo: mynewt_arduino_zero $ Once you've edited your project.yml file, the next step is to install the project dependencies, this can be done with the newt install command (to see more output, provide the -v verbose option.): $ newt install apache-mynewt-core mynewt_arduino_zero $ NOTE: If there has been a new release of a repo used in your project since you last installed it, the 0-latest version for the repo in the project.yml file will refer to the new release and will not match the installed files. In that case you will get an error message saying so and you will need to run newt upgrade to overwrite the existing files with the latest codebase. Create your bootloader target Next, you need to tell Newt what to build. For the Arduino Zero, we are going to generate both a bootloader, and an image target. To generate the bootloader target, you need to specify the following options. The output of the commands (indicating success) have been suppressed for easier readability. $ newt target create arduino_boot $ newt target set arduino_boot bsp=@mynewt_arduino_zero/hw/bsp/arduino_zero $ newt target set arduino_boot app=@apache-mynewt-core/apps/boot $ newt target set arduino_boot build_profile=optimized If you have an Arduino Zero Pro or M0 Pro, you have to set the following next: $ newt target set arduino_boot features=arduino_zero_pro If you have an Arduino Zero, you have to set the following instead: $ newt target set arduino_boot features=arduino_zero These commands do a few things: Create a target named arduino_boot , in order to build the Arduino Zero Bootloader. Set the application for the arduino_boot target to the default Apache Mynewt bootloader ( @apache-mynewt-core/apps/boot ) Set the board support package for the target to @mynewt_arduino_zero/hw/bsp/arduino_zero . This is a reference to the downloaded Arduino Zero support from Github. Use the \"optimized\" build profile for the arduino_boot target. This instructs Newt to generate smaller and more efficient code for this target. This setting is necessary due to the bootloader's strict size constraints. Tells the Board Support Package to enable support for the Arduino Zero Pro or the Arduino Zero. Set it to arduino_zero or arduino_zero_pro depending on the board you have. Build your bootloader Once you've configured the bootloader target, the next step is to build the bootloader for your Arduino. You can do this by using the newt build command: $ newt build arduino_boot Compiling asprintf.c Compiling atoi.c Compiling atol.c Compiling atoll.c Compiling bsearch.c Compiling bzero.c Compiling calloc.c Compiling fgets.c Compiling inline.c <snip> App successfully built: myproject/bin/arduino_boot/apps/boot/boot.elf If this command finishes successfully, you have successfully built the Arduino bootloader, and the next step is to build your application for the Arduino board. Build your blinky app To create and download your application, you create another target, this one pointing to the application you want to download to the Arduino board. In this tutorial, we will use the default application that comes with your project, apps/blinky : Note : Remember to set features to arduino_zero if your board is Arduino Zero and not a Pro! $ newt target create arduino_blinky Target targets/arduino_blinky successfully created $ newt target set arduino_blinky app=apps/blinky Target targets/arduino_blinky successfully set target.app to apps/blinky $ newt target set arduino_blinky bsp=@mynewt_arduino_zero/hw/bsp/arduino_zero Target targets/arduino_blinky successfully set target.bsp to @mynewt_arduino_zero/hw/bsp/arduino_zero $ newt target set arduino_blinky build_profile=debug Target targets/arduino_blinky successfully set target.build_profile to debug $ newt target set arduino_blinky features=arduino_zero_pro Target targets/arduino_blinky successfully set pkg.features to arduino_zero_pro $ You can now build the target, with newt build : $ newt build arduino_blinky Compiling main.c Archiving blinky.a Compiling cons_fmt.c Compiling cons_tty.c Archiving full.a Compiling case.c Compiling suite.c Compiling testutil.c Archiving testutil.a <snip> App successfully built: myproject/bin/arduino_blinky/apps/blinky/blinky.elf Congratulations! You have successfully built your application. Now it's time to load both the bootloader and application onto the target. Connect the Target Connect your computer to the Arduino Zero (from now on we'll call this the target) with the Micro-USB cable through the Programming Port as shown below. Mynewt will download and debug the target through this port. You should see a little green LED come on. That means the board has power. No external debugger is required. The Arduino Zero comes with an internal debugger that can be accessed by Mynewt. A image below shows the Arduino Zero Programming Port. Download the Bootloader Execute the command to download the bootloader. $ newt load arduino_boot If the newt tool finishes without error, that means the bootloader has been successfully loaded onto the target. Reminder if you are using Docker: When working with actual hardware, remember that each board has an ID. If you swap boards and do not refresh the USB Device Filter on the VirtualBox UI, the ID might be stale and the Docker instance may not be able to see the board correctly. For example, you may see an error message like Error: unable to find CMSIS-DAP device when you try to load or run an image on the board. In that case, you need to click on the USB link in VirtualBox UI, remove the existing USB Device Filter (e.g. \"Atmel Corp. EDBG CMSIS-DAP[0101]\") by clicking on the \"Removes selected USB filter\" button, and add a new filter by clicking on the \"Adds new USB filter\" button. Run the Image Now that the bootloader is downloaded to the target, the next step is to load your image onto the Arduino Zero. The easiest way to do this, is to use the newt run command. newt run will automatically rebuild your program (if necessary), create an image, and load it onto the target device. Here, we will load our arduino_blinky target onto the device, and we should see it run: $ newt run arduino_blinky 0.0.0 Debugging myproject/bin/arduino_blinky/apps/blinky/blinky.elf Open On-Chip Debugger 0.9.0 (2015-09-23-21:46) Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html Info : only one transport option; autoselect 'swd' adapter speed: 500 kHz adapter_nsrst_delay: 100 cortex_m reset_config sysresetreq Info : CMSIS-DAP: SWD Supported Info : CMSIS-DAP: JTAG Supported Info : CMSIS-DAP: Interface Initialised (SWD) Info : CMSIS-DAP: FW Version = 01.1F.0118 Info : SWCLK/TCK = 1 SWDIO/TMS = 1 TDI = 1 TDO = 1 nTRST = 0 nRESET = 1 Info : CMSIS-DAP: Interface ready Info : clock speed 500 kHz Info : SWD IDCODE 0x0bc11477 Info : at91samd21g18.cpu: hardware has 4 breakpoints, 2 watchpoints GNU gdb (GNU Tools for ARM Embedded Processors) 7.8.0.20150604-cvs Copyright (C) 2014 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type \"show copying\" and \"show warranty\" for details. This GDB was configured as \"--host=x86_64-apple-darwin10 --target=arm-none-eabi\". Type \"show configuration\" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type \"help\". Type \"apropos word\" to search for commands related to \"word\"... Reading symbols from myproject/bin/arduino_blinky/apps/blinky/blinky.elf...done. target state: halted target halted due to debug-request, current mode: Thread xPSR: 0x21000000 pc: 0x0000030e msp: 0x20008000 Info : accepting 'gdb' connection on tcp/3333 Info : SAMD MCU: SAMD21G18A (256KB Flash, 32KB RAM) 0x0000030e in ?? () (gdb) r The \"remote\" target does not support \"run\". Try \"help target\" or \"continue\". (gdb) c Continuing. NOTE: The 0.0.0 specified after the target name to newt run is the version of the image to load. If you are not providing remote upgrade, and are just developing locally, you can provide 0.0.0 for every image version. If you want the image to run without the debugger connected, simply quit the debugger and restart the board. The image you programmed will come and run on the Arduino on next boot! Watch the LED blink Congratulations! You have created a Mynewt operating system running on the Arduino Zero. The LED right next to the power LED should be blinking. It is toggled by one task running on the Mynewt OS. We have more fun tutorials for you to get your hands dirty. Be bold and try other Blinky-like tutorials or try enabling additional functionality such as remote comms on the current board. If you see anything missing or want to send us feedback, please do so by signing up for appropriate mailing lists on our Community Page . Keep on hacking and blinking!","title":"Blinky on Arduino Zero"},{"location":"os/tutorials/arduino_zero/#blinky-your-hello-world-on-arduino-zero","text":"Learn how to use packages from a default application repository of Mynewt to build your first Hello World application (Blinky) on a target board. Once built using the newt tool, this application will blink the LED lights on the target board. This tutorial describes how to run Mynewt OS on Arduino Zero. Follow these simple steps and your board will be blinking in no time!","title":"Blinky, your \"Hello World!\", on Arduino Zero"},{"location":"os/tutorials/arduino_zero/#prerequisites","text":"Before tackling this tutorial, it's best to read about Mynewt in the Introduction section of this documentation.","title":"Prerequisites"},{"location":"os/tutorials/arduino_zero/#equipment","text":"You will need the following equipment An Arduino Zero board. NOTE: There are many flavors of Arduino. Ensure that you have an Arduino Zero. See below for the versions of Arduino Zero that are compatible with this tutorial A computer that can connect to the Arduino Zero over USB A USB cable (Type A to micro B) that can connect the computer to the Arduino The Mynewt Release This tutorial has been tested on the following three Arduino Zero boards - Zero, M0 Pro, and Zero-Pro. Mynewt has not been tested on Arduino M0 which has no internal debugger support.","title":"Equipment"},{"location":"os/tutorials/arduino_zero/#install-mynewt-and-newt","text":"If you have not already done so, install Newt as shown in the Newt install tutorial If you have not already done so, create a project as shown in the Quick Start guide on how to Create Your First Project . Skip the testing and building the project steps in that tutorial since you will be defining a target for your Arduino board in this tutorial.","title":"Install Mynewt and Newt"},{"location":"os/tutorials/arduino_zero/#fetch-external-packages","text":"Mynewt uses source code provided directly from the chip manufacturer for low level operations. Sometimes this code is licensed only for the specific manufacturer of the chipset and cannot live in the Apache Mynewt repository. That happens to be the case for the Arduino Zero board which uses Atmel SAMD21. Runtime's github repository hosts such external third-party packages and the Newt tool can fetch them. To fetch the package with MCU support for Atmel SAMD21 for Arduino Zero from the Runtime git repository, you need to add the repository to the project.yml file in your base project directory. Here is an example project.yml file with the Arduino Zero repository added. The sections with mynewt_arduino_zero that need to be added to your project file are highlighted. $ more project.yml project.name: \"my_project\" project.repositories: - apache-mynewt-core - mynewt_arduino_zero repository.apache-mynewt-core: type: github vers: 0-latest user: apache repo: incubator-mynewt-core repository.mynewt_arduino_zero: type: github vers: 0-latest user: runtimeinc repo: mynewt_arduino_zero $ Once you've edited your project.yml file, the next step is to install the project dependencies, this can be done with the newt install command (to see more output, provide the -v verbose option.): $ newt install apache-mynewt-core mynewt_arduino_zero $ NOTE: If there has been a new release of a repo used in your project since you last installed it, the 0-latest version for the repo in the project.yml file will refer to the new release and will not match the installed files. In that case you will get an error message saying so and you will need to run newt upgrade to overwrite the existing files with the latest codebase.","title":"Fetch External Packages"},{"location":"os/tutorials/arduino_zero/#create-your-bootloader-target","text":"Next, you need to tell Newt what to build. For the Arduino Zero, we are going to generate both a bootloader, and an image target. To generate the bootloader target, you need to specify the following options. The output of the commands (indicating success) have been suppressed for easier readability. $ newt target create arduino_boot $ newt target set arduino_boot bsp=@mynewt_arduino_zero/hw/bsp/arduino_zero $ newt target set arduino_boot app=@apache-mynewt-core/apps/boot $ newt target set arduino_boot build_profile=optimized If you have an Arduino Zero Pro or M0 Pro, you have to set the following next: $ newt target set arduino_boot features=arduino_zero_pro If you have an Arduino Zero, you have to set the following instead: $ newt target set arduino_boot features=arduino_zero These commands do a few things: Create a target named arduino_boot , in order to build the Arduino Zero Bootloader. Set the application for the arduino_boot target to the default Apache Mynewt bootloader ( @apache-mynewt-core/apps/boot ) Set the board support package for the target to @mynewt_arduino_zero/hw/bsp/arduino_zero . This is a reference to the downloaded Arduino Zero support from Github. Use the \"optimized\" build profile for the arduino_boot target. This instructs Newt to generate smaller and more efficient code for this target. This setting is necessary due to the bootloader's strict size constraints. Tells the Board Support Package to enable support for the Arduino Zero Pro or the Arduino Zero. Set it to arduino_zero or arduino_zero_pro depending on the board you have.","title":"Create your bootloader target"},{"location":"os/tutorials/arduino_zero/#build-your-bootloader","text":"Once you've configured the bootloader target, the next step is to build the bootloader for your Arduino. You can do this by using the newt build command: $ newt build arduino_boot Compiling asprintf.c Compiling atoi.c Compiling atol.c Compiling atoll.c Compiling bsearch.c Compiling bzero.c Compiling calloc.c Compiling fgets.c Compiling inline.c <snip> App successfully built: myproject/bin/arduino_boot/apps/boot/boot.elf If this command finishes successfully, you have successfully built the Arduino bootloader, and the next step is to build your application for the Arduino board.","title":"Build your bootloader"},{"location":"os/tutorials/arduino_zero/#build-your-blinky-app","text":"To create and download your application, you create another target, this one pointing to the application you want to download to the Arduino board. In this tutorial, we will use the default application that comes with your project, apps/blinky : Note : Remember to set features to arduino_zero if your board is Arduino Zero and not a Pro! $ newt target create arduino_blinky Target targets/arduino_blinky successfully created $ newt target set arduino_blinky app=apps/blinky Target targets/arduino_blinky successfully set target.app to apps/blinky $ newt target set arduino_blinky bsp=@mynewt_arduino_zero/hw/bsp/arduino_zero Target targets/arduino_blinky successfully set target.bsp to @mynewt_arduino_zero/hw/bsp/arduino_zero $ newt target set arduino_blinky build_profile=debug Target targets/arduino_blinky successfully set target.build_profile to debug $ newt target set arduino_blinky features=arduino_zero_pro Target targets/arduino_blinky successfully set pkg.features to arduino_zero_pro $ You can now build the target, with newt build : $ newt build arduino_blinky Compiling main.c Archiving blinky.a Compiling cons_fmt.c Compiling cons_tty.c Archiving full.a Compiling case.c Compiling suite.c Compiling testutil.c Archiving testutil.a <snip> App successfully built: myproject/bin/arduino_blinky/apps/blinky/blinky.elf Congratulations! You have successfully built your application. Now it's time to load both the bootloader and application onto the target.","title":"Build your blinky app"},{"location":"os/tutorials/arduino_zero/#connect-the-target","text":"Connect your computer to the Arduino Zero (from now on we'll call this the target) with the Micro-USB cable through the Programming Port as shown below. Mynewt will download and debug the target through this port. You should see a little green LED come on. That means the board has power. No external debugger is required. The Arduino Zero comes with an internal debugger that can be accessed by Mynewt. A image below shows the Arduino Zero Programming Port.","title":"Connect the Target"},{"location":"os/tutorials/arduino_zero/#download-the-bootloader","text":"Execute the command to download the bootloader. $ newt load arduino_boot If the newt tool finishes without error, that means the bootloader has been successfully loaded onto the target. Reminder if you are using Docker: When working with actual hardware, remember that each board has an ID. If you swap boards and do not refresh the USB Device Filter on the VirtualBox UI, the ID might be stale and the Docker instance may not be able to see the board correctly. For example, you may see an error message like Error: unable to find CMSIS-DAP device when you try to load or run an image on the board. In that case, you need to click on the USB link in VirtualBox UI, remove the existing USB Device Filter (e.g. \"Atmel Corp. EDBG CMSIS-DAP[0101]\") by clicking on the \"Removes selected USB filter\" button, and add a new filter by clicking on the \"Adds new USB filter\" button.","title":"Download the Bootloader"},{"location":"os/tutorials/arduino_zero/#run-the-image","text":"Now that the bootloader is downloaded to the target, the next step is to load your image onto the Arduino Zero. The easiest way to do this, is to use the newt run command. newt run will automatically rebuild your program (if necessary), create an image, and load it onto the target device. Here, we will load our arduino_blinky target onto the device, and we should see it run: $ newt run arduino_blinky 0.0.0 Debugging myproject/bin/arduino_blinky/apps/blinky/blinky.elf Open On-Chip Debugger 0.9.0 (2015-09-23-21:46) Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html Info : only one transport option; autoselect 'swd' adapter speed: 500 kHz adapter_nsrst_delay: 100 cortex_m reset_config sysresetreq Info : CMSIS-DAP: SWD Supported Info : CMSIS-DAP: JTAG Supported Info : CMSIS-DAP: Interface Initialised (SWD) Info : CMSIS-DAP: FW Version = 01.1F.0118 Info : SWCLK/TCK = 1 SWDIO/TMS = 1 TDI = 1 TDO = 1 nTRST = 0 nRESET = 1 Info : CMSIS-DAP: Interface ready Info : clock speed 500 kHz Info : SWD IDCODE 0x0bc11477 Info : at91samd21g18.cpu: hardware has 4 breakpoints, 2 watchpoints GNU gdb (GNU Tools for ARM Embedded Processors) 7.8.0.20150604-cvs Copyright (C) 2014 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type \"show copying\" and \"show warranty\" for details. This GDB was configured as \"--host=x86_64-apple-darwin10 --target=arm-none-eabi\". Type \"show configuration\" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type \"help\". Type \"apropos word\" to search for commands related to \"word\"... Reading symbols from myproject/bin/arduino_blinky/apps/blinky/blinky.elf...done. target state: halted target halted due to debug-request, current mode: Thread xPSR: 0x21000000 pc: 0x0000030e msp: 0x20008000 Info : accepting 'gdb' connection on tcp/3333 Info : SAMD MCU: SAMD21G18A (256KB Flash, 32KB RAM) 0x0000030e in ?? () (gdb) r The \"remote\" target does not support \"run\". Try \"help target\" or \"continue\". (gdb) c Continuing. NOTE: The 0.0.0 specified after the target name to newt run is the version of the image to load. If you are not providing remote upgrade, and are just developing locally, you can provide 0.0.0 for every image version. If you want the image to run without the debugger connected, simply quit the debugger and restart the board. The image you programmed will come and run on the Arduino on next boot!","title":"Run the Image"},{"location":"os/tutorials/arduino_zero/#watch-the-led-blink","text":"Congratulations! You have created a Mynewt operating system running on the Arduino Zero. The LED right next to the power LED should be blinking. It is toggled by one task running on the Mynewt OS. We have more fun tutorials for you to get your hands dirty. Be bold and try other Blinky-like tutorials or try enabling additional functionality such as remote comms on the current board. If you see anything missing or want to send us feedback, please do so by signing up for appropriate mailing lists on our Community Page . Keep on hacking and blinking!","title":"Watch the LED blink"},{"location":"os/tutorials/blehci_project/","text":"Use HCI access to NimBLE controller This tutorial explains how to use the example application blehci included in the NimBLE stack to talk to the Mynewt NimBLE controller via the Host Controller Interface. You may build the Mynewt image using a laptop running any OS of your choice - Mac, Linux, or Windows. The host used in this specific example is the BlueZ Bluetooth stack. Since BlueZ is a Bluetooth stack for Linux kernel-based family of operating system, the tutorial expects a computer running Linux OS and with BlueZ installed to talk to the board with the Mynewt image. Pre-Requisites Ensure you have installed newt and that the newt command is in your system path. You must have Internet connectivity to fetch remote Mynewt components. If you are not using the Docker container for newt and other tools, you must install the compiler tools to support native compiling to build the project this tutorial creates. You have a board with BLE radio that is supported by Mynewt. We will use an nRF52 Dev board in this tutorial. USB TTL Serial Cable that supports hardware flow control such as ones found at http://www.ftdichip.com/Products/Cables/USBTTLSerial.htm to establish a serial USB connection between the board and the laptop. You have installed a BLE host such as BlueZ on a Linux machine to talk to the nrf52 board running Mynewt. Use sudo apt-get install bluez to install it on your Linux machine. Create a project Use the Newt tool to create a new project directory containing a skeletal Mynewt framework. Change into the newly created directory. Make sure the downloaded version is 0.9.0 or later. $ newt new blehciproj Downloading project skeleton from apache/incubator-mynewt-blinky... Installing skeleton in blehciproj ... Project blehciproj successfully created. $ cd mblehciproj $ newt install -v apache-mynewt-core Downloading repository description for apache-mynewt-core... success! ... apache-mynewt-core successfully installed version 0.9.0-none Create targets You will create two targets - one for the bootloader, the other for the application. Then you will add the definitions for them. Note that you are using the example app blehci for the application target. Set the bsp correctly (nrf52pdk or nrf52dk depending on whether the board is the preview kit or the dev kit, respectively). $ newt target create nrf52_boot $ newt target set nrf52_boot app=@apache-mynewt-core/apps/boot $ newt target set nrf52_boot bsp=@apache-mynewt-core/hw/bsp/nrf52dk $ newt target set nrf52_boot build_profile=optimized $ newt target create myble2 $ newt target set myble2 bsp=@apache-mynewt-core/hw/bsp/nrf52dk $ newt target set myble2 app=@apache-mynewt-core/apps/blehci $ newt target set myble2 build_profile=optimized Check that the targets are defined correctly. $ newt target show targets/my_blinky_sim app=apps/blinky bsp=@apache-mynewt-core/hw/bsp/native build_profile=debug targets/myble2 app=@apache-mynewt-core/apps/blehci bsp=@apache-mynewt-core/hw/bsp/nrf52dk build_profile=optimized targets/nrf52_boot app=@apache-mynewt-core/apps/boot bsp=@apache-mynewt-core/hw/bsp/nrf52dk build_profile=optimized Build targets Then build the two targets. $ newt build nrf52_boot <snip> App successfully built: ./bin/nrf52_boot/apps/boot/boot.elf $ newt build myble2 Compiling hci_common.c Compiling util.c Archiving nimble.a Compiling os.c <snip> Create the app image Generate a signed application image for the myble2 target. The version number is arbitrary. $ newt create-image myble2 1.0.0 App image succesfully generated: ./bin/makerbeacon/apps/bletiny/bletiny.img Build manifest: ./bin/makerbeacon/apps/bletiny/manifest.json Load the image Make sure the USB connector is in place and the power LED on the board is lit. Use the Power ON/OFF switch to reset the board after loading the image. $ newt -v load myble Establish serial connection Attach a serial port to your board by connecting the USB TTL Serial Cable. This should create /dev/ttyUSB0 (or similar) on your machine. Note Certain Linux OS versions have been observed to detect the nrf52 board as a mass storage device and the console access doesn\u2019t work properly. In that case try powering the nrf52 board from your monitor or something other than your Linux computer/laptop when you set up the serial port for HCI communication. Open Bluetooth monitor btmon btmon is a BlueZ test tool to display all HCI commands and events in a human readable format. Start the btmon tool in a terminal window. $ sudo btmon [sudo] password for admin: Bluetooth monitor ver 5.37 Attach the blehci device to BlueZ In a different terminal, attach the blehci device to the BlueZ daemon (substitute the correct /dev filename for ttyUSB0). $ sudo btattach -B /dev/ttyUSB0 -S 115200 Attaching BR/EDR controller to /dev/ttyUSB0 Switched line discipline from 0 to 15 Device index 1 attached Start btmgmt to send commands In a third terminal, start btmgmt. This tool allows you to send commands to the blehci controller. Use the index number that shows up when you btattach in the previous step. $ sudo btmgmt --index 1 [sudo] password for admin: Set your device address (you can substitute any static random address here). [hci1]# static-addr cc:11:11:11:11:11 Static address successfully set Initialize the controller. [hci1]# power on hci1 Set Powered complete, settings: powered le static-addr Begin scanning. [hci1]# find -l Discovery started hci1 type 6 discovering on hci1 dev_found: 58:EF:77:C8:8D:17 type LE Random rssi -78 flags 0x0000 AD flags 0x06 eir_len 23 <snip>","title":"BLE HCI interface"},{"location":"os/tutorials/blehci_project/#use-hci-access-to-nimble-controller","text":"This tutorial explains how to use the example application blehci included in the NimBLE stack to talk to the Mynewt NimBLE controller via the Host Controller Interface. You may build the Mynewt image using a laptop running any OS of your choice - Mac, Linux, or Windows. The host used in this specific example is the BlueZ Bluetooth stack. Since BlueZ is a Bluetooth stack for Linux kernel-based family of operating system, the tutorial expects a computer running Linux OS and with BlueZ installed to talk to the board with the Mynewt image.","title":"Use HCI access to NimBLE controller"},{"location":"os/tutorials/blehci_project/#pre-requisites","text":"Ensure you have installed newt and that the newt command is in your system path. You must have Internet connectivity to fetch remote Mynewt components. If you are not using the Docker container for newt and other tools, you must install the compiler tools to support native compiling to build the project this tutorial creates. You have a board with BLE radio that is supported by Mynewt. We will use an nRF52 Dev board in this tutorial. USB TTL Serial Cable that supports hardware flow control such as ones found at http://www.ftdichip.com/Products/Cables/USBTTLSerial.htm to establish a serial USB connection between the board and the laptop. You have installed a BLE host such as BlueZ on a Linux machine to talk to the nrf52 board running Mynewt. Use sudo apt-get install bluez to install it on your Linux machine.","title":"Pre-Requisites"},{"location":"os/tutorials/blehci_project/#create-a-project","text":"Use the Newt tool to create a new project directory containing a skeletal Mynewt framework. Change into the newly created directory. Make sure the downloaded version is 0.9.0 or later. $ newt new blehciproj Downloading project skeleton from apache/incubator-mynewt-blinky... Installing skeleton in blehciproj ... Project blehciproj successfully created. $ cd mblehciproj $ newt install -v apache-mynewt-core Downloading repository description for apache-mynewt-core... success! ... apache-mynewt-core successfully installed version 0.9.0-none","title":"Create a project"},{"location":"os/tutorials/blehci_project/#create-targets","text":"You will create two targets - one for the bootloader, the other for the application. Then you will add the definitions for them. Note that you are using the example app blehci for the application target. Set the bsp correctly (nrf52pdk or nrf52dk depending on whether the board is the preview kit or the dev kit, respectively). $ newt target create nrf52_boot $ newt target set nrf52_boot app=@apache-mynewt-core/apps/boot $ newt target set nrf52_boot bsp=@apache-mynewt-core/hw/bsp/nrf52dk $ newt target set nrf52_boot build_profile=optimized $ newt target create myble2 $ newt target set myble2 bsp=@apache-mynewt-core/hw/bsp/nrf52dk $ newt target set myble2 app=@apache-mynewt-core/apps/blehci $ newt target set myble2 build_profile=optimized Check that the targets are defined correctly. $ newt target show targets/my_blinky_sim app=apps/blinky bsp=@apache-mynewt-core/hw/bsp/native build_profile=debug targets/myble2 app=@apache-mynewt-core/apps/blehci bsp=@apache-mynewt-core/hw/bsp/nrf52dk build_profile=optimized targets/nrf52_boot app=@apache-mynewt-core/apps/boot bsp=@apache-mynewt-core/hw/bsp/nrf52dk build_profile=optimized","title":"Create targets"},{"location":"os/tutorials/blehci_project/#build-targets","text":"Then build the two targets. $ newt build nrf52_boot <snip> App successfully built: ./bin/nrf52_boot/apps/boot/boot.elf $ newt build myble2 Compiling hci_common.c Compiling util.c Archiving nimble.a Compiling os.c <snip>","title":"Build targets"},{"location":"os/tutorials/blehci_project/#create-the-app-image","text":"Generate a signed application image for the myble2 target. The version number is arbitrary. $ newt create-image myble2 1.0.0 App image succesfully generated: ./bin/makerbeacon/apps/bletiny/bletiny.img Build manifest: ./bin/makerbeacon/apps/bletiny/manifest.json","title":"Create the app image"},{"location":"os/tutorials/blehci_project/#load-the-image","text":"Make sure the USB connector is in place and the power LED on the board is lit. Use the Power ON/OFF switch to reset the board after loading the image. $ newt -v load myble","title":"Load the image"},{"location":"os/tutorials/blehci_project/#establish-serial-connection","text":"Attach a serial port to your board by connecting the USB TTL Serial Cable. This should create /dev/ttyUSB0 (or similar) on your machine. Note Certain Linux OS versions have been observed to detect the nrf52 board as a mass storage device and the console access doesn\u2019t work properly. In that case try powering the nrf52 board from your monitor or something other than your Linux computer/laptop when you set up the serial port for HCI communication.","title":"Establish serial connection"},{"location":"os/tutorials/blehci_project/#open-bluetooth-monitor-btmon","text":"btmon is a BlueZ test tool to display all HCI commands and events in a human readable format. Start the btmon tool in a terminal window. $ sudo btmon [sudo] password for admin: Bluetooth monitor ver 5.37","title":"Open Bluetooth monitor btmon"},{"location":"os/tutorials/blehci_project/#attach-the-blehci-device-to-bluez","text":"In a different terminal, attach the blehci device to the BlueZ daemon (substitute the correct /dev filename for ttyUSB0). $ sudo btattach -B /dev/ttyUSB0 -S 115200 Attaching BR/EDR controller to /dev/ttyUSB0 Switched line discipline from 0 to 15 Device index 1 attached","title":"Attach the blehci device to BlueZ"},{"location":"os/tutorials/blehci_project/#start-btmgmt-to-send-commands","text":"In a third terminal, start btmgmt. This tool allows you to send commands to the blehci controller. Use the index number that shows up when you btattach in the previous step. $ sudo btmgmt --index 1 [sudo] password for admin: Set your device address (you can substitute any static random address here). [hci1]# static-addr cc:11:11:11:11:11 Static address successfully set Initialize the controller. [hci1]# power on hci1 Set Powered complete, settings: powered le static-addr Begin scanning. [hci1]# find -l Discovery started hci1 type 6 discovering on hci1 dev_found: 58:EF:77:C8:8D:17 type LE Random rssi -78 flags 0x0000 AD flags 0x06 eir_len 23 <snip>","title":"Start btmgmt to send commands"},{"location":"os/tutorials/bletiny_project/","text":"Check stats on a BLE device This tutorial explains how to run an example BLE app on a board and command it to scan and spew some stats. The stats will be seen over a serial port, not a BLE wireless connection. Pre-Requisites Ensure you have installed newt and that the newt command is in your system path. You must have Internet connectivity to fetch remote Mynewt components. You must install the compiler tools to support native compiling to build the project this tutorial creates. You must install the Segger JLINK package to load your project on the board. You have a board with BLE radio that is supported by Mynewt. We will use an nRF52 Dev board in this tutorial. Cable to establish a serial USB connection between the board and the laptop Create a project Use the Newt tool to create a new project directory containing a skeletal Mynewt framework. Change into the newly created directory. $ newt new myapp1 Downloading project skeleton from apache/incubator-mynewt-blinky... Installing skeleton in myapp1... Project myapp1 successfully created. $ cd myapp1 $ newt install -v apache-mynewt-core Downloading repository description for apache-mynewt-core... success! ... apache-mynewt-core successfully installed version 0.7.9-none Create targets You will create two targets - one for the bootloader, the other for the application. $ newt target create myble Target targets/myble successfully created $ newt target create nrf52_boot Target targets/myble successfully created $ newt target show targets/my_blinky_sim app=apps/blinky bsp=@apache-mynewt-core/hw/bsp/native build_profile=debug targets/myble targets/nrf52_boot Define the targets further. Note that you are using the example app bletiny for the application target. Set the bsp correctly (nrf52pdk or nrf52dk depending on whether the board is the preview kit or the dev kit, respectively. Look on the top of your board, if you see PCA100040, use the nrf52dk version, otherwide use the nrf52pdk version). $ newt target set myble bsp=@apache-mynewt-core/hw/bsp/nrf52pdk Target targets/myble successfully set target.bsp to @apache-mynewt-core/hw/bsp/nrf52pdk $ newt target set myble app=@apache-mynewt-core/apps/bletiny Target targets/myble successfully set target.app to @apache-mynewt-core/apps/bletiny $ newt target set myble build_profile=optimized Target targets/myble successfully set target.build_profile to optimized $ newt target set myble cflags=-DSTATS_NAME_ENABLE Target targets/myble successfully set pkg.cflags to DSTATS_NAME_ENABLE Use the same newt target set command to set the following definition for the bootloader target -- again, make sure you use the correct value for the bsp based on which version of the board you have.. targets/nrf52_boot app=@apache-mynewt-core/apps/boot bsp=@apache-mynewt-core/hw/bsp/nrf52pdk build_profile=optimized You should have the following targets by the end of this step. $ newt target show targets/my_blinky_sim app=apps/blinky bsp=@apache-mynewt-core/hw/bsp/native build_profile=debug targets/myble app=@apache-mynewt-core/apps/bletiny bsp=@apache-mynewt-core/hw/bsp/nrf52pdk build_profile=optimized cflags=-DSTATS_NAME_ENABLE targets/nrf52_boot app=@apache-mynewt-core/apps/boot bsp=@apache-mynewt-core/hw/bsp/nrf52pdk build_profile=optimized Build targets Then build the two targets. $ newt build nrf52_boot <snip> App successfully built: ./bin/nrf52_boot/apps/boot/boot.elf $ newt build myble Compiling hci_common.c Compiling util.c Archiving nimble.a Compiling os.c <snip> Create the app image Generate a signed application image for the myble target. The version number is arbitrary. $ newt create-image myble 1.0.0 App image succesfully generated: ./bin/makerbeacon/apps/bletiny/bletiny.img Build manifest: ./bin/makerbeacon/apps/bletiny/manifest.json Load the image Make sure the USB connector is in place and the power LED on the board is lit. Use the Power ON/OFF switch to reset the board after loading the image. $ newt load nrf52_boot $ newt load myble Establish serial connection You will now look for some BLE related stats over a serial connection and see the radio is actually working. The picture below shows a serial connector set up. Pin PA.08 is RX and pin PA.06 is TX. Make sure TX from the NRF52 goes to RX on your Serial board, and that RX on the NRF52 goes to TX on your Serial Board. You may use any terminal emulation program to communicate with the board. This tutorial shows a Minicom set up. You will have to find out what the usbserial port number is on your laptop, of course. $ minicom -D /dev/tty.usbserial-AJ03HAQQ When the Minicom screen comes up, type in ? Welcome to minicom 2.7 OPTIONS: Compiled on Nov 24 2015, 16:14:21. Port /dev/tty.usbserial-AJ03HAQQ, 09:57:17 Press Meta-Z for help on special keys ? 4828455:log echo ? tasks mempools date 4828457:stat b Try the stat command. stat 4973017:Must specify a statistic name to dump, possible names are: 4973021: stat 4973022: ble_l2cap 4973024: ble_att 4973026: ble_gap 4973027: ble_gattc 4973029: ble_gatts 4973031: ble_hs 4973032: ble_ll_conn 4973034: ble_ll Try specifying a BLE related stat, for example ble_ll . You should see some HCI (Host Controller Interface) command counts. stat ble_ll 4986297:hci_cmds: 5 4986297:hci_cmd_errs: 0 4986299:hci_events_sent: 5 4986301:bad_ll_state: 0 4986303:bad_acl_hdr: 0 4986306:rx_adv_pdu_crc_ok: 0 4986308:rx_adv_pdu_crc_err: 0 4986311:rx_adv_bytes_crc_ok: 0 4986314:rx_adv_bytes_crc_err: 0 4986317:rx_data_pdu_crc_ok: 0 4986319:rx_data_pdu_crc_err: 0 4986322:rx_data_bytes_crc_ok: 0 <snip> For a more exciting output, try scanning your surroundings for BLE adverstisements. The HCI command shown below specifies a scan duration in ms, sets discovery mode to general (as opposed to limited), the filter to no-whitelist, and type of scan to passive. You should see some scan data flying by! b scan dur=10000 disc=gen filt=no_wl type=passive 5301227:[ts=5301227ssb, mod=4 level=1] host_hci_cmd_send: ogf=0x08 ocf=0x0b len=7 5301233:[ts=5301233ssb, mod=4 level=1] Command Complete: cmd_pkts=1 ogf=0x8 ocf=0xb status=0 5301241:[ts=5301241ssb, mod=4 level=1] host_hci_cmd_send: ogf=0x08 ocf=0x0c len=2 5301248:[ts=5301248ssb, mod=4 level=1] Command Complete: cmd_pkts=1 ogf=0x8 ocf=0xc status=0 GAP procedure initiated: discovery; disc_mode=2 filter_policyLE advertising report. len=38 num=1 evtype=3 addr9 5301270:[ts=5301270ssb, mod=4 level=1] 02 01 06 03 03 aa fe 12 5301276:[ts=5301276ssb, mod=4 level=1] 16 aa fe 10 f6 02 67 2e 5301281:[ts=5301281ssb, mod=4 level=1] 63 6f 2f 62 65 61 63 6f 5301287:[ts=5301287ssb, mod=4 level=1] 6e 73 5301291:[ts=5301291ssb, mod=64 level=2] received advertisement; event_type=3 addr_type=1 addr=0xa0:0x0d:0xec:0: 5301316:[ts=5301316ssb, mod=64 level=2] flags=0x06 5301321:[ts=5301321ssb, mod=64 level=2] uuids16(complete)=0xfeaa 5301327:[ts=5301327ssb, mod=64 level=2] svc_data_uuid16= <snip> If you're still not seeing any output from the device, try running the debugger and see if you are seeing the program execute properly. $ newt debug myble Debugging ./bin/myble/apps/bletiny/bletiny.elf GNU gdb (GNU Tools for ARM Embedded Processors) 7.6.0.20140731-cvs Copyright (C) 2013 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type \"show copying\" and \"show warranty\" for details. This GDB was configured as \"--host=x86_64-apple-darwin10 --target=arm-none-eabi\". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>... Reading symbols from ./bin/myble/apps/bletiny/bletiny.elf...done. 0x00002f08 in ?? () (gdb) monitor reset Resetting target (gdb) c Continuing. ^C Program received signal SIGTRAP, Trace/breakpoint trap. os_tick_idle (ticks=1000) at hal_os_tick.c:117 117 if (ticks > 0) { (gdb) p g_os_time $1 = 37991 (gdb) c Continuing. ^C Program received signal SIGTRAP, Trace/breakpoint trap. os_tick_idle (ticks=1000) at hal_os_tick.c:117 117 if (ticks > 0) { (gdb) p g_os_time $2 = 51888 (gdb) c Continuing. You should see the g_os_time advancing as above, as each os time tick is 1ms. If the system ticks aren't advancing, then nothing's actually running.","title":"BLE app to check stats via console"},{"location":"os/tutorials/bletiny_project/#check-stats-on-a-ble-device","text":"This tutorial explains how to run an example BLE app on a board and command it to scan and spew some stats. The stats will be seen over a serial port, not a BLE wireless connection.","title":"Check stats on a BLE device"},{"location":"os/tutorials/bletiny_project/#pre-requisites","text":"Ensure you have installed newt and that the newt command is in your system path. You must have Internet connectivity to fetch remote Mynewt components. You must install the compiler tools to support native compiling to build the project this tutorial creates. You must install the Segger JLINK package to load your project on the board. You have a board with BLE radio that is supported by Mynewt. We will use an nRF52 Dev board in this tutorial. Cable to establish a serial USB connection between the board and the laptop","title":"Pre-Requisites"},{"location":"os/tutorials/bletiny_project/#create-a-project","text":"Use the Newt tool to create a new project directory containing a skeletal Mynewt framework. Change into the newly created directory. $ newt new myapp1 Downloading project skeleton from apache/incubator-mynewt-blinky... Installing skeleton in myapp1... Project myapp1 successfully created. $ cd myapp1 $ newt install -v apache-mynewt-core Downloading repository description for apache-mynewt-core... success! ... apache-mynewt-core successfully installed version 0.7.9-none","title":"Create a project"},{"location":"os/tutorials/bletiny_project/#create-targets","text":"You will create two targets - one for the bootloader, the other for the application. $ newt target create myble Target targets/myble successfully created $ newt target create nrf52_boot Target targets/myble successfully created $ newt target show targets/my_blinky_sim app=apps/blinky bsp=@apache-mynewt-core/hw/bsp/native build_profile=debug targets/myble targets/nrf52_boot Define the targets further. Note that you are using the example app bletiny for the application target. Set the bsp correctly (nrf52pdk or nrf52dk depending on whether the board is the preview kit or the dev kit, respectively. Look on the top of your board, if you see PCA100040, use the nrf52dk version, otherwide use the nrf52pdk version). $ newt target set myble bsp=@apache-mynewt-core/hw/bsp/nrf52pdk Target targets/myble successfully set target.bsp to @apache-mynewt-core/hw/bsp/nrf52pdk $ newt target set myble app=@apache-mynewt-core/apps/bletiny Target targets/myble successfully set target.app to @apache-mynewt-core/apps/bletiny $ newt target set myble build_profile=optimized Target targets/myble successfully set target.build_profile to optimized $ newt target set myble cflags=-DSTATS_NAME_ENABLE Target targets/myble successfully set pkg.cflags to DSTATS_NAME_ENABLE Use the same newt target set command to set the following definition for the bootloader target -- again, make sure you use the correct value for the bsp based on which version of the board you have.. targets/nrf52_boot app=@apache-mynewt-core/apps/boot bsp=@apache-mynewt-core/hw/bsp/nrf52pdk build_profile=optimized You should have the following targets by the end of this step. $ newt target show targets/my_blinky_sim app=apps/blinky bsp=@apache-mynewt-core/hw/bsp/native build_profile=debug targets/myble app=@apache-mynewt-core/apps/bletiny bsp=@apache-mynewt-core/hw/bsp/nrf52pdk build_profile=optimized cflags=-DSTATS_NAME_ENABLE targets/nrf52_boot app=@apache-mynewt-core/apps/boot bsp=@apache-mynewt-core/hw/bsp/nrf52pdk build_profile=optimized","title":"Create targets"},{"location":"os/tutorials/bletiny_project/#build-targets","text":"Then build the two targets. $ newt build nrf52_boot <snip> App successfully built: ./bin/nrf52_boot/apps/boot/boot.elf $ newt build myble Compiling hci_common.c Compiling util.c Archiving nimble.a Compiling os.c <snip>","title":"Build targets"},{"location":"os/tutorials/bletiny_project/#create-the-app-image","text":"Generate a signed application image for the myble target. The version number is arbitrary. $ newt create-image myble 1.0.0 App image succesfully generated: ./bin/makerbeacon/apps/bletiny/bletiny.img Build manifest: ./bin/makerbeacon/apps/bletiny/manifest.json","title":"Create the app image"},{"location":"os/tutorials/bletiny_project/#load-the-image","text":"Make sure the USB connector is in place and the power LED on the board is lit. Use the Power ON/OFF switch to reset the board after loading the image. $ newt load nrf52_boot $ newt load myble","title":"Load the image"},{"location":"os/tutorials/bletiny_project/#establish-serial-connection","text":"You will now look for some BLE related stats over a serial connection and see the radio is actually working. The picture below shows a serial connector set up. Pin PA.08 is RX and pin PA.06 is TX. Make sure TX from the NRF52 goes to RX on your Serial board, and that RX on the NRF52 goes to TX on your Serial Board. You may use any terminal emulation program to communicate with the board. This tutorial shows a Minicom set up. You will have to find out what the usbserial port number is on your laptop, of course. $ minicom -D /dev/tty.usbserial-AJ03HAQQ When the Minicom screen comes up, type in ? Welcome to minicom 2.7 OPTIONS: Compiled on Nov 24 2015, 16:14:21. Port /dev/tty.usbserial-AJ03HAQQ, 09:57:17 Press Meta-Z for help on special keys ? 4828455:log echo ? tasks mempools date 4828457:stat b Try the stat command. stat 4973017:Must specify a statistic name to dump, possible names are: 4973021: stat 4973022: ble_l2cap 4973024: ble_att 4973026: ble_gap 4973027: ble_gattc 4973029: ble_gatts 4973031: ble_hs 4973032: ble_ll_conn 4973034: ble_ll Try specifying a BLE related stat, for example ble_ll . You should see some HCI (Host Controller Interface) command counts. stat ble_ll 4986297:hci_cmds: 5 4986297:hci_cmd_errs: 0 4986299:hci_events_sent: 5 4986301:bad_ll_state: 0 4986303:bad_acl_hdr: 0 4986306:rx_adv_pdu_crc_ok: 0 4986308:rx_adv_pdu_crc_err: 0 4986311:rx_adv_bytes_crc_ok: 0 4986314:rx_adv_bytes_crc_err: 0 4986317:rx_data_pdu_crc_ok: 0 4986319:rx_data_pdu_crc_err: 0 4986322:rx_data_bytes_crc_ok: 0 <snip> For a more exciting output, try scanning your surroundings for BLE adverstisements. The HCI command shown below specifies a scan duration in ms, sets discovery mode to general (as opposed to limited), the filter to no-whitelist, and type of scan to passive. You should see some scan data flying by! b scan dur=10000 disc=gen filt=no_wl type=passive 5301227:[ts=5301227ssb, mod=4 level=1] host_hci_cmd_send: ogf=0x08 ocf=0x0b len=7 5301233:[ts=5301233ssb, mod=4 level=1] Command Complete: cmd_pkts=1 ogf=0x8 ocf=0xb status=0 5301241:[ts=5301241ssb, mod=4 level=1] host_hci_cmd_send: ogf=0x08 ocf=0x0c len=2 5301248:[ts=5301248ssb, mod=4 level=1] Command Complete: cmd_pkts=1 ogf=0x8 ocf=0xc status=0 GAP procedure initiated: discovery; disc_mode=2 filter_policyLE advertising report. len=38 num=1 evtype=3 addr9 5301270:[ts=5301270ssb, mod=4 level=1] 02 01 06 03 03 aa fe 12 5301276:[ts=5301276ssb, mod=4 level=1] 16 aa fe 10 f6 02 67 2e 5301281:[ts=5301281ssb, mod=4 level=1] 63 6f 2f 62 65 61 63 6f 5301287:[ts=5301287ssb, mod=4 level=1] 6e 73 5301291:[ts=5301291ssb, mod=64 level=2] received advertisement; event_type=3 addr_type=1 addr=0xa0:0x0d:0xec:0: 5301316:[ts=5301316ssb, mod=64 level=2] flags=0x06 5301321:[ts=5301321ssb, mod=64 level=2] uuids16(complete)=0xfeaa 5301327:[ts=5301327ssb, mod=64 level=2] svc_data_uuid16= <snip> If you're still not seeing any output from the device, try running the debugger and see if you are seeing the program execute properly. $ newt debug myble Debugging ./bin/myble/apps/bletiny/bletiny.elf GNU gdb (GNU Tools for ARM Embedded Processors) 7.6.0.20140731-cvs Copyright (C) 2013 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type \"show copying\" and \"show warranty\" for details. This GDB was configured as \"--host=x86_64-apple-darwin10 --target=arm-none-eabi\". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>... Reading symbols from ./bin/myble/apps/bletiny/bletiny.elf...done. 0x00002f08 in ?? () (gdb) monitor reset Resetting target (gdb) c Continuing. ^C Program received signal SIGTRAP, Trace/breakpoint trap. os_tick_idle (ticks=1000) at hal_os_tick.c:117 117 if (ticks > 0) { (gdb) p g_os_time $1 = 37991 (gdb) c Continuing. ^C Program received signal SIGTRAP, Trace/breakpoint trap. os_tick_idle (ticks=1000) at hal_os_tick.c:117 117 if (ticks > 0) { (gdb) p g_os_time $2 = 51888 (gdb) c Continuing. You should see the g_os_time advancing as above, as each os time tick is 1ms. If the system ticks aren't advancing, then nothing's actually running.","title":"Establish serial connection"},{"location":"os/tutorials/blinky_primo/","text":"Blinky, your \"Hello World!\", on Arduino Primo Objective Learn how to use packages from a default application repository of Mynewt to build your first Hello World application (Blinky) on a target board. Once built using the newt tool, this application will blink the LED lights on the target board. Create a project with a simple app that blinks an LED on the Arduino Primo board. Download the application to the target and watch it blink! Note that the Mynewt OS will run on the nRF52 chip in the Arduino Primo board. However, the board support package for the Arduino Primo is different from the nRF52 dev kit board support package. Hardware and Software needed Arduino Primo Laptop running Mac OS A micro USB 2.0 cable to power the Arduino primo board It is assumed you have already installed newt tool. It is assumed you already installed native tools as described here Debugger - choose one of the two options below. Option 1 requires additional hardware but very easy to set up. Option 2 is free software install but not as simple as Option 1. Option 1 Segger J-Link Debug Probe - any model (this tutorial has been tested with J-Link EDU and J-Link Pro) J-Link 9 pin Cortex-M Adapter that allows JTAG, SWD and SWO connections between J-Link and Cortex M based target hardware systems Option 2 No additional hardware is required but a version of OpenOCD 0.10.0 that is currently in development needs to be installed. A patch for the nRF52 has been applied to the OpenOCD code in development and a tarball has been made available for download here . Untar it. From the top of the directory tree (\"openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4\"), build it using the following configuration: $./configure --enable-cmsis-dap --enable-openjtag_ftdi --enable-jlink --enable-stlink Then run make and sudo make install . This step takes minutes, so be patient. $ openocd -v Open On-Chip Debugger 0.10.0-dev-snapshot (2016-05-20-10:43) Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html Next, make sure that you have checked out the newt develop branch and rebuilt newt. $ cd $GOPATH/src/mynewt.apache.org/newt $ git checkout develop $ git pull $ cd newt $ go install Note: This step can be removed once the changes have been pushed to master. You can now use openocd to upload to Arduino Primo board via the USB port itself. Install jlinkEXE In order to be able to communicate with the SEGGER J-Link debugger on the dev board, you have to download and install the J-Link GDB Server software on to your laptop. You may download the \"Software and documentation pack for Mac OS X\" from https://www.segger.com/jlink-software.html . Create a project. Create a new project to hold your work. For a deeper understanding, you can read about project creation in Get Started -- Creating Your First Project or just follow the commands below. $ mkdir ~/dev $ cd ~/dev $ newt new myproj Downloading project skeleton from apache/incubator-mynewt-blinky... Installing skeleton in myproj... Project myproj successfully created. $ cd myproj $ newt install -v apache-mynewt-core Downloading repository description for apache-mynewt-core... success! ... apache-mynewt-core successfully installed version 0.9.0 If you are working with 0.9.0 release (and not any subsequent releases), you will have to instruct newt to download code for the Arduino Primo Board Support Package (bsp) from the develop branch. You first edit the project.yml file in your project directory to change vers:0-latest to 0-dev : <snip> # repository.apache-mynewt-core: type: github vers: 0-dev user: apache repo: incubator-mynewt-core Then you run newt upgrade : $ newt upgrade apache-mynewt-core Would you like to upgrade repository apache-mynewt-core from 0.9.0-none to 0.0.0-none ? [Yn] Y Note : With the next release, the Arduino Primo bsp will be included in the main release package. The above edit and newt upgrade step will not be required. Create the targets Create two targets - one for the bootloader and one for the Primo board. $ newt target create primoblinky $ newt target set primoblinky app=@apache-mynewt-core/apps/blinky bsp=@apache-mynewt-core/hw/bsp/arduino_primo_nrf52 build_profile=debug $ newt target create primo_boot $ newt target set primo_boot app=@apache-mynewt-core/apps/boot bsp=@apache-mynewt-core/hw/bsp/arduino_primo_nrf52 build_profile=optimized $ newt target show targets/my_blinky_sim app=apps/blinky bsp=@apache-mynewt-core/hw/bsp/native build_profile=debug targets/primo_boot app=@apache-mynewt-core/apps/boot bsp=@apache-mynewt-core/hw/bsp/arduino_primo_nrf52 build_profile=optimized targets/primoblinky app=@apache-mynewt-core/apps/blinky bsp=@apache-mynewt-core/hw/bsp/arduino_primo_nrf52 build_profile=optimized If you are using openocd you must set the openocd_debug feature for both primo_boot and primoblinky. $ newt target set primo_boot features=openocd_debug $ newt target set primoblinky features=openocd_debug Build the target executables $ newt build primo_boot <snip> Compiling log_shell.c Archiving log.a Linking boot.elf App successfully built: ~/dev/myproj/bin/primo_boot/apps/boot/boot.elf $ newt build primoblinky <snip> Compiling stats_shell.c Archiving stats.a Linking blinky.elf App successfully built: ~/dev/myproj/bin/primoblinky/apps/blinky/blinky.elf Sign and create the blinky application image You must sign and version your application image to download it using newt to the board. Use the newt create-image command to perform this action. You may assign an arbitrary version (e.g. 1.0.0) to the image. $ newt create-image primoblinky 1.0.0 Connect the board Connect the Segger J-Link debug probe to the JTAG port on the Primo board using the Jlink 9-pin adapter and cable. Note that there are two JTAG ports on the board. Use the one nearest to the reset button as shown in the picture. Also use a micro USB 2.0 cable to connect the Primo board to one of your laptop's USB host ports. Note: If you are going the OpenOCD route, you do not need to attach this connector. Download to the target Download the bootloader first and then the blinky executable to the target platform. Don't forget to reset the board if you don't see the LED blinking right away. If the reset button doesn't work, powercycle the board! $ newt -v load primo_boot $ newt -v load primoblinky Note: If you want to erase the flash and load the image again, you can use JLinkExe to issue an erase command. $ JLinkExe -device nRF52 -speed 4000 -if SWD SEGGER J-Link Commander V5.12c (Compiled Apr 21 2016 16:05:51) DLL version V5.12c, compiled Apr 21 2016 16:05:45 Connecting to J-Link via USB...O.K. Firmware: J-Link OB-SAM3U128-V2-NordicSemi compiled Mar 15 2016 18:03:17 Hardware version: V1.00 S/N: 682863966 VTref = 3.300V Type \"connect\" to establish a target connection, '?' for help J-Link>erase Cortex-M4 identified. Erasing device (0;?i?)... Comparing flash [100%] Done. Erasing flash [100%] Done. Verifying flash [100%] Done. J-Link: Flash download: Total time needed: 0.363s (Prepare: 0.093s, Compare: 0.000s, Erase: 0.262s, Program: 0.000s, Verify: 0.000s, Restore: 0.008s) Erasing done. J-Link>exit $ Conclusion You have created, setup, compiled, loaded, and ran your first mynewt application for an Arduino Primo board. We have more fun tutorials for you to get your hands dirty. Be bold and work on the OS with tutorials on writing a test suite or try enabling additional functionality such as remote comms or Bluetooth Low Energy on your current board. If you see anything missing or want to send us feedback, please do so by signing up for appropriate mailing lists on our Community Page . Keep on hacking and blinking!","title":"Blinky on Arduino Primo"},{"location":"os/tutorials/blinky_primo/#blinky-your-hello-world-on-arduino-primo","text":"","title":"Blinky, your \"Hello World!\", on Arduino Primo"},{"location":"os/tutorials/blinky_primo/#objective","text":"Learn how to use packages from a default application repository of Mynewt to build your first Hello World application (Blinky) on a target board. Once built using the newt tool, this application will blink the LED lights on the target board. Create a project with a simple app that blinks an LED on the Arduino Primo board. Download the application to the target and watch it blink! Note that the Mynewt OS will run on the nRF52 chip in the Arduino Primo board. However, the board support package for the Arduino Primo is different from the nRF52 dev kit board support package.","title":"Objective"},{"location":"os/tutorials/blinky_primo/#hardware-and-software-needed","text":"Arduino Primo Laptop running Mac OS A micro USB 2.0 cable to power the Arduino primo board It is assumed you have already installed newt tool. It is assumed you already installed native tools as described here Debugger - choose one of the two options below. Option 1 requires additional hardware but very easy to set up. Option 2 is free software install but not as simple as Option 1.","title":"Hardware and Software needed"},{"location":"os/tutorials/blinky_primo/#option-1","text":"Segger J-Link Debug Probe - any model (this tutorial has been tested with J-Link EDU and J-Link Pro) J-Link 9 pin Cortex-M Adapter that allows JTAG, SWD and SWO connections between J-Link and Cortex M based target hardware systems","title":"Option 1"},{"location":"os/tutorials/blinky_primo/#option-2","text":"No additional hardware is required but a version of OpenOCD 0.10.0 that is currently in development needs to be installed. A patch for the nRF52 has been applied to the OpenOCD code in development and a tarball has been made available for download here . Untar it. From the top of the directory tree (\"openocd-code-89bf96ffe6ac66c80407af8383b9d5adc0dc35f4\"), build it using the following configuration: $./configure --enable-cmsis-dap --enable-openjtag_ftdi --enable-jlink --enable-stlink Then run make and sudo make install . This step takes minutes, so be patient. $ openocd -v Open On-Chip Debugger 0.10.0-dev-snapshot (2016-05-20-10:43) Licensed under GNU GPL v2 For bug reports, read http://openocd.org/doc/doxygen/bugs.html Next, make sure that you have checked out the newt develop branch and rebuilt newt. $ cd $GOPATH/src/mynewt.apache.org/newt $ git checkout develop $ git pull $ cd newt $ go install Note: This step can be removed once the changes have been pushed to master. You can now use openocd to upload to Arduino Primo board via the USB port itself.","title":"Option 2"},{"location":"os/tutorials/blinky_primo/#install-jlinkexe","text":"In order to be able to communicate with the SEGGER J-Link debugger on the dev board, you have to download and install the J-Link GDB Server software on to your laptop. You may download the \"Software and documentation pack for Mac OS X\" from https://www.segger.com/jlink-software.html .","title":"Install jlinkEXE"},{"location":"os/tutorials/blinky_primo/#create-a-project","text":"Create a new project to hold your work. For a deeper understanding, you can read about project creation in Get Started -- Creating Your First Project or just follow the commands below. $ mkdir ~/dev $ cd ~/dev $ newt new myproj Downloading project skeleton from apache/incubator-mynewt-blinky... Installing skeleton in myproj... Project myproj successfully created. $ cd myproj $ newt install -v apache-mynewt-core Downloading repository description for apache-mynewt-core... success! ... apache-mynewt-core successfully installed version 0.9.0 If you are working with 0.9.0 release (and not any subsequent releases), you will have to instruct newt to download code for the Arduino Primo Board Support Package (bsp) from the develop branch. You first edit the project.yml file in your project directory to change vers:0-latest to 0-dev : <snip> # repository.apache-mynewt-core: type: github vers: 0-dev user: apache repo: incubator-mynewt-core Then you run newt upgrade : $ newt upgrade apache-mynewt-core Would you like to upgrade repository apache-mynewt-core from 0.9.0-none to 0.0.0-none ? [Yn] Y Note : With the next release, the Arduino Primo bsp will be included in the main release package. The above edit and newt upgrade step will not be required.","title":"Create a project."},{"location":"os/tutorials/blinky_primo/#create-the-targets","text":"Create two targets - one for the bootloader and one for the Primo board. $ newt target create primoblinky $ newt target set primoblinky app=@apache-mynewt-core/apps/blinky bsp=@apache-mynewt-core/hw/bsp/arduino_primo_nrf52 build_profile=debug $ newt target create primo_boot $ newt target set primo_boot app=@apache-mynewt-core/apps/boot bsp=@apache-mynewt-core/hw/bsp/arduino_primo_nrf52 build_profile=optimized $ newt target show targets/my_blinky_sim app=apps/blinky bsp=@apache-mynewt-core/hw/bsp/native build_profile=debug targets/primo_boot app=@apache-mynewt-core/apps/boot bsp=@apache-mynewt-core/hw/bsp/arduino_primo_nrf52 build_profile=optimized targets/primoblinky app=@apache-mynewt-core/apps/blinky bsp=@apache-mynewt-core/hw/bsp/arduino_primo_nrf52 build_profile=optimized If you are using openocd you must set the openocd_debug feature for both primo_boot and primoblinky. $ newt target set primo_boot features=openocd_debug $ newt target set primoblinky features=openocd_debug","title":"Create the targets"},{"location":"os/tutorials/blinky_primo/#build-the-target-executables","text":"$ newt build primo_boot <snip> Compiling log_shell.c Archiving log.a Linking boot.elf App successfully built: ~/dev/myproj/bin/primo_boot/apps/boot/boot.elf $ newt build primoblinky <snip> Compiling stats_shell.c Archiving stats.a Linking blinky.elf App successfully built: ~/dev/myproj/bin/primoblinky/apps/blinky/blinky.elf","title":"Build the target executables"},{"location":"os/tutorials/blinky_primo/#sign-and-create-the-blinky-application-image","text":"You must sign and version your application image to download it using newt to the board. Use the newt create-image command to perform this action. You may assign an arbitrary version (e.g. 1.0.0) to the image. $ newt create-image primoblinky 1.0.0","title":"Sign and create the blinky application image"},{"location":"os/tutorials/blinky_primo/#connect-the-board","text":"Connect the Segger J-Link debug probe to the JTAG port on the Primo board using the Jlink 9-pin adapter and cable. Note that there are two JTAG ports on the board. Use the one nearest to the reset button as shown in the picture. Also use a micro USB 2.0 cable to connect the Primo board to one of your laptop's USB host ports. Note: If you are going the OpenOCD route, you do not need to attach this connector.","title":"Connect the board"},{"location":"os/tutorials/blinky_primo/#download-to-the-target","text":"Download the bootloader first and then the blinky executable to the target platform. Don't forget to reset the board if you don't see the LED blinking right away. If the reset button doesn't work, powercycle the board! $ newt -v load primo_boot $ newt -v load primoblinky Note: If you want to erase the flash and load the image again, you can use JLinkExe to issue an erase command. $ JLinkExe -device nRF52 -speed 4000 -if SWD SEGGER J-Link Commander V5.12c (Compiled Apr 21 2016 16:05:51) DLL version V5.12c, compiled Apr 21 2016 16:05:45 Connecting to J-Link via USB...O.K. Firmware: J-Link OB-SAM3U128-V2-NordicSemi compiled Mar 15 2016 18:03:17 Hardware version: V1.00 S/N: 682863966 VTref = 3.300V Type \"connect\" to establish a target connection, '?' for help J-Link>erase Cortex-M4 identified. Erasing device (0;?i?)... Comparing flash [100%] Done. Erasing flash [100%] Done. Verifying flash [100%] Done. J-Link: Flash download: Total time needed: 0.363s (Prepare: 0.093s, Compare: 0.000s, Erase: 0.262s, Program: 0.000s, Verify: 0.000s, Restore: 0.008s) Erasing done. J-Link>exit $","title":"Download to the target"},{"location":"os/tutorials/blinky_primo/#conclusion","text":"You have created, setup, compiled, loaded, and ran your first mynewt application for an Arduino Primo board. We have more fun tutorials for you to get your hands dirty. Be bold and work on the OS with tutorials on writing a test suite or try enabling additional functionality such as remote comms or Bluetooth Low Energy on your current board. If you see anything missing or want to send us feedback, please do so by signing up for appropriate mailing lists on our Community Page . Keep on hacking and blinking!","title":"Conclusion"},{"location":"os/tutorials/blinky_sram_olimex/","text":"Run Blinky from SRAM without bootloader Objective To download an application image directly into the embedded SRAM in the microcontroller and run it without the bootloader. This tutorial describes how you do it on an Olimex STM32 board. What you need STM32-E407 development board from Olimex. You can order it from http://www.mouser.com , http://www.digikey.com , and other places. ARM-USB-TINY-H connector with JTAG interface for debugging ARM microcontrollers (comes with the ribbon cable to hook up to the board) USB A-B type cable to connect the debugger to your personal computer Personal Computer with Mac OS (Mac: OS X Yosemite Version 10.10.5) or Linux box (Ubuntu 14.10: Utopic Unicorn) An account on Github repository and git installed on your computer. It is assumed you have already installed newt tool. It is assumed you already installed native tools as described here Also, we assume that you're familiar with UNIX shells. Let's gets started! Prepare the Software Make sure the PATH environment variable includes the $HOME/dev/go/bin directory. Create a project Create a new project to hold your work. For a deeper understanding, you can read about project creation in Get Started -- Creating Your First Project or just follow the commands below. $ mkdir ~/dev $ cd ~/dev $ newt new myproj Downloading project skeleton from apache/incubator-mynewt-blinky... Installing skeleton in myproj... Project myproj successfully created. $cd myproj $ newt install -v apache-mynewt-core Downloading repository description for apache-mynewt-core... success! ... apache-mynewt-core successfully installed version 0.7.9-none Create a target Change directory to ~/dev/myproj directory and define the blinky target inside myproj, using the newt tool. Starting with the target name, assign specific aspects of the project, as shown below, to pull the appropriate packages and build the right bundle or list for the board. For example, we set the build_profile, board support package (bsp), and app. $ newt target create blinky $ newt target set blinky build_profile=debug $ newt target set blinky bsp=@apache-mynewt-core/hw/bsp/olimex_stm32-e407_devboard $ newt target set blinky app=apps/blinky $ newt target show blinky targets/blinky app=apps/blinky bsp=hw/bsp/olimex_stm32-e407_devboard build_profile=debug Build the image Next, let's build the image for the above target. By default, the linker script within the hw/bsp/olimex_stm32-e407_devboard package builds an image for flash memory, which we don't want; instead, we want an image for the SRAM, so you need to switch that script with run_from_sram.ld . Afer you build the target, you can find the executable blinky.elf in the project directory ~/dev/myproj/bin/blinky/apps/blinky/. $ cd ~/dev/myproj/repos/apache-mynewt-core/hw/bsp/olimex_stm32-e407_devboard/ $ diff olimex_stm32-e407_devboard.ld run_from_sram.ld (some diff will be displayed) $ cp run_from_sram.ld olimex_stm32-e407_devboard.ld $ cd ~/dev/myproj $ newt build blinky Compiling case.c Compiling suite.c ... Linking blinky.elf App successfully built:~/dev/myproj/bin/blinky/apps/blinky/blinky.elf $ ls ~/dev/myproj/bin/blinky/apps/blinky/ blinky.elf blinky.elf.bin blinky.elf.cmd blinky.elf.lst blinky.elf.map Prepare the hardware to boot from embedded SRAM Locate the boot jumpers on the board. B1_1/B1_0 and B0_1/B0_0 are PTH jumpers. Note that because the markings on the board may not always be accurate, when in doubt, you should always refer to the manual for the correct positioning. Since the jumpers are a pair, they should move together, and as such, the pair is responsible for the boot mode when bootloader is present. To locate the bootloader, the board searches in three places: User Flash Memory, System Memory or the Embedded SRAM. For this Blinky project, we will configure it to boot from SRAM by jumpering B0_1 and B1_1 . Connect USB-OTG#2 in the picture above to a USB port on your computer (or a powered USB hub to make sure there is enough power available to the board). The red PWR LED should be lit. Connect the JTAG connector to the SWD/JTAG interface on the board. The other end of the cable should be connected to the USB port or hub of your computer. Let's Go! Ensure that you are in the blinky project directory with the blinky.elf executable. Run the debug command in the newt tool. You'll see some status messages as shown below. In case you need to halt the debugging session, you can issue an -c \"reset halt\" command. $ newt debug blinky Debugging with ~/dev/core/hw/bsp/olimex_... Debugging ~/dev/core/project/blinky/bin/blinky/blinky.elf GNU gdb (GNU Tools for ARM Embedded Processors) 7.8.0.20150604-cvs Copyright (C) 2014 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 <http://gnu.org/licenses/gpl.html> ... (info) ... target state: halted target halted due to debug-request, current mode: Thread xPSR: 0x01000000 pc: 0x080003c0 msp: 0x10010000 Info : accepting 'gdb' connection on tcp/3333 Info : device id = 0x10036413 Info : flash size = 1024kbytes Check the value of the msp (main service pointer) register. If it is not 0x10010000 as indicated above, you will have to manually set it after you open the gdb tool and load the image on it. For example, (gdb) set $msp=0x10010000 Now load the image and type \"c\" or \"continue\" from the GNU debugger. (gdb) load ~/dev/myproj/bin/blinky/apps/blinky/blinky.elf Loading section .text, size 0x16b88 lma 0x20000000 Loading section .ARM.exidx, size 0x18 lma 0x20016b88 Loading section .data, size 0x9ec lma 0x20016ba0 Start address 0x200004b8, load size 95628 Transfer rate: 74 KB/sec, 3825 bytes/write. (gdb) c Continuing. Voil\u00e0! The board's LED should be blinking at 1 Hz. Success!","title":"Run Blinky from SRAM, no bootloader"},{"location":"os/tutorials/blinky_sram_olimex/#run-blinky-from-sram-without-bootloader","text":"","title":"Run Blinky from SRAM without bootloader"},{"location":"os/tutorials/blinky_sram_olimex/#objective","text":"To download an application image directly into the embedded SRAM in the microcontroller and run it without the bootloader. This tutorial describes how you do it on an Olimex STM32 board.","title":"Objective"},{"location":"os/tutorials/blinky_sram_olimex/#what-you-need","text":"STM32-E407 development board from Olimex. You can order it from http://www.mouser.com , http://www.digikey.com , and other places. ARM-USB-TINY-H connector with JTAG interface for debugging ARM microcontrollers (comes with the ribbon cable to hook up to the board) USB A-B type cable to connect the debugger to your personal computer Personal Computer with Mac OS (Mac: OS X Yosemite Version 10.10.5) or Linux box (Ubuntu 14.10: Utopic Unicorn) An account on Github repository and git installed on your computer. It is assumed you have already installed newt tool. It is assumed you already installed native tools as described here Also, we assume that you're familiar with UNIX shells. Let's gets started!","title":"What you need"},{"location":"os/tutorials/blinky_sram_olimex/#prepare-the-software","text":"Make sure the PATH environment variable includes the $HOME/dev/go/bin directory.","title":"Prepare the Software"},{"location":"os/tutorials/blinky_sram_olimex/#create-a-project","text":"Create a new project to hold your work. For a deeper understanding, you can read about project creation in Get Started -- Creating Your First Project or just follow the commands below. $ mkdir ~/dev $ cd ~/dev $ newt new myproj Downloading project skeleton from apache/incubator-mynewt-blinky... Installing skeleton in myproj... Project myproj successfully created. $cd myproj $ newt install -v apache-mynewt-core Downloading repository description for apache-mynewt-core... success! ... apache-mynewt-core successfully installed version 0.7.9-none","title":"Create a project"},{"location":"os/tutorials/blinky_sram_olimex/#create-a-target","text":"Change directory to ~/dev/myproj directory and define the blinky target inside myproj, using the newt tool. Starting with the target name, assign specific aspects of the project, as shown below, to pull the appropriate packages and build the right bundle or list for the board. For example, we set the build_profile, board support package (bsp), and app. $ newt target create blinky $ newt target set blinky build_profile=debug $ newt target set blinky bsp=@apache-mynewt-core/hw/bsp/olimex_stm32-e407_devboard $ newt target set blinky app=apps/blinky $ newt target show blinky targets/blinky app=apps/blinky bsp=hw/bsp/olimex_stm32-e407_devboard build_profile=debug","title":"Create a target"},{"location":"os/tutorials/blinky_sram_olimex/#build-the-image","text":"Next, let's build the image for the above target. By default, the linker script within the hw/bsp/olimex_stm32-e407_devboard package builds an image for flash memory, which we don't want; instead, we want an image for the SRAM, so you need to switch that script with run_from_sram.ld . Afer you build the target, you can find the executable blinky.elf in the project directory ~/dev/myproj/bin/blinky/apps/blinky/. $ cd ~/dev/myproj/repos/apache-mynewt-core/hw/bsp/olimex_stm32-e407_devboard/ $ diff olimex_stm32-e407_devboard.ld run_from_sram.ld (some diff will be displayed) $ cp run_from_sram.ld olimex_stm32-e407_devboard.ld $ cd ~/dev/myproj $ newt build blinky Compiling case.c Compiling suite.c ... Linking blinky.elf App successfully built:~/dev/myproj/bin/blinky/apps/blinky/blinky.elf $ ls ~/dev/myproj/bin/blinky/apps/blinky/ blinky.elf blinky.elf.bin blinky.elf.cmd blinky.elf.lst blinky.elf.map","title":"Build the image"},{"location":"os/tutorials/blinky_sram_olimex/#prepare-the-hardware-to-boot-from-embedded-sram","text":"Locate the boot jumpers on the board. B1_1/B1_0 and B0_1/B0_0 are PTH jumpers. Note that because the markings on the board may not always be accurate, when in doubt, you should always refer to the manual for the correct positioning. Since the jumpers are a pair, they should move together, and as such, the pair is responsible for the boot mode when bootloader is present. To locate the bootloader, the board searches in three places: User Flash Memory, System Memory or the Embedded SRAM. For this Blinky project, we will configure it to boot from SRAM by jumpering B0_1 and B1_1 . Connect USB-OTG#2 in the picture above to a USB port on your computer (or a powered USB hub to make sure there is enough power available to the board). The red PWR LED should be lit. Connect the JTAG connector to the SWD/JTAG interface on the board. The other end of the cable should be connected to the USB port or hub of your computer.","title":"Prepare the hardware to boot from embedded SRAM"},{"location":"os/tutorials/blinky_sram_olimex/#lets-go","text":"Ensure that you are in the blinky project directory with the blinky.elf executable. Run the debug command in the newt tool. You'll see some status messages as shown below. In case you need to halt the debugging session, you can issue an -c \"reset halt\" command. $ newt debug blinky Debugging with ~/dev/core/hw/bsp/olimex_... Debugging ~/dev/core/project/blinky/bin/blinky/blinky.elf GNU gdb (GNU Tools for ARM Embedded Processors) 7.8.0.20150604-cvs Copyright (C) 2014 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 <http://gnu.org/licenses/gpl.html> ... (info) ... target state: halted target halted due to debug-request, current mode: Thread xPSR: 0x01000000 pc: 0x080003c0 msp: 0x10010000 Info : accepting 'gdb' connection on tcp/3333 Info : device id = 0x10036413 Info : flash size = 1024kbytes Check the value of the msp (main service pointer) register. If it is not 0x10010000 as indicated above, you will have to manually set it after you open the gdb tool and load the image on it. For example, (gdb) set $msp=0x10010000 Now load the image and type \"c\" or \"continue\" from the GNU debugger. (gdb) load ~/dev/myproj/bin/blinky/apps/blinky/blinky.elf Loading section .text, size 0x16b88 lma 0x20000000 Loading section .ARM.exidx, size 0x18 lma 0x20016b88 Loading section .data, size 0x9ec lma 0x20016ba0 Start address 0x200004b8, load size 95628 Transfer rate: 74 KB/sec, 3825 bytes/write. (gdb) c Continuing. Voil\u00e0! The board's LED should be blinking at 1 Hz. Success!","title":"Let's Go!"},{"location":"os/tutorials/blinky_windows/","text":"Project Blinky on a Windows Machine Getting your Windows machine ready for simulated target The newt tool is the build software used to build Mynewt OS images or executables for any embedded hardware device/board, including the one for the current tutorial (STM32-E407 development board from Olimex). You can run the newt tool natively on a computer running any of the three Operating System machines - OSX, Linux, or Windows. However, Mynewt OS images for a simulated target are built on the Windows machine by using Linux versions of the build software (newt)in a virtual machine on your Windows box. The Linux VM is set up by installing the Docker Toolbox. Your Windows machine will communicate with the Linux VM via transient ssh connections. You will then download a Docker image ( newtvm.exe )that allows you to run the newt commands in the Linux Docker instance. The Docker image contains: The newt command-line tool Go A multilib-capable native gcc / glibc An arm-none-eabi gcc Native gdb The sequence of events when using the Docker image is as follows: A new docker environment is created in the Linux VM. The specified command with the newtvm prefix ( newtvm newt command) is sent to the docker environment via ssh. The Linux command runs. The output from the command is sent back to Windows via ssh. The output is displayed in the Windows command prompt. Install Linux virtual machine Download the Docker Toolbox for Windows (version 1.9.0c or later) from https://www.docker.com/docker-toolbox . The Docker toolbox creates a consistently reproducible and self-contained environment in Linux. Run the Docker Toolbox installer. All the default settings are OK. You may need to add \"C:\\Program Files\\Git\\usr\\bin\" to your PATH environment variable. To add to the PATH environment variable, right-click on the Start button in the bottom left corner. Choose System -> Advanced system settings -> Environment Variables. Click on the PATH variable under \"System variables\" and click Edit to check and add it if it is not already there. Install newtvm tool From your base user (home) directory, pull or clone the latest code from the newt repository into the newt directory. It includes the executable newtvm.exe for the newtvm tool in the newtvm directory. C : \\Users\\admin> git clone https: //git-wip-us.apache.org/repos/asf/incubator-mynewt-newt newt The newtvm tool is what allows you to run programs in the Linux docker instance. Run the Docker Quickstart Terminal application inside the Docker folder under Programs. You can find it by clicking Start button -> All apps. By default, the Docker Toolbox installer creates a shortcut to this program on your desktop. Wait until you see an ASCII art whale displayed in the terminal window and the Docker prompt given. ## . ## ## ## == ## ## ## ## ## === / \"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\\___/ === ~~~ { ~~ ~~~~ ~~~ ~~~~ ~~~ ~ / ===- ~~~ \\______ o __/ \\ \\ __/ \\____\\_______/ docker is configured to use the default machine with IP 192.168.99.100 For help getting started , check out the docs at https: //docs.docker.com admin@dev1 MINGW64 ~ ( master ) $ The first time you run this, it may take several minutes to complete. You will need to run the Docker Quickstart Terminal once each time you restart your computer. Open a command prompt (e.g., Windows-R, \"cmd\", enter). You execute the newt tool commands as though you were running newt in Linux, but you prefix each command with \"newtvm\". For example: C : \\Users\\admin\\newt\\newtvm> newtvm newt help The newtvm tool will take a long time to run the first time you execute it. The delay is due to the fact that the tool must download the mynewt docker instance. You are now ready to proceed to building the image for the simulated target . Getting your Windows machine ready for hardware target When you want to produce images for actual hardware board on your Windows machine, go through the following setup procedure and then proceed to the blinky project on the Olimex board with this method. Installing some prerequisites You have to install the following if you do not have them already. The steps below indicate specific folders where each of these programs should be installed. You can choose different locations, but the remainder of this tutorial for a Windows machine assumes the specified folders. win-builds-i686 win-builds-x86_64 MSYS gcc for ARM openocd zadig git go win-builds (mingw64) 1.5 for i686 Download from http://win-builds.org/doku.php/download_and_installation_from_windows . Install at: \"C:\\win-builds-i686\". Be sure to click the i686 option (not x86_64). The defaults for all other options are OK. The installer will want to download a bunch of additional packages. They are not all necessary, but it is simplest to just accept the defaults. win-builds (mingw64) 1.5 for x86_64 Download from http://win-builds.org/doku.php/download_and_installation_from_windows . Install at \"C:\\win-builds-x86_64\" Run the installer a second time, but this time click the x86_64 option, NOT i686. The defaults for all other options are OK. MSYS Start your download from http://sourceforge.net/projects/mingw-w64/files/External%20binary%20packages%20%28Win64%20hosted%29/MSYS%20%2832-bit%29/MSYS-20111123.zip Unzip to \"C:\\msys\" gcc for ARM, 4.9.3 Download the Windows installer from https://launchpad.net/gcc-arm-embedded/+download and install at \"C:\\Program Files (x86)\\GNU Tools ARM Embedded\\4.9 2015q3\". OpenOCD 0.8.0 Download OpenOCD 0.8.0 from http://www.freddiechopin.info/en/download/category/4-openocd . Unzip to \"C:\\openocd\". Zadig 2.1.2 Download it from http://zadig.akeo.ie and install it at \"C:\\zadig\". Git Click on https://git-scm.com/download/win to start the download. Install at \"C:\\Program Files (x86)\\Git\". Specify the \"Use Git from the Windows Command Prompt\" option. The defaults for all other options are OK. Go Download the release for Microsoft Windows from https://golang.org/dl/ and install it \"C:\\Go\". Creating local repository The directory structure must be first readied for using Go. Go code must be kept inside a workspace. A workspace is a directory hierarchy with three directories at its root: src contains Go source files organized into packages (one package per directory), pkg contains package objects, and bin contains executable commands. The GOPATH environment variable specifies the location of your workspace. First create a 'dev' directory and then a 'go' directory under it. Set the GOPATH environment variable to this directory and then proceed to create the directory for cloning the newt tool repository. $ cd c: \\ $ mkdir dev\\go $ cd dev\\go Set the following user environment variables using the steps outlined here. * GOPATH: C:\\dev\\go * PATH: C:\\Program Files ( x86 ) \\GNU Tools ARM Embedded\\ 4.9 2015 q3\\bin ; %GOPATH%\\bin ; C:\\win-builds-x86_64\\bin ; C:\\win-builds-i686\\bin ; C:\\msys\\bin Steps: Right-click the start button Click \"Control panel\" Click \"System and Security\" Click \"System\" Click \"Advanced system settings\" in the left panel Click the \"Envoronment Variables...\" button There will be two sets of environment variables: user variables in the upper half of the screen, and system variables in the lower half. Configuring the user variables is recommended and tested (though system variables will work as well). Next, install godep. Note that the following command produces no output. $ go get github . com/tools/godep Set up the repository for the package building tool \"newt\" on your local machine. First create the appropriate directory for it and then clone the newt tool repository from the online apache repository (or its github.com mirror) into this newly created directory. Check the contents of the directory. $ go get git-wip-us . apache . org/repos/asf/incubator-mynewt-newt . git/newt $ dir bin pkg src $ dir src git-wip-us . apache . org github . com gopkg . in $ dir newt $ cd newt $ dir Godeps README . md coding_style . txt newt . go LICENSE cli design . txt Check that newt is in place. $ dir $GOPATH\\src\\git-wip-us . apache . org\\repos\\asf\\incubator-mynewt-newt . git\\newt Godeps README . md coding_style . txt newt . go LICENSE cli design . txt Building the newt tool You will use Go to run the newt.go program to build the newt tool. The command used is go install which compiles and writes the resulting executable to an output file named newt . It installs the results along with its dependencies in $GOPATH/bin. $ go install $ ls \"$GOPATH\" /bin/ godep incubator-mynewt-newt . git newt Try running newt using the compiled binary. For example, check for the version number by typing 'newt version'. See all the possible commands available to a user of newt by typing 'newt -h'. Note: If you are going to be be modifying the newt tool itself often and wish to compile the program every time you call it, you may want to define the newt environment variable that allows you to execute the command via %newt% . Use set newt=go run %GOPATH%\\src\\github.com\\mynewt\\newt\\newt.go or set it from the GUI. Here, you use go run which runs the compiled binary directly without producing an executable. $ newt version Newt version: 1.0 $ newt -h Newt allows you to create your own embedded project based on the Mynewt operating system . Newt provides both build and package management in a single tool , which allows you to compose an embedded workspace , and set of projects , and then build the necessary artifacts from those projects . For more information on the Mynewt operating system , please visit https : //www.github.com/mynewt/documentation. Please use the newt help command , and specify the name of the command you want help for , for help on how to use a specific command Usage : newt [ flags ] newt [ command ] Examples : newt newt help [ <command-name> ] For help on <command-name> . If not specified , print this message . Available Commands: version Display the Newt version number . target Set and view target information egg Commands to list and inspect eggs on a nest nest Commands to manage nests & clutches ( remote egg repositories ) help Help about any command Flags : -h , --help= false : help for newt -l , --loglevel= \"WARN\" : Log level , defaults to WARN . -q , --quiet= false : Be quiet ; only display error output . -s , --silent= false : Be silent ; don't output anything . -v , --verbose= false : Enable verbose output when executing commands . Use \"newt help [command]\" for more information about a command . Without creating a project repository you can't do a whole lot with the Newt tool. So you'll have to wait till you have downloaded a nest to try out the tool. Getting the debugger ready Use Zadig to configure the USB driver for your Olimex debugger. If your debugger is already set up, you can skip this step. Plug in your Olimex debugger. Start Zadig. Check the Options -> List All Devices checkbox. Select \"Olimex OpenOCD JTAG ARM-USB-TINY-H\" in the dropdown menu. Select the \"WinUSB\" driver. Click the \"Install Driver\" button. Proceed to the section on how to make an LED blink section.","title":"Blinky windows"},{"location":"os/tutorials/blinky_windows/#project-blinky-on-a-windows-machine","text":"","title":"Project Blinky on a Windows Machine"},{"location":"os/tutorials/blinky_windows/#getting-your-windows-machine-ready-for-simulated-target","text":"The newt tool is the build software used to build Mynewt OS images or executables for any embedded hardware device/board, including the one for the current tutorial (STM32-E407 development board from Olimex). You can run the newt tool natively on a computer running any of the three Operating System machines - OSX, Linux, or Windows. However, Mynewt OS images for a simulated target are built on the Windows machine by using Linux versions of the build software (newt)in a virtual machine on your Windows box. The Linux VM is set up by installing the Docker Toolbox. Your Windows machine will communicate with the Linux VM via transient ssh connections. You will then download a Docker image ( newtvm.exe )that allows you to run the newt commands in the Linux Docker instance. The Docker image contains: The newt command-line tool Go A multilib-capable native gcc / glibc An arm-none-eabi gcc Native gdb The sequence of events when using the Docker image is as follows: A new docker environment is created in the Linux VM. The specified command with the newtvm prefix ( newtvm newt command) is sent to the docker environment via ssh. The Linux command runs. The output from the command is sent back to Windows via ssh. The output is displayed in the Windows command prompt.","title":"Getting your Windows machine ready for simulated target"},{"location":"os/tutorials/blinky_windows/#install-linux-virtual-machine","text":"Download the Docker Toolbox for Windows (version 1.9.0c or later) from https://www.docker.com/docker-toolbox . The Docker toolbox creates a consistently reproducible and self-contained environment in Linux. Run the Docker Toolbox installer. All the default settings are OK. You may need to add \"C:\\Program Files\\Git\\usr\\bin\" to your PATH environment variable. To add to the PATH environment variable, right-click on the Start button in the bottom left corner. Choose System -> Advanced system settings -> Environment Variables. Click on the PATH variable under \"System variables\" and click Edit to check and add it if it is not already there.","title":"Install Linux virtual machine"},{"location":"os/tutorials/blinky_windows/#install-newtvm-tool","text":"From your base user (home) directory, pull or clone the latest code from the newt repository into the newt directory. It includes the executable newtvm.exe for the newtvm tool in the newtvm directory. C : \\Users\\admin> git clone https: //git-wip-us.apache.org/repos/asf/incubator-mynewt-newt newt The newtvm tool is what allows you to run programs in the Linux docker instance. Run the Docker Quickstart Terminal application inside the Docker folder under Programs. You can find it by clicking Start button -> All apps. By default, the Docker Toolbox installer creates a shortcut to this program on your desktop. Wait until you see an ASCII art whale displayed in the terminal window and the Docker prompt given. ## . ## ## ## == ## ## ## ## ## === / \"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\\___/ === ~~~ { ~~ ~~~~ ~~~ ~~~~ ~~~ ~ / ===- ~~~ \\______ o __/ \\ \\ __/ \\____\\_______/ docker is configured to use the default machine with IP 192.168.99.100 For help getting started , check out the docs at https: //docs.docker.com admin@dev1 MINGW64 ~ ( master ) $ The first time you run this, it may take several minutes to complete. You will need to run the Docker Quickstart Terminal once each time you restart your computer. Open a command prompt (e.g., Windows-R, \"cmd\", enter). You execute the newt tool commands as though you were running newt in Linux, but you prefix each command with \"newtvm\". For example: C : \\Users\\admin\\newt\\newtvm> newtvm newt help The newtvm tool will take a long time to run the first time you execute it. The delay is due to the fact that the tool must download the mynewt docker instance. You are now ready to proceed to building the image for the simulated target .","title":"Install newtvm tool"},{"location":"os/tutorials/blinky_windows/#getting-your-windows-machine-ready-for-hardware-target","text":"When you want to produce images for actual hardware board on your Windows machine, go through the following setup procedure and then proceed to the blinky project on the Olimex board with this method.","title":"Getting your Windows machine ready for hardware target"},{"location":"os/tutorials/blinky_windows/#installing-some-prerequisites","text":"You have to install the following if you do not have them already. The steps below indicate specific folders where each of these programs should be installed. You can choose different locations, but the remainder of this tutorial for a Windows machine assumes the specified folders. win-builds-i686 win-builds-x86_64 MSYS gcc for ARM openocd zadig git go win-builds (mingw64) 1.5 for i686 Download from http://win-builds.org/doku.php/download_and_installation_from_windows . Install at: \"C:\\win-builds-i686\". Be sure to click the i686 option (not x86_64). The defaults for all other options are OK. The installer will want to download a bunch of additional packages. They are not all necessary, but it is simplest to just accept the defaults. win-builds (mingw64) 1.5 for x86_64 Download from http://win-builds.org/doku.php/download_and_installation_from_windows . Install at \"C:\\win-builds-x86_64\" Run the installer a second time, but this time click the x86_64 option, NOT i686. The defaults for all other options are OK. MSYS Start your download from http://sourceforge.net/projects/mingw-w64/files/External%20binary%20packages%20%28Win64%20hosted%29/MSYS%20%2832-bit%29/MSYS-20111123.zip Unzip to \"C:\\msys\" gcc for ARM, 4.9.3 Download the Windows installer from https://launchpad.net/gcc-arm-embedded/+download and install at \"C:\\Program Files (x86)\\GNU Tools ARM Embedded\\4.9 2015q3\". OpenOCD 0.8.0 Download OpenOCD 0.8.0 from http://www.freddiechopin.info/en/download/category/4-openocd . Unzip to \"C:\\openocd\". Zadig 2.1.2 Download it from http://zadig.akeo.ie and install it at \"C:\\zadig\". Git Click on https://git-scm.com/download/win to start the download. Install at \"C:\\Program Files (x86)\\Git\". Specify the \"Use Git from the Windows Command Prompt\" option. The defaults for all other options are OK. Go Download the release for Microsoft Windows from https://golang.org/dl/ and install it \"C:\\Go\".","title":"Installing some prerequisites"},{"location":"os/tutorials/blinky_windows/#creating-local-repository","text":"The directory structure must be first readied for using Go. Go code must be kept inside a workspace. A workspace is a directory hierarchy with three directories at its root: src contains Go source files organized into packages (one package per directory), pkg contains package objects, and bin contains executable commands. The GOPATH environment variable specifies the location of your workspace. First create a 'dev' directory and then a 'go' directory under it. Set the GOPATH environment variable to this directory and then proceed to create the directory for cloning the newt tool repository. $ cd c: \\ $ mkdir dev\\go $ cd dev\\go Set the following user environment variables using the steps outlined here. * GOPATH: C:\\dev\\go * PATH: C:\\Program Files ( x86 ) \\GNU Tools ARM Embedded\\ 4.9 2015 q3\\bin ; %GOPATH%\\bin ; C:\\win-builds-x86_64\\bin ; C:\\win-builds-i686\\bin ; C:\\msys\\bin Steps: Right-click the start button Click \"Control panel\" Click \"System and Security\" Click \"System\" Click \"Advanced system settings\" in the left panel Click the \"Envoronment Variables...\" button There will be two sets of environment variables: user variables in the upper half of the screen, and system variables in the lower half. Configuring the user variables is recommended and tested (though system variables will work as well). Next, install godep. Note that the following command produces no output. $ go get github . com/tools/godep Set up the repository for the package building tool \"newt\" on your local machine. First create the appropriate directory for it and then clone the newt tool repository from the online apache repository (or its github.com mirror) into this newly created directory. Check the contents of the directory. $ go get git-wip-us . apache . org/repos/asf/incubator-mynewt-newt . git/newt $ dir bin pkg src $ dir src git-wip-us . apache . org github . com gopkg . in $ dir newt $ cd newt $ dir Godeps README . md coding_style . txt newt . go LICENSE cli design . txt Check that newt is in place. $ dir $GOPATH\\src\\git-wip-us . apache . org\\repos\\asf\\incubator-mynewt-newt . git\\newt Godeps README . md coding_style . txt newt . go LICENSE cli design . txt","title":"Creating local repository"},{"location":"os/tutorials/blinky_windows/#building-the-newt-tool","text":"You will use Go to run the newt.go program to build the newt tool. The command used is go install which compiles and writes the resulting executable to an output file named newt . It installs the results along with its dependencies in $GOPATH/bin. $ go install $ ls \"$GOPATH\" /bin/ godep incubator-mynewt-newt . git newt Try running newt using the compiled binary. For example, check for the version number by typing 'newt version'. See all the possible commands available to a user of newt by typing 'newt -h'. Note: If you are going to be be modifying the newt tool itself often and wish to compile the program every time you call it, you may want to define the newt environment variable that allows you to execute the command via %newt% . Use set newt=go run %GOPATH%\\src\\github.com\\mynewt\\newt\\newt.go or set it from the GUI. Here, you use go run which runs the compiled binary directly without producing an executable. $ newt version Newt version: 1.0 $ newt -h Newt allows you to create your own embedded project based on the Mynewt operating system . Newt provides both build and package management in a single tool , which allows you to compose an embedded workspace , and set of projects , and then build the necessary artifacts from those projects . For more information on the Mynewt operating system , please visit https : //www.github.com/mynewt/documentation. Please use the newt help command , and specify the name of the command you want help for , for help on how to use a specific command Usage : newt [ flags ] newt [ command ] Examples : newt newt help [ <command-name> ] For help on <command-name> . If not specified , print this message . Available Commands: version Display the Newt version number . target Set and view target information egg Commands to list and inspect eggs on a nest nest Commands to manage nests & clutches ( remote egg repositories ) help Help about any command Flags : -h , --help= false : help for newt -l , --loglevel= \"WARN\" : Log level , defaults to WARN . -q , --quiet= false : Be quiet ; only display error output . -s , --silent= false : Be silent ; don't output anything . -v , --verbose= false : Enable verbose output when executing commands . Use \"newt help [command]\" for more information about a command . Without creating a project repository you can't do a whole lot with the Newt tool. So you'll have to wait till you have downloaded a nest to try out the tool.","title":"Building the newt tool"},{"location":"os/tutorials/blinky_windows/#getting-the-debugger-ready","text":"Use Zadig to configure the USB driver for your Olimex debugger. If your debugger is already set up, you can skip this step. Plug in your Olimex debugger. Start Zadig. Check the Options -> List All Devices checkbox. Select \"Olimex OpenOCD JTAG ARM-USB-TINY-H\" in the dropdown menu. Select the \"WinUSB\" driver. Click the \"Install Driver\" button. Proceed to the section on how to make an LED blink section.","title":"Getting the debugger ready"},{"location":"os/tutorials/define_target/","text":"How to Define a Target What newt commands to use?","title":"Define target"},{"location":"os/tutorials/define_target/#how-to-define-a-target","text":"What newt commands to use?","title":"How to Define a Target"},{"location":"os/tutorials/event_queue/","text":"How to define a task which uses event queues to manage multiple events Introduction Event queue is a mechanism by which you can serialize incoming events for your task. You can use it to get info about arrived hardware interrupts, callout expirations and messages from other tasks. The benefit of doing inter-task communication this way is that there should be less resources that need to be locked. The benefit of doing interrupt processing in a task context instead of inside an interrupt context is that you are not blocking other HW interrupts when doing the work. The same goes for high priority tasks in the system; they're blocked until the interrupt handler returns. From the task context you'll also be able to access other OS facilities; you can sleep while waiting for a lock, for example. Example app Here you are going to write an app which demonstrates the use of event queues for communication between tasks. You will also use OS callouts for timer expiration and another event from a GPIO interrupt. You will use inputs from 3 sources to toggle 3 GPIO outputs on my STM32F3discovery board. Create project You start by creating a project and populating it with repositories incubator-mynewt-core and mynewt_stm32f3. See STM32F3 tutorial if you need help with this. You can also read the tutorial on Additional Repositories for a more thorough understanding. Create application Here's what the pkg.yml looks for the application. [marko@IsMyLaptop:~/src/events]$ cat apps/event_sample/pkg.yml pkg.name: apps/event_sample pkg.type: app pkg.deps: - \"@apache-mynewt-core/libs/os\" - \"@apache-mynewt-core/hw/hal\" - \"@apache-mynewt-core/libs/console/stub\" Initialize the event queue structure This must be done before anyone tries to place events to the queue. Here it's done before any task gets created. Initialization is done by calling os_eventq_init() . #define MY_TASK_PRIO 4 #define MY_TASK_STACK_SZ 512 static struct os_eventq my_eventq ; static os_stack_t my_task_stack [ MY_TASK_STACK_SZ ]; static struct os_task my_task_str ; void init_tasks ( void ) { struct os_task taskid ; os_eventq_init ( &my_eventq ); os_task_init ( &my_task_str , \"task\" , my_task , NULL , MY_TASK_PRIO , OS_WAIT_FOREVER , my_task_stack , MY_TASK_STACK_SZ ); Processing events Here event processing is done inside my_task . The main loop of the task is pulling events from the queue, and then taking action. We look at the type of the event to figure out what to do. The code snippet shows what the main loop of the event handler looks like. Events are removed from the head of the queue using os_eventq_get void my_task ( void *arg ) { struct os_event *ev ; while ( 1 ) { ev = os_eventq_get ( &my_eventq ); switch ( ev->ev_type ) { /* more event types here */ default : assert ( 0 ); } } } Event types You can define your own event types. Some numbers are already reserved by the OS, so you should not use those as your own types. Reserved event types are defined in libs/os/include/os/os_eventq.h . One example of a reserved type is OS_EVENT_T_TIMER, which is used as type in OS callouts. You should start your event numbers from OS_EVENT_T_PERUSER , and go higher. You are going to generate events from GPIO interrupt handler, from another task as well as from a callout. OS callout already has a type, but you'll need to define types for the other uses. #define MY_TASK_GPIO_EVENT (OS_EVENT_T_PERUSER) #define MY_TASK_TASK_EVENT (OS_EVENT_T_PERUSER + 1) Posting events from another task Events are posted to a queue by calling os_eventq_put() . You need to preallocate memory for the event structure. Here it's done by declaring the event structure as a global variable. Note that you can call os_eventq_put() with an event which has already been queued. In that case, the call has no effect; the position of the event is not changed within the queue. In the code snippet we declare the os_event structure, and initialize it. We also create the event generating task, and periodically post event to the event queue. #define GEN_TASK_PRIO 3 #define GEN_TASK_STACK_SZ 512 static struct os_event gen_task_ev ; static os_stack_t gen_task_stack [ GEN_TASK_STACK_SZ ]; static struct os_task gen_task_str ; void gen_task ( void *arg ) { while ( 1 ) { os_time_delay ( OS_TICKS_PER_SEC / 4 ); os_eventq_put ( &my_eventq , &gen_task_ev ); } } void init_tasks ( void ) { /* .... */ gen_task_ev . ev_type = MY_TASK_TASK_EVENT ; os_task_init ( &gen_task_str , \"gen_task\" , gen_task , NULL , GEN_TASK_PRIO , OS_WAIT_FOREVER , gen_task_stack , GEN_TASK_STACK_SZ ); } Callout events You can get timer events delivered to your task's event queue with OS callout. Check callout documentation for description on how to use the API. For this example, you'll use only one type of callout; so you can use the simpler structure. In the code snippet we declare the os_callout structure and initialize it. Then we arm the timer. static struct os_callout my_callout ; void init_tasks ( void ) { /* .... */ os_callout_init ( &my_callout , &my_eventq , NULL ); os_callout_reset ( &my_callout , OS_TICKS_PER_SEC ); } Posting events from interrupt handler Another place where posting events makes sense is from an interrupt handler. In this tutorial you will do it when GPIO changes state. You'll use HAL GPIO interface to register a routine which is getting called from the interrupt handler context. This routine will then post event to your queue. On STM32F3Discovery board, there is a button connected to PA0. The identifier for this GPIO pin is 0. static struct os_event gpio_ev ; void init_tasks ( void ) { /* .... */ gpio_ev . ev_type = MY_TASK_GPIO_EVENT ; hal_gpio_irq_init ( 0 , my_gpio_irq , NULL , GPIO_TRIG_RISING , GPIO_PULL_NONE ); hal_gpio_irq_enable ( 0 ); } static void my_gpio_irq ( void *arg ) { os_eventq_put ( &my_eventq , &gpio_ev ); } Event processing finalized Now that you are posting events from different sources, you will fill in the parts in the task main loop to trigger different behaviors depending on event type. You'll drive different LEDs depending on what type of event arrived. LEDs on this board are connected to PE8, PE9, PE10 and so on. These have GPIO identifiers starting from 72 onwards. #define TASK_LED 72 #define CALLOUT_LED 73 #define GPIO_LED 74 void init_tasks ( void ) { /* .... */ hal_gpio_init_out ( TASK_LED , 1 ); hal_gpio_init_out ( CALLOUT_LED , 1 ); hal_gpio_init_out ( GPIO_LED , 1 ); } And here is the new main loop for your task. Note that when callout event arrives, we re-arm the callout. void my_task ( void *arg ) { struct os_event *ev ; while ( 1 ) { ev = os_eventq_get ( &my_eventq ); switch ( ev->ev_type ) { case MY_TASK_TASK_EVENT : hal_gpio_toggle ( TASK_LED ); break ; case OS_EVENT_T_TIMER : hal_gpio_toggle ( CALLOUT_LED ); os_callout_reset ( &my_callout , OS_TICKS_PER_SEC / 2 ); break ; case MY_TASK_GPIO_EVENT : hal_gpio_toggle ( GPIO_LED ); break ; default : assert ( 0 ); } } } Now you're done. Once you load this to your board, the task LED will blink at an interval of 250ms, the callout LED with an interval of 500ms, and the GPIO LED every time you press the button. Code for the example #include <os/os.h> #include <bsp/bsp.h> #include <hal/hal_gpio.h> #include <assert.h> #define MY_TASK_PRIO 4 #define MY_TASK_STACK_SZ 512 #define GEN_TASK_PRIO 3 #define GEN_TASK_STACK_SZ 512 #define MY_TASK_GPIO_EVENT (OS_EVENT_T_PERUSER) #define MY_TASK_TASK_EVENT (OS_EVENT_T_PERUSER + 1) #define TASK_LED 72 #define CALLOUT_LED 73 #define GPIO_LED 74 static struct os_eventq my_eventq ; static os_stack_t my_task_stack [ MY_TASK_STACK_SZ ]; static struct os_task my_task_str ; static struct os_event gen_task_ev ; static os_stack_t gen_task_stack [ GEN_TASK_STACK_SZ ]; static struct os_task gen_task_str ; static struct os_callout my_callout ; static struct os_event gpio_ev ; void my_task ( void *arg ) { struct os_event *ev ; while ( 1 ) { ev = os_eventq_get ( &my_eventq ); switch ( ev->ev_type ) { case MY_TASK_TASK_EVENT : hal_gpio_toggle ( TASK_LED ); break ; case OS_EVENT_T_TIMER : hal_gpio_toggle ( CALLOUT_LED ); os_callout_reset ( &my_callout , OS_TICKS_PER_SEC / 2 ); break ; case MY_TASK_GPIO_EVENT : hal_gpio_toggle ( GPIO_LED ); break ; default : assert ( 0 ); } } } static void my_gpio_irq ( void *arg ) { os_eventq_put ( &my_eventq , &gpio_ev ); } void gen_task ( void *arg ) { while ( 1 ) { os_time_delay ( OS_TICKS_PER_SEC / 4 ); os_eventq_put ( &my_eventq , &gen_task_ev ); } } void init_tasks ( void ) { os_eventq_init ( &my_eventq ); os_task_init ( &my_task_str , \"task\" , my_task , NULL , MY_TASK_PRIO , OS_WAIT_FOREVER , my_task_stack , MY_TASK_STACK_SZ ); gen_task_ev . ev_type = MY_TASK_TASK_EVENT ; os_task_init ( &gen_task_str , \"gen_task\" , gen_task , NULL , GEN_TASK_PRIO , OS_WAIT_FOREVER , gen_task_stack , GEN_TASK_STACK_SZ ); os_callout_init ( &my_callout , &my_eventq , NULL ); os_callout_reset ( &my_callout , OS_TICKS_PER_SEC ); gpio_ev . ev_type = MY_TASK_GPIO_EVENT ; hal_gpio_irq_init ( 0 , my_gpio_irq , NULL , GPIO_TRIG_RISING , GPIO_PULL_NONE ); hal_gpio_irq_enable ( 0 ); hal_gpio_init_out ( TASK_LED , 1 ); hal_gpio_init_out ( CALLOUT_LED , 1 ); hal_gpio_init_out ( GPIO_LED , 1 ); } int main ( int argc , char **argv ) { os_init (); init_tasks (); os_start (); assert ( 0 ); return 0 ; }","title":"Add task to manage multiple events"},{"location":"os/tutorials/event_queue/#how-to-define-a-task-which-uses-event-queues-to-manage-multiple-events","text":"","title":"How to define a task which uses event queues to manage multiple events"},{"location":"os/tutorials/event_queue/#introduction","text":"Event queue is a mechanism by which you can serialize incoming events for your task. You can use it to get info about arrived hardware interrupts, callout expirations and messages from other tasks. The benefit of doing inter-task communication this way is that there should be less resources that need to be locked. The benefit of doing interrupt processing in a task context instead of inside an interrupt context is that you are not blocking other HW interrupts when doing the work. The same goes for high priority tasks in the system; they're blocked until the interrupt handler returns. From the task context you'll also be able to access other OS facilities; you can sleep while waiting for a lock, for example.","title":"Introduction"},{"location":"os/tutorials/event_queue/#example-app","text":"Here you are going to write an app which demonstrates the use of event queues for communication between tasks. You will also use OS callouts for timer expiration and another event from a GPIO interrupt. You will use inputs from 3 sources to toggle 3 GPIO outputs on my STM32F3discovery board.","title":"Example app"},{"location":"os/tutorials/event_queue/#create-project","text":"You start by creating a project and populating it with repositories incubator-mynewt-core and mynewt_stm32f3. See STM32F3 tutorial if you need help with this. You can also read the tutorial on Additional Repositories for a more thorough understanding.","title":"Create project"},{"location":"os/tutorials/event_queue/#create-application","text":"Here's what the pkg.yml looks for the application. [marko@IsMyLaptop:~/src/events]$ cat apps/event_sample/pkg.yml pkg.name: apps/event_sample pkg.type: app pkg.deps: - \"@apache-mynewt-core/libs/os\" - \"@apache-mynewt-core/hw/hal\" - \"@apache-mynewt-core/libs/console/stub\"","title":"Create application"},{"location":"os/tutorials/event_queue/#initialize-the-event-queue-structure","text":"This must be done before anyone tries to place events to the queue. Here it's done before any task gets created. Initialization is done by calling os_eventq_init() . #define MY_TASK_PRIO 4 #define MY_TASK_STACK_SZ 512 static struct os_eventq my_eventq ; static os_stack_t my_task_stack [ MY_TASK_STACK_SZ ]; static struct os_task my_task_str ; void init_tasks ( void ) { struct os_task taskid ; os_eventq_init ( &my_eventq ); os_task_init ( &my_task_str , \"task\" , my_task , NULL , MY_TASK_PRIO , OS_WAIT_FOREVER , my_task_stack , MY_TASK_STACK_SZ );","title":"Initialize the event queue structure"},{"location":"os/tutorials/event_queue/#processing-events","text":"Here event processing is done inside my_task . The main loop of the task is pulling events from the queue, and then taking action. We look at the type of the event to figure out what to do. The code snippet shows what the main loop of the event handler looks like. Events are removed from the head of the queue using os_eventq_get void my_task ( void *arg ) { struct os_event *ev ; while ( 1 ) { ev = os_eventq_get ( &my_eventq ); switch ( ev->ev_type ) { /* more event types here */ default : assert ( 0 ); } } }","title":"Processing events"},{"location":"os/tutorials/event_queue/#event-types","text":"You can define your own event types. Some numbers are already reserved by the OS, so you should not use those as your own types. Reserved event types are defined in libs/os/include/os/os_eventq.h . One example of a reserved type is OS_EVENT_T_TIMER, which is used as type in OS callouts. You should start your event numbers from OS_EVENT_T_PERUSER , and go higher. You are going to generate events from GPIO interrupt handler, from another task as well as from a callout. OS callout already has a type, but you'll need to define types for the other uses. #define MY_TASK_GPIO_EVENT (OS_EVENT_T_PERUSER) #define MY_TASK_TASK_EVENT (OS_EVENT_T_PERUSER + 1)","title":"Event types"},{"location":"os/tutorials/event_queue/#posting-events-from-another-task","text":"Events are posted to a queue by calling os_eventq_put() . You need to preallocate memory for the event structure. Here it's done by declaring the event structure as a global variable. Note that you can call os_eventq_put() with an event which has already been queued. In that case, the call has no effect; the position of the event is not changed within the queue. In the code snippet we declare the os_event structure, and initialize it. We also create the event generating task, and periodically post event to the event queue. #define GEN_TASK_PRIO 3 #define GEN_TASK_STACK_SZ 512 static struct os_event gen_task_ev ; static os_stack_t gen_task_stack [ GEN_TASK_STACK_SZ ]; static struct os_task gen_task_str ; void gen_task ( void *arg ) { while ( 1 ) { os_time_delay ( OS_TICKS_PER_SEC / 4 ); os_eventq_put ( &my_eventq , &gen_task_ev ); } } void init_tasks ( void ) { /* .... */ gen_task_ev . ev_type = MY_TASK_TASK_EVENT ; os_task_init ( &gen_task_str , \"gen_task\" , gen_task , NULL , GEN_TASK_PRIO , OS_WAIT_FOREVER , gen_task_stack , GEN_TASK_STACK_SZ ); }","title":"Posting events from another task"},{"location":"os/tutorials/event_queue/#callout-events","text":"You can get timer events delivered to your task's event queue with OS callout. Check callout documentation for description on how to use the API. For this example, you'll use only one type of callout; so you can use the simpler structure. In the code snippet we declare the os_callout structure and initialize it. Then we arm the timer. static struct os_callout my_callout ; void init_tasks ( void ) { /* .... */ os_callout_init ( &my_callout , &my_eventq , NULL ); os_callout_reset ( &my_callout , OS_TICKS_PER_SEC ); }","title":"Callout events"},{"location":"os/tutorials/event_queue/#posting-events-from-interrupt-handler","text":"Another place where posting events makes sense is from an interrupt handler. In this tutorial you will do it when GPIO changes state. You'll use HAL GPIO interface to register a routine which is getting called from the interrupt handler context. This routine will then post event to your queue. On STM32F3Discovery board, there is a button connected to PA0. The identifier for this GPIO pin is 0. static struct os_event gpio_ev ; void init_tasks ( void ) { /* .... */ gpio_ev . ev_type = MY_TASK_GPIO_EVENT ; hal_gpio_irq_init ( 0 , my_gpio_irq , NULL , GPIO_TRIG_RISING , GPIO_PULL_NONE ); hal_gpio_irq_enable ( 0 ); } static void my_gpio_irq ( void *arg ) { os_eventq_put ( &my_eventq , &gpio_ev ); }","title":"Posting events from interrupt handler"},{"location":"os/tutorials/event_queue/#event-processing-finalized","text":"Now that you are posting events from different sources, you will fill in the parts in the task main loop to trigger different behaviors depending on event type. You'll drive different LEDs depending on what type of event arrived. LEDs on this board are connected to PE8, PE9, PE10 and so on. These have GPIO identifiers starting from 72 onwards. #define TASK_LED 72 #define CALLOUT_LED 73 #define GPIO_LED 74 void init_tasks ( void ) { /* .... */ hal_gpio_init_out ( TASK_LED , 1 ); hal_gpio_init_out ( CALLOUT_LED , 1 ); hal_gpio_init_out ( GPIO_LED , 1 ); } And here is the new main loop for your task. Note that when callout event arrives, we re-arm the callout. void my_task ( void *arg ) { struct os_event *ev ; while ( 1 ) { ev = os_eventq_get ( &my_eventq ); switch ( ev->ev_type ) { case MY_TASK_TASK_EVENT : hal_gpio_toggle ( TASK_LED ); break ; case OS_EVENT_T_TIMER : hal_gpio_toggle ( CALLOUT_LED ); os_callout_reset ( &my_callout , OS_TICKS_PER_SEC / 2 ); break ; case MY_TASK_GPIO_EVENT : hal_gpio_toggle ( GPIO_LED ); break ; default : assert ( 0 ); } } } Now you're done. Once you load this to your board, the task LED will blink at an interval of 250ms, the callout LED with an interval of 500ms, and the GPIO LED every time you press the button.","title":"Event processing finalized"},{"location":"os/tutorials/event_queue/#code-for-the-example","text":"#include <os/os.h> #include <bsp/bsp.h> #include <hal/hal_gpio.h> #include <assert.h> #define MY_TASK_PRIO 4 #define MY_TASK_STACK_SZ 512 #define GEN_TASK_PRIO 3 #define GEN_TASK_STACK_SZ 512 #define MY_TASK_GPIO_EVENT (OS_EVENT_T_PERUSER) #define MY_TASK_TASK_EVENT (OS_EVENT_T_PERUSER + 1) #define TASK_LED 72 #define CALLOUT_LED 73 #define GPIO_LED 74 static struct os_eventq my_eventq ; static os_stack_t my_task_stack [ MY_TASK_STACK_SZ ]; static struct os_task my_task_str ; static struct os_event gen_task_ev ; static os_stack_t gen_task_stack [ GEN_TASK_STACK_SZ ]; static struct os_task gen_task_str ; static struct os_callout my_callout ; static struct os_event gpio_ev ; void my_task ( void *arg ) { struct os_event *ev ; while ( 1 ) { ev = os_eventq_get ( &my_eventq ); switch ( ev->ev_type ) { case MY_TASK_TASK_EVENT : hal_gpio_toggle ( TASK_LED ); break ; case OS_EVENT_T_TIMER : hal_gpio_toggle ( CALLOUT_LED ); os_callout_reset ( &my_callout , OS_TICKS_PER_SEC / 2 ); break ; case MY_TASK_GPIO_EVENT : hal_gpio_toggle ( GPIO_LED ); break ; default : assert ( 0 ); } } } static void my_gpio_irq ( void *arg ) { os_eventq_put ( &my_eventq , &gpio_ev ); } void gen_task ( void *arg ) { while ( 1 ) { os_time_delay ( OS_TICKS_PER_SEC / 4 ); os_eventq_put ( &my_eventq , &gen_task_ev ); } } void init_tasks ( void ) { os_eventq_init ( &my_eventq ); os_task_init ( &my_task_str , \"task\" , my_task , NULL , MY_TASK_PRIO , OS_WAIT_FOREVER , my_task_stack , MY_TASK_STACK_SZ ); gen_task_ev . ev_type = MY_TASK_TASK_EVENT ; os_task_init ( &gen_task_str , \"gen_task\" , gen_task , NULL , GEN_TASK_PRIO , OS_WAIT_FOREVER , gen_task_stack , GEN_TASK_STACK_SZ ); os_callout_init ( &my_callout , &my_eventq , NULL ); os_callout_reset ( &my_callout , OS_TICKS_PER_SEC ); gpio_ev . ev_type = MY_TASK_GPIO_EVENT ; hal_gpio_irq_init ( 0 , my_gpio_irq , NULL , GPIO_TRIG_RISING , GPIO_PULL_NONE ); hal_gpio_irq_enable ( 0 ); hal_gpio_init_out ( TASK_LED , 1 ); hal_gpio_init_out ( CALLOUT_LED , 1 ); hal_gpio_init_out ( GPIO_LED , 1 ); } int main ( int argc , char **argv ) { os_init (); init_tasks (); os_start (); assert ( 0 ); return 0 ; }","title":"Code for the example"},{"location":"os/tutorials/ibeacon/","text":"BLE iBeacon iBeacon Protocol A beaconing device announces its presence to the world by broadcasting advertisements. The iBeacon protocol is built on top of the standard BLE advertisement specification. An iBeacon advertisement contains a single field: Manufacturer Specific Data ; this field contains the iBeacon-specific sub-fields. This page provides a good summary of the iBeacon sub-fields. Configuration Use the following function to configure your NimBLE device to send iBeacons: int ble_ibeacon_set_adv_data ( void *uuid128 , uint16_t major , uint16_t minor ) This function's parameters are documented below. Parameter Purpose UUID 128-bit UUID identifying the application Major version number First number in your app's version Minor version number Second number in your app's version Modify bleprph To demonstrate how the above function is used, we will now modify the bleprph example application to send iBeacons. For some background behind the bleprph app, we recommend you take a look at the bleprph project tutorial . If you plan on making these modifications yourself, it might be a good idea to copy bleprph to your local repository and work with the copy. In general, you should avoid changing a package that newt downloads, as you will lose your changes the next time you upgrade the package. bleprph sets its advertisement data and begins advertising as follows ( main.c ): static void bleprph_advertise ( void ) { struct ble_hs_adv_fields fields ; int rc ; /* Set the advertisement data included in our advertisements. */ memset ( &fields , 0 , sizeof fields ); fields . name = ( uint8_t * ) bleprph_device_name ; fields . name_len = strlen ( bleprph_device_name ); fields . name_is_complete = 1 ; rc = ble_gap_adv_set_fields ( &fields ); if ( rc != 0 ) { BLEPRPH_LOG ( ERROR , \"error setting advertisement data; rc=%d\\n\" , rc ); return ; } /* Begin advertising. */ rc = ble_gap_adv_start ( BLE_GAP_DISC_MODE_GEN , BLE_GAP_CONN_MODE_UND , NULL , 0 , NULL , bleprph_on_connect , NULL ); if ( rc != 0 ) { BLEPRPH_LOG ( ERROR , \"error enabling advertisement; rc=%d\\n\" , rc ); return ; } } The call to ble_gap_adv_set_fields() configures the device with normal (non-iBeacon) advertisements; the call to ble_gap_adv_start() tells the NimBLE stack to start broadcasting. We are now going to create an iBeacon app by making the following to changes: Call ble_ibeacon_set_adv_data() instead of ble_gap_adv_set_fields() . Modify the call to ble_gap_adv_start() such that the device is non-discoverable and non-connectable. static void bleprph_advertise ( void ) { uint8_t uuid128 [ 16 ]; int rc ; /* Arbitrarily et the UUID to a string of 0x11 bytes. */ memset ( uuid128 , 0x11 , sizeof uuid128 ); /* Major version=2; minor version=10. */ rc = ble_ibeacon_set_adv_data ( uuid128 , 2 , 10 ); if ( rc != 0 ) { BLEPRPH_LOG ( ERROR , \"error setting iBeacon advertisement data; rc=%d\\n\" , rc ); return ; } /* Begin advertising. */ rc = ble_gap_adv_start ( BLE_GAP_DISC_MODE_NON , BLE_GAP_CONN_MODE_NON , NULL , 0 , NULL , bleprph_on_connect , NULL ); if ( rc != 0 ) { BLEPRPH_LOG ( ERROR , \"error enabling advertisement; rc=%d\\n\" , rc ); return ; } } Now when you run this app on your board, you should be able to see it with all your iBeacon-aware devices.","title":"BLE iBeacon"},{"location":"os/tutorials/ibeacon/#ble-ibeacon","text":"","title":"BLE iBeacon"},{"location":"os/tutorials/ibeacon/#ibeacon-protocol","text":"A beaconing device announces its presence to the world by broadcasting advertisements. The iBeacon protocol is built on top of the standard BLE advertisement specification. An iBeacon advertisement contains a single field: Manufacturer Specific Data ; this field contains the iBeacon-specific sub-fields. This page provides a good summary of the iBeacon sub-fields.","title":"iBeacon Protocol"},{"location":"os/tutorials/ibeacon/#configuration","text":"Use the following function to configure your NimBLE device to send iBeacons: int ble_ibeacon_set_adv_data ( void *uuid128 , uint16_t major , uint16_t minor ) This function's parameters are documented below. Parameter Purpose UUID 128-bit UUID identifying the application Major version number First number in your app's version Minor version number Second number in your app's version","title":"Configuration"},{"location":"os/tutorials/ibeacon/#modify-bleprph","text":"To demonstrate how the above function is used, we will now modify the bleprph example application to send iBeacons. For some background behind the bleprph app, we recommend you take a look at the bleprph project tutorial . If you plan on making these modifications yourself, it might be a good idea to copy bleprph to your local repository and work with the copy. In general, you should avoid changing a package that newt downloads, as you will lose your changes the next time you upgrade the package. bleprph sets its advertisement data and begins advertising as follows ( main.c ): static void bleprph_advertise ( void ) { struct ble_hs_adv_fields fields ; int rc ; /* Set the advertisement data included in our advertisements. */ memset ( &fields , 0 , sizeof fields ); fields . name = ( uint8_t * ) bleprph_device_name ; fields . name_len = strlen ( bleprph_device_name ); fields . name_is_complete = 1 ; rc = ble_gap_adv_set_fields ( &fields ); if ( rc != 0 ) { BLEPRPH_LOG ( ERROR , \"error setting advertisement data; rc=%d\\n\" , rc ); return ; } /* Begin advertising. */ rc = ble_gap_adv_start ( BLE_GAP_DISC_MODE_GEN , BLE_GAP_CONN_MODE_UND , NULL , 0 , NULL , bleprph_on_connect , NULL ); if ( rc != 0 ) { BLEPRPH_LOG ( ERROR , \"error enabling advertisement; rc=%d\\n\" , rc ); return ; } } The call to ble_gap_adv_set_fields() configures the device with normal (non-iBeacon) advertisements; the call to ble_gap_adv_start() tells the NimBLE stack to start broadcasting. We are now going to create an iBeacon app by making the following to changes: Call ble_ibeacon_set_adv_data() instead of ble_gap_adv_set_fields() . Modify the call to ble_gap_adv_start() such that the device is non-discoverable and non-connectable. static void bleprph_advertise ( void ) { uint8_t uuid128 [ 16 ]; int rc ; /* Arbitrarily et the UUID to a string of 0x11 bytes. */ memset ( uuid128 , 0x11 , sizeof uuid128 ); /* Major version=2; minor version=10. */ rc = ble_ibeacon_set_adv_data ( uuid128 , 2 , 10 ); if ( rc != 0 ) { BLEPRPH_LOG ( ERROR , \"error setting iBeacon advertisement data; rc=%d\\n\" , rc ); return ; } /* Begin advertising. */ rc = ble_gap_adv_start ( BLE_GAP_DISC_MODE_NON , BLE_GAP_CONN_MODE_NON , NULL , 0 , NULL , bleprph_on_connect , NULL ); if ( rc != 0 ) { BLEPRPH_LOG ( ERROR , \"error enabling advertisement; rc=%d\\n\" , rc ); return ; } } Now when you run this app on your board, you should be able to see it with all your iBeacon-aware devices.","title":"Modify bleprph"},{"location":"os/tutorials/nRF52/","text":"Blinky, your \"Hello World!\", on nRF52 Objective Learn how to use packages from a default application repository of Mynewt to build your first Hello World application (Blinky) on a target board. Once built using the newt tool, this application will blink the LED lights on the target board. Create a project with a simple app that blinks an LED on the nRF52 board from Nordic Semiconductors. Download the application to the target and watch it blink! Note that there are several versions of the nRF52 in the market. The boards tested with this tutorial are listed under \"Hardware needed\" below. Hardware needed nRF52 Development Kit (one of the following) Preview Kit from Nordic - PCA 10036 Dev Kit from Nordic - PCA 10040 Eval Kit from Rigado - BMD-300-EVAL-ES Laptop running Mac OS It is assumed you have already installed newt tool. It is assumed you already installed native tools as described here Install jlinkEXE In order to be able to communicate with the SEGGER J-Link debugger on the dev board, you have to download and install the J-Link GDB Server software on to your laptop. You may download the \"Software and documentation pack for Mac OS X\" from https://www.segger.com/jlink-software.html . Create a project. Create a new project to hold your work. For a deeper understanding, you can read about project creation in Get Started -- Creating Your First Project or just follow the commands below. $ mkdir ~/dev $ cd ~/dev $ newt new myproj Downloading project skeleton from apache/incubator-mynewt-blinky... Installing skeleton in myproj... Project myproj successfully created. $ cd myproj $ newt install -v apache-mynewt-core Downloading repository description for apache-mynewt-core... success! ... apache-mynewt-core successfully installed version 0.7.9-none Create the targets Create two targets - one for the bootloader and one for the nrf52 board. Note: The correct bsp must be chosen for the board you are using. For the Nordic Preview Dev Kit choose @apache-mynewt-core/hw/bsp/nrf52pdk (as shown below) For the Nordic Dev Kit choose @apache-mynewt-core/hw/bsp/nrf52dk instead (in the highlighted lines) For the Rigado Eval Kit choose @apache-mynewt-core/hw/bsp/bmd300eval instead (in the highlighted lines) $ newt target create blink_nordic $ newt target set blink_nordic app=apps/blinky $ newt target set blink_nordic bsp=@apache-mynewt-core/hw/bsp/nrf52pdk $ newt target set blink_nordic build_profile=debug $ newt target create nrf52_boot $ newt target set nrf52_boot app=@apache-mynewt-core/apps/boot $ newt target set nrf52_boot bsp=@apache-mynewt-core/hw/bsp/nrf52pdk $ newt target set nrf52_boot build_profile=optimized $ newt target show targets/blink_nordic app=apps/blinky bsp=@apache-mynewt-core/hw/bsp/nrf52pdk build_profile=debug targets/nrf52_boot app=@apache-mynewt-core/apps/boot bsp=@apache-mynewt-core/hw/bsp/nrf52pdk build_profile=optimized Build the target executables $ newt build nrf52_boot ... Compiling log_shell.c Archiving log.a Linking boot.elf App successfully built: ~/dev/myproj/bin/nrf52_boot/apps/boot/boot.elf $ newt build blink_nordic ... Compiling main.c Archiving blinky.a Linking blinky.elf App successfully built: ~/dev/myproj/bin/blink_nordic/apps/blinky/blinky.elf Sign and create the blinky application image You must sign and version your application image to download it using newt to the board. Use the newt create-image command to perform this action. You may assign an arbitrary version (e.g. 1.0.0) to the image. $ newt create-image blink_nordic 1.0.0 App image successfully generated: ~/dev/myproj/bin/blink_nordic/apps/blinky/blinky.img Build manifest: ~/dev/myproj/bin/blink_nordic/apps/blinky/manifest.json Connect the board Connect the evaluation board via micro-USB to your PC via USB cable. Download to the target Download the bootloader first and then the blinky executable to the target platform. Don't forget to reset the board if you don't see the LED blinking right away! $ newt -v load nrf52_boot $ newt -v load blink_nordic Note: If you want to erase the flash and load the image again, you can use JLinkExe to issue an erase command. $ JLinkExe -device nRF52 -speed 4000 -if SWD SEGGER J-Link Commander V5.12c (Compiled Apr 21 2016 16:05:51) DLL version V5.12c, compiled Apr 21 2016 16:05:45 Connecting to J-Link via USB...O.K. Firmware: J-Link OB-SAM3U128-V2-NordicSemi compiled Mar 15 2016 18:03:17 Hardware version: V1.00 S/N: 682863966 VTref = 3.300V Type \"connect\" to establish a target connection, '?' for help J-Link>erase Cortex-M4 identified. Erasing device (0;?i?)... Comparing flash [100%] Done. Erasing flash [100%] Done. Verifying flash [100%] Done. J-Link: Flash download: Total time needed: 0.363s (Prepare: 0.093s, Compare: 0.000s, Erase: 0.262s, Program: 0.000s, Verify: 0.000s, Restore: 0.008s) Erasing done. J-Link>exit $ Conclusion You have created, setup, compiled, loaded, and ran your first mynewt application for an nrf52 board. We have more fun tutorials for you to get your hands dirty. Be bold and work on the OS with tutorials on writing a test suite or try enabling additional functionality such as remote comms or Bluetooth Low Energy on your current board. If you see anything missing or want to send us feedback, please do so by signing up for appropriate mailing lists on our Community Page . Keep on hacking and blinking!","title":"Blinky on nRF52"},{"location":"os/tutorials/nRF52/#blinky-your-hello-world-on-nrf52","text":"","title":"Blinky, your \"Hello World!\", on nRF52"},{"location":"os/tutorials/nRF52/#objective","text":"Learn how to use packages from a default application repository of Mynewt to build your first Hello World application (Blinky) on a target board. Once built using the newt tool, this application will blink the LED lights on the target board. Create a project with a simple app that blinks an LED on the nRF52 board from Nordic Semiconductors. Download the application to the target and watch it blink! Note that there are several versions of the nRF52 in the market. The boards tested with this tutorial are listed under \"Hardware needed\" below.","title":"Objective"},{"location":"os/tutorials/nRF52/#hardware-needed","text":"nRF52 Development Kit (one of the following) Preview Kit from Nordic - PCA 10036 Dev Kit from Nordic - PCA 10040 Eval Kit from Rigado - BMD-300-EVAL-ES Laptop running Mac OS It is assumed you have already installed newt tool. It is assumed you already installed native tools as described here","title":"Hardware needed"},{"location":"os/tutorials/nRF52/#install-jlinkexe","text":"In order to be able to communicate with the SEGGER J-Link debugger on the dev board, you have to download and install the J-Link GDB Server software on to your laptop. You may download the \"Software and documentation pack for Mac OS X\" from https://www.segger.com/jlink-software.html .","title":"Install jlinkEXE"},{"location":"os/tutorials/nRF52/#create-a-project","text":"Create a new project to hold your work. For a deeper understanding, you can read about project creation in Get Started -- Creating Your First Project or just follow the commands below. $ mkdir ~/dev $ cd ~/dev $ newt new myproj Downloading project skeleton from apache/incubator-mynewt-blinky... Installing skeleton in myproj... Project myproj successfully created. $ cd myproj $ newt install -v apache-mynewt-core Downloading repository description for apache-mynewt-core... success! ... apache-mynewt-core successfully installed version 0.7.9-none","title":"Create a project."},{"location":"os/tutorials/nRF52/#create-the-targets","text":"Create two targets - one for the bootloader and one for the nrf52 board. Note: The correct bsp must be chosen for the board you are using. For the Nordic Preview Dev Kit choose @apache-mynewt-core/hw/bsp/nrf52pdk (as shown below) For the Nordic Dev Kit choose @apache-mynewt-core/hw/bsp/nrf52dk instead (in the highlighted lines) For the Rigado Eval Kit choose @apache-mynewt-core/hw/bsp/bmd300eval instead (in the highlighted lines) $ newt target create blink_nordic $ newt target set blink_nordic app=apps/blinky $ newt target set blink_nordic bsp=@apache-mynewt-core/hw/bsp/nrf52pdk $ newt target set blink_nordic build_profile=debug $ newt target create nrf52_boot $ newt target set nrf52_boot app=@apache-mynewt-core/apps/boot $ newt target set nrf52_boot bsp=@apache-mynewt-core/hw/bsp/nrf52pdk $ newt target set nrf52_boot build_profile=optimized $ newt target show targets/blink_nordic app=apps/blinky bsp=@apache-mynewt-core/hw/bsp/nrf52pdk build_profile=debug targets/nrf52_boot app=@apache-mynewt-core/apps/boot bsp=@apache-mynewt-core/hw/bsp/nrf52pdk build_profile=optimized","title":"Create the targets"},{"location":"os/tutorials/nRF52/#build-the-target-executables","text":"$ newt build nrf52_boot ... Compiling log_shell.c Archiving log.a Linking boot.elf App successfully built: ~/dev/myproj/bin/nrf52_boot/apps/boot/boot.elf $ newt build blink_nordic ... Compiling main.c Archiving blinky.a Linking blinky.elf App successfully built: ~/dev/myproj/bin/blink_nordic/apps/blinky/blinky.elf","title":"Build the target executables"},{"location":"os/tutorials/nRF52/#sign-and-create-the-blinky-application-image","text":"You must sign and version your application image to download it using newt to the board. Use the newt create-image command to perform this action. You may assign an arbitrary version (e.g. 1.0.0) to the image. $ newt create-image blink_nordic 1.0.0 App image successfully generated: ~/dev/myproj/bin/blink_nordic/apps/blinky/blinky.img Build manifest: ~/dev/myproj/bin/blink_nordic/apps/blinky/manifest.json","title":"Sign and create the blinky application image"},{"location":"os/tutorials/nRF52/#connect-the-board","text":"Connect the evaluation board via micro-USB to your PC via USB cable.","title":"Connect the board"},{"location":"os/tutorials/nRF52/#download-to-the-target","text":"Download the bootloader first and then the blinky executable to the target platform. Don't forget to reset the board if you don't see the LED blinking right away! $ newt -v load nrf52_boot $ newt -v load blink_nordic Note: If you want to erase the flash and load the image again, you can use JLinkExe to issue an erase command. $ JLinkExe -device nRF52 -speed 4000 -if SWD SEGGER J-Link Commander V5.12c (Compiled Apr 21 2016 16:05:51) DLL version V5.12c, compiled Apr 21 2016 16:05:45 Connecting to J-Link via USB...O.K. Firmware: J-Link OB-SAM3U128-V2-NordicSemi compiled Mar 15 2016 18:03:17 Hardware version: V1.00 S/N: 682863966 VTref = 3.300V Type \"connect\" to establish a target connection, '?' for help J-Link>erase Cortex-M4 identified. Erasing device (0;?i?)... Comparing flash [100%] Done. Erasing flash [100%] Done. Verifying flash [100%] Done. J-Link: Flash download: Total time needed: 0.363s (Prepare: 0.093s, Compare: 0.000s, Erase: 0.262s, Program: 0.000s, Verify: 0.000s, Restore: 0.008s) Erasing done. J-Link>exit $","title":"Download to the target"},{"location":"os/tutorials/nRF52/#conclusion","text":"You have created, setup, compiled, loaded, and ran your first mynewt application for an nrf52 board. We have more fun tutorials for you to get your hands dirty. Be bold and work on the OS with tutorials on writing a test suite or try enabling additional functionality such as remote comms or Bluetooth Low Energy on your current board. If you see anything missing or want to send us feedback, please do so by signing up for appropriate mailing lists on our Community Page . Keep on hacking and blinking!","title":"Conclusion"},{"location":"os/tutorials/olimex/","text":"Blinky, your \"Hello World!\", on Olimex Objective Learn how to use packages from a default application repository of Mynewt to build your first Hello World application (Blinky) on a target board. Once built using the newt tool, this application will blink the LED lights on the target board. Fun stuff! This tutorial shows you how to create a runtime image for an Olimex board to make its LED blink. Download the image to its flash memory and see the LED blink! What you need STM32-E407 development board from Olimex. You can order it from http://www.mouser.com , http://www.digikey.com , and other places. ARM-USB-TINY-H connector with JTAG interface for debugging ARM microcontrollers (comes with the ribbon cable to hook up to the board) USB A-B type cable to connect the debugger to your personal computer Personal Computer with Mac OS (Mac: OS X Yosemite Version 10.10.5) or Linux box (Ubuntu 14.10: Utopic Unicorn) An account on Github repository and git installed on your computer. It is assumed you have already installed newt tool. It is assumed you already installed native tools as described here Also, we assume that you're familiar with UNIX shells. Let's gets started! Prepare the Software Make sure the PATH environment variable includes the $HOME/dev/go/bin directory. Create a project. Create a new project to hold your work. For a deeper understanding, you can read about project creation in Get Started -- Creating Your First Project or just follow the commands below. $ mkdir ~/dev $ cd ~/dev $ newt new myproj Downloading project skeleton from apache/incubator-mynewt-blinky... Installing skeleton in myproj... Project myproj successfully created. $cd myproj $ newt install -v apache-mynewt-core Downloading repository description for apache-mynewt-core... success! ... apache-mynewt-core successfully installed version 0.7.9-none Create targets Change directory to ~/dev/myproj directory and define the blinky target inside myproj, using the newt tool. Starting with the target name, assign specific aspects of the project, as shown below, to pull the appropriate packages and build the right bundle or list for the board. For example, we set the build_profile, board support package (bsp), and app. $ newt target create blinky $ newt target set blinky build_profile=debug $ newt target set blinky bsp=@apache-mynewt-core/hw/bsp/olimex_stm32-e407_devboard $ newt target set blinky app=apps/blinky $ newt target create boot_olimex $ newt target set boot_olimex app=@apache-mynewt-core/apps/boot $ newt target set boot_olimex bsp=@apache-mynewt-core/hw/bsp/olimex_stm32-e407_devboard $ newt target set boot_olimex build_profile=optimized $ newt target show targets/blinky app=apps/blinky bsp=@apache-mynewt-core/hw/bsp/olimex_stm32-e407_devboard build_profile=debug targets/boot_olimex app=@apache-mynewt-core/apps/boot bsp=@apache-mynewt-core/hw/bsp/olimex_stm32-e407_devboard build_profile=optimized Build the images Next, let's build the images for the above targets. Afer you build the target, you can find the executable blinky.elf in the project directory ~/dev/myproj/bin/blinky/apps/blinky/. $ newt build blinky Compiling case.c Compiling suite.c ... Linking blinky.elf App successfully built:~/dev/myproj/bin/blinky/apps/blinky/blinky.elf $ ls ~/dev/myproj/bin/blinky/apps/blinky/ blinky.elf blinky.elf.bin blinky.elf.cmd blinky.elf.lst blinky.elf.map $ newt build boot_olimex Building target targets/boot_olimex App successfully built: ~/dev/myproj/bin/boot_olimex/apps/boot/boot.elf Sign and create the blinky application image You must sign and version your application image to download it using newt to the board. Use the newt create-image command to perform this action. You may assign an arbitrary version (e.g. 1.0.0) to the image. $ newt create-image blinky 1.0.0 App image successfully generated: ~/dev/myproj/bin/blinky/apps/blinky/blinky.img Build manifest: ~/dev/myproj/bin/blinky/apps/blinky/manifest.json Prepare the hardware to boot from flash Locate the boot jumpers on the board. B1_1/B1_0 and B0_1/B0_0 are PTH jumpers. Note that because the markings on the board may not always be accurate, when in doubt, you should always refer to the manual for the correct positioning. Since the jumpers are a pair, they should move together, and as such, the pair is responsible for the boot mode when bootloader is present. To locate the bootloader, the board searches in three places: User Flash Memory, System Memory or the Embedded SRAM. For this Blinky project, we will configure it to boot from flash by jumpering B0_0 and B1_0 . Connect USB-OTG#2 in the picture above to a USB port on your computer (or a powered USB hub to make sure there is enough power available to the board). The red PWR LED should be lit. Connect the JTAG connector to the SWD/JTAG interface on the board. The other end of the cable should be connected to the USB port or hub of your computer. Let's Go! Load the images $ newt -v load boot_olimex Loading image with: ~/dev/myproj/repos/apache-mynewt-core/hw/bsp/olimex_stm32-e407_devboard/olimex_stm32-e407_devboard_download.sh ~/dev/myproj/repos/apache-mynewt-core/hw/bsp/olimex_stm32-e407_devboard/ ~/dev/myproj/bin/boot_olimex/apps/boot/boot BASELIBC FS LIBC NFFS bootloader Successfully loaded image. $ newt -v load blinky Loading image with: ~/dev/myproj/repos/apache-mynewt-core/hw/bsp/olimex_stm32-e407_devboard/olimex_stm32-e407_devboard_download.sh ~/dev/myproj/repos/apache-mynewt-core/hw/bsp/olimex_stm32-e407_devboard/ ~/dev/myproj/bin/blinky/apps/blinky/blinky BASELIBC LIBC Successfully loaded image. Voil\u00e0! The LED should be blinking! Success! But wait...not so fast. Let's double check that it is indeed booting from flash and making the LED blink from the image in flash. Pull the USB cable off the Olimex JTAG adaptor, severing the debug connection to the JTAG port. Next power off the Olimex board by pulling out the USB cable from the board. Wait for a couple of seconds and plug the USB cable back to the board. The LED light will start blinking again. Success! Note #1: If you want to download the image to flash and a gdb session opened up, use newt debug blinky . Type c to continue inside the gdb session. $ newt debug blinky Debugging with ~/dev/myproj/hw/bsp/olimex_stm32-e407_... Debugging ~/dev/myproj/project/blinky/bin/blinky/blinky.elf GNU gdb (GNU Tools for ARM Embedded Processors) 7.8.0.20150604-cvs Copyright (C) 2014 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 <http://gnu.org/licenses/gpl.html> ... (info) ... target state: halted target halted due to debug-request, current mode: Thread xPSR: 0x01000000 pc: 0x08000250 msp: 0x10010000 Info : accepting 'gdb' connection from 3333 Info : device id = 0x10036413 Info : flash size = 1024kbytes Reset_Handler () at startup_STM32F40x.s:199 199 ldr r1, =__etext (gdb) Note #2: If you want to erase the flash and load the image again you may use the following commands from within gdb. flash erase_sector 0 0 x tells it to erase sectors 0 through x. When you ask it to display (in hex notation) the contents of the sector starting at location 'lma,' you should see all f's. The memory location 0x8000000 is the start or origin of the flash memory contents and is specified in the olimex_stm32-e407_devboard.ld linker script. The flash memory locations is specific to the processor. (gdb) monitor flash erase_sector 0 0 4 erased sectors 0 through 4 on flash bank 0 in 2.296712s (gdb) monitor mdw 0x08000000 16 0x08000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff (0x08000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff (0x08000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff (0x08000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff (gdb) monitor flash info 0 Conclusion Congratulations! You have now tried out a project on actual hardware. If this is your first time to embedded systems, this must feel like the best hands-on and low-level \"Hello World\" program ever. Good, we have more fun tutorials for you to get your hands dirty. Be bold and try other Blinky-like tutorials or try enabling additional functionality such as remote comms on the current board. If you see anything missing or want to send us feedback, please do so by signing up for appropriate mailing lists on our Community Page . Keep on hacking and blinking!","title":"Blinky on Olimex"},{"location":"os/tutorials/olimex/#blinky-your-hello-world-on-olimex","text":"","title":"Blinky, your \"Hello World!\", on Olimex"},{"location":"os/tutorials/olimex/#objective","text":"Learn how to use packages from a default application repository of Mynewt to build your first Hello World application (Blinky) on a target board. Once built using the newt tool, this application will blink the LED lights on the target board. Fun stuff! This tutorial shows you how to create a runtime image for an Olimex board to make its LED blink. Download the image to its flash memory and see the LED blink!","title":"Objective"},{"location":"os/tutorials/olimex/#what-you-need","text":"STM32-E407 development board from Olimex. You can order it from http://www.mouser.com , http://www.digikey.com , and other places. ARM-USB-TINY-H connector with JTAG interface for debugging ARM microcontrollers (comes with the ribbon cable to hook up to the board) USB A-B type cable to connect the debugger to your personal computer Personal Computer with Mac OS (Mac: OS X Yosemite Version 10.10.5) or Linux box (Ubuntu 14.10: Utopic Unicorn) An account on Github repository and git installed on your computer. It is assumed you have already installed newt tool. It is assumed you already installed native tools as described here Also, we assume that you're familiar with UNIX shells. Let's gets started!","title":"What you need"},{"location":"os/tutorials/olimex/#prepare-the-software","text":"Make sure the PATH environment variable includes the $HOME/dev/go/bin directory.","title":"Prepare the Software"},{"location":"os/tutorials/olimex/#create-a-project","text":"Create a new project to hold your work. For a deeper understanding, you can read about project creation in Get Started -- Creating Your First Project or just follow the commands below. $ mkdir ~/dev $ cd ~/dev $ newt new myproj Downloading project skeleton from apache/incubator-mynewt-blinky... Installing skeleton in myproj... Project myproj successfully created. $cd myproj $ newt install -v apache-mynewt-core Downloading repository description for apache-mynewt-core... success! ... apache-mynewt-core successfully installed version 0.7.9-none","title":"Create a project."},{"location":"os/tutorials/olimex/#create-targets","text":"Change directory to ~/dev/myproj directory and define the blinky target inside myproj, using the newt tool. Starting with the target name, assign specific aspects of the project, as shown below, to pull the appropriate packages and build the right bundle or list for the board. For example, we set the build_profile, board support package (bsp), and app. $ newt target create blinky $ newt target set blinky build_profile=debug $ newt target set blinky bsp=@apache-mynewt-core/hw/bsp/olimex_stm32-e407_devboard $ newt target set blinky app=apps/blinky $ newt target create boot_olimex $ newt target set boot_olimex app=@apache-mynewt-core/apps/boot $ newt target set boot_olimex bsp=@apache-mynewt-core/hw/bsp/olimex_stm32-e407_devboard $ newt target set boot_olimex build_profile=optimized $ newt target show targets/blinky app=apps/blinky bsp=@apache-mynewt-core/hw/bsp/olimex_stm32-e407_devboard build_profile=debug targets/boot_olimex app=@apache-mynewt-core/apps/boot bsp=@apache-mynewt-core/hw/bsp/olimex_stm32-e407_devboard build_profile=optimized","title":"Create targets"},{"location":"os/tutorials/olimex/#build-the-images","text":"Next, let's build the images for the above targets. Afer you build the target, you can find the executable blinky.elf in the project directory ~/dev/myproj/bin/blinky/apps/blinky/. $ newt build blinky Compiling case.c Compiling suite.c ... Linking blinky.elf App successfully built:~/dev/myproj/bin/blinky/apps/blinky/blinky.elf $ ls ~/dev/myproj/bin/blinky/apps/blinky/ blinky.elf blinky.elf.bin blinky.elf.cmd blinky.elf.lst blinky.elf.map $ newt build boot_olimex Building target targets/boot_olimex App successfully built: ~/dev/myproj/bin/boot_olimex/apps/boot/boot.elf","title":"Build the images"},{"location":"os/tutorials/olimex/#sign-and-create-the-blinky-application-image","text":"You must sign and version your application image to download it using newt to the board. Use the newt create-image command to perform this action. You may assign an arbitrary version (e.g. 1.0.0) to the image. $ newt create-image blinky 1.0.0 App image successfully generated: ~/dev/myproj/bin/blinky/apps/blinky/blinky.img Build manifest: ~/dev/myproj/bin/blinky/apps/blinky/manifest.json","title":"Sign and create the blinky application image"},{"location":"os/tutorials/olimex/#prepare-the-hardware-to-boot-from-flash","text":"Locate the boot jumpers on the board. B1_1/B1_0 and B0_1/B0_0 are PTH jumpers. Note that because the markings on the board may not always be accurate, when in doubt, you should always refer to the manual for the correct positioning. Since the jumpers are a pair, they should move together, and as such, the pair is responsible for the boot mode when bootloader is present. To locate the bootloader, the board searches in three places: User Flash Memory, System Memory or the Embedded SRAM. For this Blinky project, we will configure it to boot from flash by jumpering B0_0 and B1_0 . Connect USB-OTG#2 in the picture above to a USB port on your computer (or a powered USB hub to make sure there is enough power available to the board). The red PWR LED should be lit. Connect the JTAG connector to the SWD/JTAG interface on the board. The other end of the cable should be connected to the USB port or hub of your computer.","title":"Prepare the hardware to boot from flash"},{"location":"os/tutorials/olimex/#lets-go","text":"Load the images $ newt -v load boot_olimex Loading image with: ~/dev/myproj/repos/apache-mynewt-core/hw/bsp/olimex_stm32-e407_devboard/olimex_stm32-e407_devboard_download.sh ~/dev/myproj/repos/apache-mynewt-core/hw/bsp/olimex_stm32-e407_devboard/ ~/dev/myproj/bin/boot_olimex/apps/boot/boot BASELIBC FS LIBC NFFS bootloader Successfully loaded image. $ newt -v load blinky Loading image with: ~/dev/myproj/repos/apache-mynewt-core/hw/bsp/olimex_stm32-e407_devboard/olimex_stm32-e407_devboard_download.sh ~/dev/myproj/repos/apache-mynewt-core/hw/bsp/olimex_stm32-e407_devboard/ ~/dev/myproj/bin/blinky/apps/blinky/blinky BASELIBC LIBC Successfully loaded image. Voil\u00e0! The LED should be blinking! Success! But wait...not so fast. Let's double check that it is indeed booting from flash and making the LED blink from the image in flash. Pull the USB cable off the Olimex JTAG adaptor, severing the debug connection to the JTAG port. Next power off the Olimex board by pulling out the USB cable from the board. Wait for a couple of seconds and plug the USB cable back to the board. The LED light will start blinking again. Success! Note #1: If you want to download the image to flash and a gdb session opened up, use newt debug blinky . Type c to continue inside the gdb session. $ newt debug blinky Debugging with ~/dev/myproj/hw/bsp/olimex_stm32-e407_... Debugging ~/dev/myproj/project/blinky/bin/blinky/blinky.elf GNU gdb (GNU Tools for ARM Embedded Processors) 7.8.0.20150604-cvs Copyright (C) 2014 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 <http://gnu.org/licenses/gpl.html> ... (info) ... target state: halted target halted due to debug-request, current mode: Thread xPSR: 0x01000000 pc: 0x08000250 msp: 0x10010000 Info : accepting 'gdb' connection from 3333 Info : device id = 0x10036413 Info : flash size = 1024kbytes Reset_Handler () at startup_STM32F40x.s:199 199 ldr r1, =__etext (gdb) Note #2: If you want to erase the flash and load the image again you may use the following commands from within gdb. flash erase_sector 0 0 x tells it to erase sectors 0 through x. When you ask it to display (in hex notation) the contents of the sector starting at location 'lma,' you should see all f's. The memory location 0x8000000 is the start or origin of the flash memory contents and is specified in the olimex_stm32-e407_devboard.ld linker script. The flash memory locations is specific to the processor. (gdb) monitor flash erase_sector 0 0 4 erased sectors 0 through 4 on flash bank 0 in 2.296712s (gdb) monitor mdw 0x08000000 16 0x08000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff (0x08000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff (0x08000000: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff (0x08000020: ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff (gdb) monitor flash info 0","title":"Let's Go!"},{"location":"os/tutorials/olimex/#conclusion","text":"Congratulations! You have now tried out a project on actual hardware. If this is your first time to embedded systems, this must feel like the best hands-on and low-level \"Hello World\" program ever. Good, we have more fun tutorials for you to get your hands dirty. Be bold and try other Blinky-like tutorials or try enabling additional functionality such as remote comms on the current board. If you see anything missing or want to send us feedback, please do so by signing up for appropriate mailing lists on our Community Page . Keep on hacking and blinking!","title":"Conclusion"},{"location":"os/tutorials/pin-wheel-mods/","text":"Pin Wheel Modifications to \"Blinky\" on STM32F3 Discovery Objective Learn how to modify an existing app -- the blinky app -- to light all the LEDs on the STM32F3 Discovery board. What you need Discovery kit with STM32F303VC MCU Laptop running Mac OSX. It is assumed you have already installed and run the blinky app succesfully. Since you've already successfully created your blinky app project, you'll need to modify only one file, main.c, in order to get this app working. The main.c file resides in the apps/blinky/src directory in your project folder so you can edit it with your favorite editor. You'll make the following changes: Replace the line: int g_led_pin ; With the line: int g_led_pins [ 8 ] = { LED_BLINK_PIN_1 , LED_BLINK_PIN_2 , LED_BLINK_PIN_3 , LED_BLINK_PIN_4 , LED_BLINK_PIN_5 , LED_BLINK_PIN_6 , LED_BLINK_PIN_7 , LED_BLINK_PIN_8 }; So that you now have an array of all 8 LED Pins on the board. Delete the line: g_led_pin = LED_BLINK_PIN ; And in its place, add the following lines to initialize all the LED_PINS correctly: int x ; for ( x = 0 ; x < 8 ; x++ ){ hal_gpio_init_out ( g_led_pins [ x ], 1 ); } int p = 0 ; We'll use that 'p' later. Next you'll want to change the line: os_time_delay ( 1000 ); to a shorter time in order to make it a little more interesting. A full 1 second delay doesn't look great, so try 100 for starters and then you can adjust it to your liking. Finally, change the line: hal_gpio_toggle ( g_led_pin ); to look like this: hal_gpio_toggle ( g_led_pins [ p++ ]); p = ( p > 7 ) ? 0 : p ; Build the target and executables and download the images Run the same commands you used on the blinky app to build and load this one: $ newt create-image stmf3_blinky 1.2.3 App image successfully generated: ~/dev/myproj/bin/stmf3_blinky/apps/blinky/blinky.img Build manifest:~/dev/myproj/bin/stmf3_blinky/apps/blinky/manifest.json $ newt -v load stmf3_boot $ newt -v load stmf3_blinky Watch the LEDs go round and round The colored LEDs should now all light up in succession, and once they're all lit, they should then go off in the same order. This should repeat continuously. If you see anything missing or want to send us feedback, please do so by signing up for appropriate mailing lists on our Community Page . Keep on hacking and blinking!","title":"Pinwheel Blinky"},{"location":"os/tutorials/pin-wheel-mods/#pin-wheel-modifications-to-blinky-on-stm32f3-discovery","text":"","title":"Pin Wheel Modifications to \"Blinky\" on STM32F3 Discovery"},{"location":"os/tutorials/pin-wheel-mods/#objective","text":"Learn how to modify an existing app -- the blinky app -- to light all the LEDs on the STM32F3 Discovery board.","title":"Objective"},{"location":"os/tutorials/pin-wheel-mods/#what-you-need","text":"Discovery kit with STM32F303VC MCU Laptop running Mac OSX. It is assumed you have already installed and run the blinky app succesfully. Since you've already successfully created your blinky app project, you'll need to modify only one file, main.c, in order to get this app working. The main.c file resides in the apps/blinky/src directory in your project folder so you can edit it with your favorite editor. You'll make the following changes: Replace the line: int g_led_pin ; With the line: int g_led_pins [ 8 ] = { LED_BLINK_PIN_1 , LED_BLINK_PIN_2 , LED_BLINK_PIN_3 , LED_BLINK_PIN_4 , LED_BLINK_PIN_5 , LED_BLINK_PIN_6 , LED_BLINK_PIN_7 , LED_BLINK_PIN_8 }; So that you now have an array of all 8 LED Pins on the board. Delete the line: g_led_pin = LED_BLINK_PIN ; And in its place, add the following lines to initialize all the LED_PINS correctly: int x ; for ( x = 0 ; x < 8 ; x++ ){ hal_gpio_init_out ( g_led_pins [ x ], 1 ); } int p = 0 ; We'll use that 'p' later. Next you'll want to change the line: os_time_delay ( 1000 ); to a shorter time in order to make it a little more interesting. A full 1 second delay doesn't look great, so try 100 for starters and then you can adjust it to your liking. Finally, change the line: hal_gpio_toggle ( g_led_pin ); to look like this: hal_gpio_toggle ( g_led_pins [ p++ ]); p = ( p > 7 ) ? 0 : p ;","title":"What you need"},{"location":"os/tutorials/pin-wheel-mods/#build-the-target-and-executables-and-download-the-images","text":"Run the same commands you used on the blinky app to build and load this one: $ newt create-image stmf3_blinky 1.2.3 App image successfully generated: ~/dev/myproj/bin/stmf3_blinky/apps/blinky/blinky.img Build manifest:~/dev/myproj/bin/stmf3_blinky/apps/blinky/manifest.json $ newt -v load stmf3_boot $ newt -v load stmf3_blinky","title":"Build the target and executables and download the images"},{"location":"os/tutorials/pin-wheel-mods/#watch-the-leds-go-round-and-round","text":"The colored LEDs should now all light up in succession, and once they're all lit, they should then go off in the same order. This should repeat continuously. If you see anything missing or want to send us feedback, please do so by signing up for appropriate mailing lists on our Community Page . Keep on hacking and blinking!","title":"Watch the LEDs go round and round"},{"location":"os/tutorials/project-slinky/","text":"Project Sim Slinky Objective The goal of the project is to enable and demonstrate remote communications with the Mynewt OS via newt manager (newtmgr). We will do this through building a project with Mynewt called Slinky that runs via the native platform. What you need 1.Personal Computer The instructions assume the user is using a Bourne-compatible shell (e.g. bash or zsh) on your computer. The given instructions have been tested with the following releases of operating systems: Mac: OS X Yosemite Version 10.10.5 Overview of steps Install dependencies Define a target using the newt tool Build executables for the targets using the newt tool Set up serial connection with the targets Create a connection profile using the newtmgr tool Use the newtmgr tool to communicate with the targets Installing newt If you have not already installed newt see the newt installation instructions and ensure newt is installed an in your path. Installing newtmgr If you have not already installed newtmgr see the newtmgr installation instructions and ensure newtmgr is installed an in your path. Creating a new project Instructions for creating a project are located in the Basic Setup section of the Mynewt Documentation We will list only the steps here for brevity. We will name the project slinky . $ newt new slinky Downloading project skeleton from apache/incubator-mynewt-blinky... ... Installing skeleton in slink... Project slink successfully created $ cd slinky $ newt install -v Downloading repository description for apache-mynewt-core... success! ... Repos successfully installed Setting up your target build Create a target for slinky using the native bsp. We will list only the steps and suppress the tool output here for brevity. $ newt target create sim_slinky $ newt target set sim_slinky bsp=@apache-mynewt-core/hw/bsp/native $ newt target set sim_slinky build_profile=debug $ newt target set sim_slinky app=@apache-mynewt-core/apps/slinky Building Your target To build your target, use newt build . When complete, an executable file is created. $ newt build sim_slinky Compiling main.c ... Linking slinky.elf App successfully built: ~/dev/slinky/bin/sim_slinky/apps/slinky/slinky.elf Run the target Run the executable you have build for the simulated environment. The serial port name on which the simulated target is connected is shown in the output when mynewt slinky starts. $ ~/dev/slinky/bin/sim_slinky/apps/slinky/slinky.elf uart0 at /dev/ttys005 In this example, the slinky app opened up a com port /dev/ttys005 for communications with newtmgr. NOTE: This application will block. You will need to open a new console (or execute this in another console) to continue the tutorial.* Setting up a connection profile You will now set up a connection profile using newtmgr for the serial port connection and start communicating with the simulated remote device. $ newtmgr conn add sim1 type=serial connstring=/dev/ttys005 Connection profile sim1 successfully added $ newtmgr conn show Connection profiles: sim1: type=serial, connstring='/dev/ttys007' Executing newtmgr commands with the target You can now use connection profile sim1 to talk to the running sim_blinky. As an example, we will query the running mynewt OS for the usage of its memory pools. $ newtmgr -c sim1 mpstats Return Code = 0 nffs_cache_inode_pool (blksize=36 nblocks=4 nfree=4) nffs_cache_block_pool (blksize=32 nblocks=64 nfree=64) nffs_dir_pool (blksize=8 nblocks=4 nfree=4) default_mbuf_data (blksize=256 nblocks=10 nfree=8) nffs_file_pool (blksize=12 nblocks=4 nfree=4) nffs_inode_entry_pool (blksize=24 nblocks=100 nfree=98) nffs_block_entry_pool (blksize=12 nblocks=100 nfree=100) As a test command, you can send an arbitrary string to the target and it will echo that string back in a response to newtmgr. $ newtmgr -c sim1 echo \"Hello Mynewt\" {\"r\": \"Hello Mynewt\"} The response comes back as a json string. In addition to these, you can also examine running tasks, statistics, logs, image status (not on sim), and configuration.","title":"Enable remote comms on sim device"},{"location":"os/tutorials/project-slinky/#project-sim-slinky","text":"","title":"Project Sim Slinky"},{"location":"os/tutorials/project-slinky/#objective","text":"The goal of the project is to enable and demonstrate remote communications with the Mynewt OS via newt manager (newtmgr). We will do this through building a project with Mynewt called Slinky that runs via the native platform.","title":"Objective"},{"location":"os/tutorials/project-slinky/#what-you-need","text":"1.Personal Computer The instructions assume the user is using a Bourne-compatible shell (e.g. bash or zsh) on your computer. The given instructions have been tested with the following releases of operating systems: Mac: OS X Yosemite Version 10.10.5","title":"What you need"},{"location":"os/tutorials/project-slinky/#overview-of-steps","text":"Install dependencies Define a target using the newt tool Build executables for the targets using the newt tool Set up serial connection with the targets Create a connection profile using the newtmgr tool Use the newtmgr tool to communicate with the targets","title":"Overview of steps"},{"location":"os/tutorials/project-slinky/#installing-newt","text":"If you have not already installed newt see the newt installation instructions and ensure newt is installed an in your path.","title":"Installing newt"},{"location":"os/tutorials/project-slinky/#installing-newtmgr","text":"If you have not already installed newtmgr see the newtmgr installation instructions and ensure newtmgr is installed an in your path.","title":"Installing newtmgr"},{"location":"os/tutorials/project-slinky/#creating-a-new-project","text":"Instructions for creating a project are located in the Basic Setup section of the Mynewt Documentation We will list only the steps here for brevity. We will name the project slinky . $ newt new slinky Downloading project skeleton from apache/incubator-mynewt-blinky... ... Installing skeleton in slink... Project slink successfully created $ cd slinky $ newt install -v Downloading repository description for apache-mynewt-core... success! ... Repos successfully installed","title":"Creating a new project"},{"location":"os/tutorials/project-slinky/#setting-up-your-target-build","text":"Create a target for slinky using the native bsp. We will list only the steps and suppress the tool output here for brevity. $ newt target create sim_slinky $ newt target set sim_slinky bsp=@apache-mynewt-core/hw/bsp/native $ newt target set sim_slinky build_profile=debug $ newt target set sim_slinky app=@apache-mynewt-core/apps/slinky","title":"Setting up your target build"},{"location":"os/tutorials/project-slinky/#building-your-target","text":"To build your target, use newt build . When complete, an executable file is created. $ newt build sim_slinky Compiling main.c ... Linking slinky.elf App successfully built: ~/dev/slinky/bin/sim_slinky/apps/slinky/slinky.elf","title":"Building Your target"},{"location":"os/tutorials/project-slinky/#run-the-target","text":"Run the executable you have build for the simulated environment. The serial port name on which the simulated target is connected is shown in the output when mynewt slinky starts. $ ~/dev/slinky/bin/sim_slinky/apps/slinky/slinky.elf uart0 at /dev/ttys005 In this example, the slinky app opened up a com port /dev/ttys005 for communications with newtmgr. NOTE: This application will block. You will need to open a new console (or execute this in another console) to continue the tutorial.*","title":"Run the target"},{"location":"os/tutorials/project-slinky/#setting-up-a-connection-profile","text":"You will now set up a connection profile using newtmgr for the serial port connection and start communicating with the simulated remote device. $ newtmgr conn add sim1 type=serial connstring=/dev/ttys005 Connection profile sim1 successfully added $ newtmgr conn show Connection profiles: sim1: type=serial, connstring='/dev/ttys007'","title":"Setting up a connection profile"},{"location":"os/tutorials/project-slinky/#executing-newtmgr-commands-with-the-target","text":"You can now use connection profile sim1 to talk to the running sim_blinky. As an example, we will query the running mynewt OS for the usage of its memory pools. $ newtmgr -c sim1 mpstats Return Code = 0 nffs_cache_inode_pool (blksize=36 nblocks=4 nfree=4) nffs_cache_block_pool (blksize=32 nblocks=64 nfree=64) nffs_dir_pool (blksize=8 nblocks=4 nfree=4) default_mbuf_data (blksize=256 nblocks=10 nfree=8) nffs_file_pool (blksize=12 nblocks=4 nfree=4) nffs_inode_entry_pool (blksize=24 nblocks=100 nfree=98) nffs_block_entry_pool (blksize=12 nblocks=100 nfree=100) As a test command, you can send an arbitrary string to the target and it will echo that string back in a response to newtmgr. $ newtmgr -c sim1 echo \"Hello Mynewt\" {\"r\": \"Hello Mynewt\"} The response comes back as a json string. In addition to these, you can also examine running tasks, statistics, logs, image status (not on sim), and configuration.","title":"Executing newtmgr commands with the target"},{"location":"os/tutorials/project-target-slinky/","text":"Project Slinky Objective The goal of the project is to enable and demonstrate remote communications with the Mynewt OS via newt manager (newtmgr). We will do this through a project with Mynewt called Slinky that runs on the STM32-E407 board. What you need STM32-E407 development board from Olimex. You can order it from http://www.mouser.com , http://www.digikey.com , and other places. ARM-USB-TINY-H connector with JTAG interface for debugging ARM microcontrollers (comes with the ribbon cable to hook up to the board) USB A-B type cable to connect the debugger to your personal computer A USB to TTL Serial Cable with female wiring harness. An example is http://www.amazon.com/JBtek\u00ae-WINDOWS-Supported-Raspberry-Programming/dp/B00QT7LQ88/ref=lp_464404_1_9?s=pc&ie=UTF8&qid=1454631303&sr=1-9 Personal Computer The instructions assume the user is using a Bourne-compatible shell (e.g. bash or zsh) on your computer. The given instructions have been tested with the following releases of operating systems: Mac: OS X Yosemite Version 10.10.5 Overview of steps Install dependencies Define a target using the newt tool Build executables for the targets using the newt tool Set up serial connection with the targets Create a connection profile using the newtmgr tool Use the newtmgr tool to communicate with the targets Install newt If you have not already installed newt , see the newt installation instructions and ensure newt is installed an in your path. Install newtmgr If you have not already installed newtmgr , see the newtmgr installation instructions and ensure newtmgr is installed an in your path. Create a new project Instructions for creating a project are located in the Basic Setup section of the Mynewt Documentation . If you already completed Sim Slinky you can skip this step. We will list only the steps here for brevity. We will name the project slinky . $ newt new slinky Downloading project skeleton from apache/incubator-mynewt-blinky... ... Installing skeleton in slink... Project slink successfully created $ cd slinky $newt install -v Downloading repository description for apache-mynewt-core... success! ... Repos successfully installed Set up your target builds Create a target for stm32_slinky using the native BSP. The Newt tool output is suppressed below for brevity. $ newt target create stm32_slinky $ newt target set stm32_slinky bsp=@apache-mynewt-core/hw/bsp/olimex_stm32-e407_devboard $ newt target set stm32_slinky build_profile=debug $ newt target set stm32_slinky app=@apache-mynewt-core/apps/slinky Create a second target for stm32_bootloader to build a bootloader to boot the stm32_slinky image. The tool output is suppressed below for brevity. $ newt target create stm32_bootloader $ newt target set stm32_bootloader bsp=@apache-mynewt-core/hw/bsp/olimex_stm32-e407_devboard $ newt target set stm32_bootloader build_profile=optimized $ newt target set stm32_bootloader target.app=@apache-mynewt-core/apps/boot Build Targets $ newt build stm32_slinky Compiling main.c ... Linking slinky.elf App successfully built: ~/dev/slinky/bin/stm32_slinky/apps/slinky/slinky.elf newt build stm32_bootloader Compiling crc16.c ... Linking boot.elf App successfully built: ~/slinky/bin/stm32_bootloader/apps/boot/boot.elf For the main image, you need to create an image using newt create-image. Give this image some arbitrary version number \"1.2.3\". $ newt create-image stm32_slinky 1.2.3 App image successfully generated: /Users/paulfdietrich/dev/slinky/bin/stm32_slinky/apps/slinky/slinky.img Build manifest: /Users/paulfdietrich/dev/slinky/bin/stm32_slinky/apps/slinky/manifest.json Using newtmgr with a remote target First make sure the USB A-B type cable is connected to the ARM-USB-TINY-H debugger connector on the Olimex board. Next go the to project directory and download the slinky project image to the flash of the Olimex board. $ newt load stm32_bootloader $ newt load stm32_slinky You can now disconnect the debugging cable from the board. You should see the green LED blinking. If not, try powercycling the board. Now you have to set up the serial connection from your computer to the Olimex board. Locate the PC6/USART6_TX (pin#3), PC7/USART6_RX (pin#4), and GND (pin#2) of the UEXT connector on the Olimex board. More information on the UEXT connector can be found at https://www.olimex.com/Products/Modules/UEXT/ . The schematic of the board can be found at https://www.olimex.com/Products/ARM/ST/STM32-E407/resources/STM32-E407_sch.pdf for reference. Connect the female RX pin of the USB-TTL serial cable to the TX of the UEXT connector on the board. Connect the female TX pin of the USB-TTL serial cable to the RX of the UEXT connector on the board. Connect the GND pin of the USB-TTL serial cable to the GND of the UEXT connector on the board. Locate the serial connection established in the /dev directory of your computer. It should be of the type tty.usbserial-<some identifier> . $ ls /dev/tty.usbserial-AJ03HAQQ /dev/tty.usbserial-AJ03HAQQ You now have to define a connection profile using newtmgr. You can give it any name you want. The example below shows the connection profile being named as the very imaginative olimex01 . $ pwd /Users/<user>/dev/larva/project/slinky $ newtmgr conn add olimex01 type=serial connstring=/dev/tty.usbserial-AJ03HAQQ Connection profile olimex01 successfully added $ newtmgr conn show Connection profiles: sim1: type=serial, connstring='/dev/ttys007' olimex01: type=serial, connstring='/dev/tty.usbserial-AJ03HAQQ' Now go ahead and query the Olimex board to get responses back. The simplest command is the echo command to ask it to respond with the text you send it. $ newtmgr echo -c olimex01 hello {\"r\": \"hello\"} $ newtmgr image -c olimex01 list Images: 0 : 1.2.3 $ newtmgr -c olimex01 taskstats Return Code = 0 newtmgr (prio=4 tid=2 runtime=0 cswcnt=12 stksize=512 stkusage=255 last_checkin=0 next_checkin=0) task1 (prio=1 tid=3 runtime=0 cswcnt=299 stksize=128 stkusage=33 last_checkin=0 next_checkin=0) task2 (prio=2 tid=4 runtime=0 cswcnt=300 stksize=128 stkusage=31 last_checkin=0 next_checkin=0) idle (prio=255 tid=0 runtime=299916 cswcnt=313 stksize=32 stkusage=18 last_checkin=0 next_checkin=0) shell (prio=3 tid=1 runtime=1 cswcnt=20 stksize=384 stkusage=60 last_checkin=0 next_checkin=0)","title":"Enable remote comms on STM32 board"},{"location":"os/tutorials/project-target-slinky/#project-slinky","text":"","title":"Project Slinky"},{"location":"os/tutorials/project-target-slinky/#objective","text":"The goal of the project is to enable and demonstrate remote communications with the Mynewt OS via newt manager (newtmgr). We will do this through a project with Mynewt called Slinky that runs on the STM32-E407 board.","title":"Objective"},{"location":"os/tutorials/project-target-slinky/#what-you-need","text":"STM32-E407 development board from Olimex. You can order it from http://www.mouser.com , http://www.digikey.com , and other places. ARM-USB-TINY-H connector with JTAG interface for debugging ARM microcontrollers (comes with the ribbon cable to hook up to the board) USB A-B type cable to connect the debugger to your personal computer A USB to TTL Serial Cable with female wiring harness. An example is http://www.amazon.com/JBtek\u00ae-WINDOWS-Supported-Raspberry-Programming/dp/B00QT7LQ88/ref=lp_464404_1_9?s=pc&ie=UTF8&qid=1454631303&sr=1-9 Personal Computer The instructions assume the user is using a Bourne-compatible shell (e.g. bash or zsh) on your computer. The given instructions have been tested with the following releases of operating systems: Mac: OS X Yosemite Version 10.10.5","title":"What you need"},{"location":"os/tutorials/project-target-slinky/#overview-of-steps","text":"Install dependencies Define a target using the newt tool Build executables for the targets using the newt tool Set up serial connection with the targets Create a connection profile using the newtmgr tool Use the newtmgr tool to communicate with the targets","title":"Overview of steps"},{"location":"os/tutorials/project-target-slinky/#install-newt","text":"If you have not already installed newt , see the newt installation instructions and ensure newt is installed an in your path.","title":"Install newt"},{"location":"os/tutorials/project-target-slinky/#install-newtmgr","text":"If you have not already installed newtmgr , see the newtmgr installation instructions and ensure newtmgr is installed an in your path.","title":"Install newtmgr"},{"location":"os/tutorials/project-target-slinky/#create-a-new-project","text":"Instructions for creating a project are located in the Basic Setup section of the Mynewt Documentation . If you already completed Sim Slinky you can skip this step. We will list only the steps here for brevity. We will name the project slinky . $ newt new slinky Downloading project skeleton from apache/incubator-mynewt-blinky... ... Installing skeleton in slink... Project slink successfully created $ cd slinky $newt install -v Downloading repository description for apache-mynewt-core... success! ... Repos successfully installed","title":"Create a new project"},{"location":"os/tutorials/project-target-slinky/#set-up-your-target-builds","text":"Create a target for stm32_slinky using the native BSP. The Newt tool output is suppressed below for brevity. $ newt target create stm32_slinky $ newt target set stm32_slinky bsp=@apache-mynewt-core/hw/bsp/olimex_stm32-e407_devboard $ newt target set stm32_slinky build_profile=debug $ newt target set stm32_slinky app=@apache-mynewt-core/apps/slinky Create a second target for stm32_bootloader to build a bootloader to boot the stm32_slinky image. The tool output is suppressed below for brevity. $ newt target create stm32_bootloader $ newt target set stm32_bootloader bsp=@apache-mynewt-core/hw/bsp/olimex_stm32-e407_devboard $ newt target set stm32_bootloader build_profile=optimized $ newt target set stm32_bootloader target.app=@apache-mynewt-core/apps/boot","title":"Set up your target builds"},{"location":"os/tutorials/project-target-slinky/#build-targets","text":"$ newt build stm32_slinky Compiling main.c ... Linking slinky.elf App successfully built: ~/dev/slinky/bin/stm32_slinky/apps/slinky/slinky.elf newt build stm32_bootloader Compiling crc16.c ... Linking boot.elf App successfully built: ~/slinky/bin/stm32_bootloader/apps/boot/boot.elf For the main image, you need to create an image using newt create-image. Give this image some arbitrary version number \"1.2.3\". $ newt create-image stm32_slinky 1.2.3 App image successfully generated: /Users/paulfdietrich/dev/slinky/bin/stm32_slinky/apps/slinky/slinky.img Build manifest: /Users/paulfdietrich/dev/slinky/bin/stm32_slinky/apps/slinky/manifest.json","title":"Build Targets"},{"location":"os/tutorials/project-target-slinky/#using-newtmgr-with-a-remote-target","text":"First make sure the USB A-B type cable is connected to the ARM-USB-TINY-H debugger connector on the Olimex board. Next go the to project directory and download the slinky project image to the flash of the Olimex board. $ newt load stm32_bootloader $ newt load stm32_slinky You can now disconnect the debugging cable from the board. You should see the green LED blinking. If not, try powercycling the board. Now you have to set up the serial connection from your computer to the Olimex board. Locate the PC6/USART6_TX (pin#3), PC7/USART6_RX (pin#4), and GND (pin#2) of the UEXT connector on the Olimex board. More information on the UEXT connector can be found at https://www.olimex.com/Products/Modules/UEXT/ . The schematic of the board can be found at https://www.olimex.com/Products/ARM/ST/STM32-E407/resources/STM32-E407_sch.pdf for reference. Connect the female RX pin of the USB-TTL serial cable to the TX of the UEXT connector on the board. Connect the female TX pin of the USB-TTL serial cable to the RX of the UEXT connector on the board. Connect the GND pin of the USB-TTL serial cable to the GND of the UEXT connector on the board. Locate the serial connection established in the /dev directory of your computer. It should be of the type tty.usbserial-<some identifier> . $ ls /dev/tty.usbserial-AJ03HAQQ /dev/tty.usbserial-AJ03HAQQ You now have to define a connection profile using newtmgr. You can give it any name you want. The example below shows the connection profile being named as the very imaginative olimex01 . $ pwd /Users/<user>/dev/larva/project/slinky $ newtmgr conn add olimex01 type=serial connstring=/dev/tty.usbserial-AJ03HAQQ Connection profile olimex01 successfully added $ newtmgr conn show Connection profiles: sim1: type=serial, connstring='/dev/ttys007' olimex01: type=serial, connstring='/dev/tty.usbserial-AJ03HAQQ' Now go ahead and query the Olimex board to get responses back. The simplest command is the echo command to ask it to respond with the text you send it. $ newtmgr echo -c olimex01 hello {\"r\": \"hello\"} $ newtmgr image -c olimex01 list Images: 0 : 1.2.3 $ newtmgr -c olimex01 taskstats Return Code = 0 newtmgr (prio=4 tid=2 runtime=0 cswcnt=12 stksize=512 stkusage=255 last_checkin=0 next_checkin=0) task1 (prio=1 tid=3 runtime=0 cswcnt=299 stksize=128 stkusage=33 last_checkin=0 next_checkin=0) task2 (prio=2 tid=4 runtime=0 cswcnt=300 stksize=128 stkusage=31 last_checkin=0 next_checkin=0) idle (prio=255 tid=0 runtime=299916 cswcnt=313 stksize=32 stkusage=18 last_checkin=0 next_checkin=0) shell (prio=3 tid=1 runtime=1 cswcnt=20 stksize=384 stkusage=60 last_checkin=0 next_checkin=0)","title":"Using newtmgr with a remote target"},{"location":"os/tutorials/tasks_lesson/","text":"Core OS Lesson: Tasks and Priority Management Target Platform: Arduino M0 Pro (or legacy Arduino Zero or Zero Pro, but not Arduino M0) This lesson is designed to teach core OS concepts and strategies encountered when building applications using Mynewt. Specifically, this lesson will cover tasks, simple multitasking, and priority management running on an Arduino M0 Pro. Prerequisites Before starting, you should read about Mynewt in the Introduction section and complete the QuickStart guide and the Blinky tutorial. Furthermore, it may be helpful to take a peek at the task documentation for additional insights. Equipment You will need the following equipment: Arduino M0 Pro (or legacy Arduino Zero or Zero Pro, but not Arduino M0) Computer with Mynewt installed USB to Micro USB Cable Build Your Application To save time, we will simply modify the Blinky app. We'll add the Task Management code to the Blinky app. Follow the Arduino Zero Blinky tutorial to create a new project and build your bootloader and application. Finally, build and load the application to your Arduino to verify that everything is in order. Now let\u2019s get started! Create a New Task The purpose of this section is to give an introduction to the important aspects of tasks and how to properly initialize them. First, let\u2019s define a second task called work_task in main.c (located in apps/blinky/src): struct os_task work_task ; A task is represented by the os_task struct which will hold the task\u2019s information (name, state, priority, etc.). A task is made up of two main elements, a task function (also known as a task handler) and a task stack. Next, let\u2019s take a look at what is required to initialize our new task. Task Stack The task stack is an array of type os_stack_t which holds the program stack frames. Mynewt gives us the ability to set the stack size for a task giving the application developer room to optimize memory usage. Since we\u2019re not short on memory, our blinky_stack and work_stack are plenty large for the purpose of this lesson. Notice that the elements in our task stack are of type os_stack_t which are generally 32 bits, making our entire stack 1024 Bytes. #define WORK_STACK_SIZE OS_STACK_ALIGN(256) os_stack_t work_stack [ WORK_STACK_SIZE ]; Note: The OS_STACK_ALIGN macro is used to align the stack based on the hardware architecture. Task Function The task function is essentially an infinite loop which waits for some \u201cevent\u201d to wake it up. In our Blinky app the task function, named blinky_task_handler() , is initially called when we call os_start() in main() . In general, the task function is where the majority of work is done by a task. Let\u2019s write a task function for work_task called work_task_handler() : void work_task_handler ( void *arg ) { struct os_task *t ; g_led_pin = LED_BLINK_PIN ; hal_gpio_init_out ( g_led_pin , 1 ); while ( 1 ) { t = os_sched_get_current_task (); assert ( t->t_func == work_task_handler ); /* Do work... */ } } The task function is called when the task is initially put into the running state by the scheduler. We use an infinite loop to ensure that the task function never returns. Our assertion that the current task's handler is the same as our task handler is for illustration purposes only and does not need to be in most task functions. Task Priority As a preemptive, multitasking RTOS, Mynewt decides which tasks to run based on which has a higher priority; the highest priority being 0 and the lowest 255. Thus, before initializing our task, we must choose a priority defined as a macro variable. Let\u2019s set the priority of work_task to 0, because everyone knows that work is more important than blinking. #define WORK_TASK_PRIO (0) Initialization To initialize a new task we use os_task_init() which takes a number of arguments including our new task function, stack, and priority. Much like blinky_task , we\u2019re going to initialize work_task inside init_tasks to keep our main function clean. int init_tasks ( void ) { /* \u2026 */ os_task_init ( &work_task , \"work\" , work_task_handler , NULL , WORK_TASK_PRIO , OS_WAIT_FOREVER , work_stack , WORK_STACK_SIZE ); tasks_initialized = 1 ; return 0 ; } And that\u2019s it! Now run your application using the newt run command. $ newt run arduino_blinky 0.0.0 When GDB appears press C then Enter to continue and \u2026 wait, why doesn't our LED blink anymore? Review Before we run our new app, let\u2019s review what we need in order to create a task. This is a general case for a new task called mytask: 1) Define a new task, task stack, and priority: /* My Task */ struct os_task mytask /* My Task Stack */ #define MYTASK_STACK_SIZE OS_STACK_ALIGN(256) os_stack_t mytask_stack [ MYTASK_STACK_SIZE ]; /* My Task Priority */ #define MYTASK_PRIO (0) 2) Define task function: void mytask_handler ( void *arg ) { while ( 1 ) { /* ... */ } } 3) Initialize task before calling os_start() : os_task_init ( &mytask , \"mytask\" , mytask_handler , NULL , MYTASK_PRIO , OS_WAIT_FOREVER , mytask_stack , MYTASK_STACK_SIZE ); Task Priority, Preempting, and Context Switching A preemptive RTOS is one in which a higher priority task that is ready to run will preempt (i.e. take the place of) the lower priority task which is running . When a lower priority task is preempted by a higher priority task, the lower priority task\u2019s context data (stack pointer, registers, etc.) is saved and the new task is switched in. In our example, work_task has a higher priority than blinky_task and, because it is never put into a sleep state, holds the processor focus on its context. Let\u2019s give work_task a delay and some simulated work to keep it busy. Because the delay is measured in os ticks, the actual number of ticks per second is dependent on the board. Therefore, we multiply OS_TICKS_PER_SEC , which is defined in the MCU, by the number of seconds we wish to delay. void work_task_handler ( void *arg ) { struct os_task *t ; g_led_pin = LED_BLINK_PIN ; hal_gpio_init_out ( g_led_pin , 1 ); while ( 1 ) { t = os_sched_get_current_t:ask (); assert ( t->t_func == work_task_handler ); /* Do work... */ int i ; for ( i = 0 ; i < 1000000 ; ++i ) { /* Simulate doing a noticeable amount of work */ hal_gpio_set ( g_led_pin ); } os_time_delay ( 3 *OS_TICKS_PER_SECOND ); } } In order to notice the LED changing, modify the time delay in blinky_task_handler() to blink at a higher frequency. os_time_delay ( OS_TICKS_PER_SEC/ 10 ); Before we run the app, let\u2019s predict the behavior. With the newest additions to work_task_handler() , our first action will be to sleep for three seconds. This will allow blinky_task to take over the CPU and blink to its heart\u2019s content. After three seconds, work_task will wake up and be made ready to run , causing it to preempt blinky_task . The LED will then remain lit for a short period while work_task loops, then blink again for another three seconds while work_task sleeps. Voila, you should see that our prediction was correct! Priority Management Considerations When projects grow in scope, from blinking LEDs into more sophisticated applications, the number of tasks needed increases alongside complexity. It remains important, then, that each of our tasks is capable of doing its work within a reasonable amount of time. Some tasks, such as the Shell task, execute quickly and require almost instantaneous response. Therefore, the Shell task should be given a high priority. On the other hand, tasks which may be communicating over a network, or processing data, should be given a low priority in order to not hog the CPU. The diagram below showcases the different scheduling patterns we. would expect from swapping blinky and work tasks priorities. In the second case where blinky_task has a higher priority, the \u201cwork\u201d done by work_task would be executed during the millisecond delays in blinky_task , saving us idle time compared to the first case. Note: Defining the same priority for two tasks leads to somewhat undefined behavior and should be avoided. Comparing Priority Strategies Instead of stepping through a bunch of changes to our blinky app, clone my task lesson application from github and copy an existing target. Change directory into apps and clone the repository to get our new files: $ cd apps $ git clone https://github.com/bgiori/mynewt_tasks_lesson.git Change directory back to your project root and copy the arduino_blinky target to a new target called task_tgt. $ newt target copy arduino_blinky task_tgt Set a new app location. $ newt target set task_tgt app=apps/mynewt_tasks_lesson Now let\u2019s take a look at our new code. First, notice that we have abandoned blinking, instead choosing t o use the console and shell to follow our tasks through execution. Additionally, we have a number of different tasks: Task A ( a_task ): Priority : 3 \u2192 2 Description : Task A is supposed to represent a task which frequently does a small amount of work, such as one which rapidly polls a sensor for data. Much like blinky_task , Task A will loop 10,000 times then wait 1 millisecond. Priority is changed by timer_task after the first simulation. Task B ( b_task ): Priority : 2 \u2192 3 Description : Task B is supposed to represent a task which does a large amount of work relatively infrequently, such as one which sends/receives data from the cloud. Like work_task, Task B will loop 1,000,000 times then wait 3 seconds. Priority is changed by timer_task after the first simulation. Timer Task ( timer_task ): Priority : 1 Description : With default settings, Timer Task will wait 20 seconds then print the first simulations data for Task A and B. Timer task will then swap A and B\u2019s priorities and restart the simulation. After the second simulation, timer will again print simulation data then compare the two and calculate a final speedup (simulation2 / simulation1). Shell Task : Priority : 0 Description : Task used by Shell behind the scenes to communicate with the serial port. Connecting to the Serial Console Before running our new app, we must first connect to the serial console. First make sure the mynewt_arduino_zero repository is set to the develop branch. (Remove once changes have been moved to master). $ cd repos/mynewt_arduino_zero $ git checkout develop Open a new terminal window and list your serial connections to find our Arduino. $ ls /dev/tty . * /dev/tty . Bluetooth-Incoming-Port /dev/tty . usbmodem14132 In the same window, connect to the serial port using a serial communication program. In this case I\u2019ll be using mincom as it can scroll through output. $ minicom -D /dev/tty . usbmodem14132 -b 115200 If you see minicom welcome you, you\u2019re ready to move on! Output Analysis Run our new target, task_tgt, and you should see an output similar to this: Starting First Simulation... 1: Task B: 0% 78: Task B: 1% 155: Task B: 2% 257: Task B: 3% 359: Task B: 4% 461: Task B: 5% <snip> ========== Timer Expired ========== >>> Task A <<< Priority: 3 Loop count: 162849 Cycle count: 16.28 Run time: 1.40 sec >>> Task B <<< Priority: 2 Loop count: 1345852 Cycle count: 1.34 Run time: 17.0 sec Total loops: 1508709 20023: Switching priorities and restarting... 20111: Task A looped 20113: Task B: 0% 20191: Task B: 1% 20297: Task A looped 20356: Task B: 2% 20483: Task A looped 20545: Task B: 3% 20669: Task A looped 20734: Task B: 4% 20855: Task A looped 20923: Task B: 5% <snip> ========== Timer Expired ========== >>> Task A <<< Priority: 2 Loop count: 1080000 Cycle count: 108.0 Run time: 9.28 sec >>> Task B <<< Priority: 3 Loop count: 830356 Cycle count: 0.83 Run time: 10.72 sec Total loops: 1910404 40058: Final Speedup (Sim2 / Sim1): 1.26 The console output reaffirms our previous prediction and makes both the scheduling differences and subsequent efficiency boost far more apparent. Let\u2019s take a look at scheduling differences before we delve into efficiency. In the first case, where Task B\u2019s priority is higher than that of Task A, we see A get starved by Task B\u2019s long execution time. Starvation occurs when one task hogs the processor, essentially \u201cstarving\u201d other tasks which also need to run. At the end of the first 20 second simulation period, Task A has only run for 1.4 seconds compared to task B\u2019s 17 second running time \u2013 ouch. As explained before, processes which are expected to run for long periods of time (e.g. network communication, data processing) should be given higher priorities in order to combat starvation. In the second simulation with priorities swapped, we can see Task B only running during the millisecond delays when Task A is sleeping . Although having Task B only run during these delays slows its execution time, we benefit from un-starving Task A and using the processor at a higher efficiency. The bottom line speedup gives us an immediate and clear indication that we have improved our ability to process work (i.e throughput). In our second run, we processed an additional 400,000 loop iterations, equating to a 26% increase in efficiency. On a standard multi-core processor found in every modern PC, a 1.26 speedup would be an ok result to adding multithreading capabilities to a serial program. However, we accomplished this by simply setting priorities on a single core processor \u2013 not bad! NOTE: Usually the the term \u201cspeedup\u201d is used within a parallel programming context and refers to the change in execution time between a serial and parallel program executing over the same problem. In this case we\u2019re using the term loosely to illustrate the priority change\u2019s effect on scheduling and throughput in our specific context. Efficiency Isn\u2019t Everything Using the processor during every OS tick isn\u2019t always the best course of action. If we modify Task A\u2019s delay to a tenth of a millisecond and turn off the console output, we can boost our speedup to 1.44. This, however, reduces our ability to process work from Task B who ends up only completing 18% of its work cycle after the second simulation. That would mean, at that rate, Task B would take over a minute to finish one cycle. Feel free to play around with the testing parameters to study the different changes yourself! Conclusion Moving forward, tasks are just the tip of the iceberg. The scheduler , event queues , semaphores , and mutexes also add to tasks functionality, increasing our ability as the developer to control greater numbers of tasks more intricately. For example, when we switch the tasks priority, we have to tell the scheduler that our tasks priorities have changed, allowing us us to use priorities dynamically. When running multiple tasks, logging through either the built-in Logs module (not covered in this lesson) or through the serial console/shell can be very useful for debugging your application. In the end, the way you manage your tasks depends on the context of your application. You should assign priorities based on execution time, urgency, and frequency, among other things. Keep blinking and happy hacking!","title":"Tasks lesson"},{"location":"os/tutorials/tasks_lesson/#core-os-lesson-tasks-and-priority-management","text":"Target Platform: Arduino M0 Pro (or legacy Arduino Zero or Zero Pro, but not Arduino M0) This lesson is designed to teach core OS concepts and strategies encountered when building applications using Mynewt. Specifically, this lesson will cover tasks, simple multitasking, and priority management running on an Arduino M0 Pro.","title":"Core OS Lesson: Tasks and Priority Management"},{"location":"os/tutorials/tasks_lesson/#prerequisites","text":"Before starting, you should read about Mynewt in the Introduction section and complete the QuickStart guide and the Blinky tutorial. Furthermore, it may be helpful to take a peek at the task documentation for additional insights.","title":"Prerequisites"},{"location":"os/tutorials/tasks_lesson/#equipment","text":"You will need the following equipment: Arduino M0 Pro (or legacy Arduino Zero or Zero Pro, but not Arduino M0) Computer with Mynewt installed USB to Micro USB Cable","title":"Equipment"},{"location":"os/tutorials/tasks_lesson/#build-your-application","text":"To save time, we will simply modify the Blinky app. We'll add the Task Management code to the Blinky app. Follow the Arduino Zero Blinky tutorial to create a new project and build your bootloader and application. Finally, build and load the application to your Arduino to verify that everything is in order. Now let\u2019s get started!","title":"Build Your Application"},{"location":"os/tutorials/tasks_lesson/#create-a-new-task","text":"The purpose of this section is to give an introduction to the important aspects of tasks and how to properly initialize them. First, let\u2019s define a second task called work_task in main.c (located in apps/blinky/src): struct os_task work_task ; A task is represented by the os_task struct which will hold the task\u2019s information (name, state, priority, etc.). A task is made up of two main elements, a task function (also known as a task handler) and a task stack. Next, let\u2019s take a look at what is required to initialize our new task.","title":"Create a New Task"},{"location":"os/tutorials/tasks_lesson/#task-stack","text":"The task stack is an array of type os_stack_t which holds the program stack frames. Mynewt gives us the ability to set the stack size for a task giving the application developer room to optimize memory usage. Since we\u2019re not short on memory, our blinky_stack and work_stack are plenty large for the purpose of this lesson. Notice that the elements in our task stack are of type os_stack_t which are generally 32 bits, making our entire stack 1024 Bytes. #define WORK_STACK_SIZE OS_STACK_ALIGN(256) os_stack_t work_stack [ WORK_STACK_SIZE ]; Note: The OS_STACK_ALIGN macro is used to align the stack based on the hardware architecture.","title":"Task Stack"},{"location":"os/tutorials/tasks_lesson/#task-function","text":"The task function is essentially an infinite loop which waits for some \u201cevent\u201d to wake it up. In our Blinky app the task function, named blinky_task_handler() , is initially called when we call os_start() in main() . In general, the task function is where the majority of work is done by a task. Let\u2019s write a task function for work_task called work_task_handler() : void work_task_handler ( void *arg ) { struct os_task *t ; g_led_pin = LED_BLINK_PIN ; hal_gpio_init_out ( g_led_pin , 1 ); while ( 1 ) { t = os_sched_get_current_task (); assert ( t->t_func == work_task_handler ); /* Do work... */ } } The task function is called when the task is initially put into the running state by the scheduler. We use an infinite loop to ensure that the task function never returns. Our assertion that the current task's handler is the same as our task handler is for illustration purposes only and does not need to be in most task functions.","title":"Task Function"},{"location":"os/tutorials/tasks_lesson/#task-priority","text":"As a preemptive, multitasking RTOS, Mynewt decides which tasks to run based on which has a higher priority; the highest priority being 0 and the lowest 255. Thus, before initializing our task, we must choose a priority defined as a macro variable. Let\u2019s set the priority of work_task to 0, because everyone knows that work is more important than blinking. #define WORK_TASK_PRIO (0)","title":"Task Priority"},{"location":"os/tutorials/tasks_lesson/#initialization","text":"To initialize a new task we use os_task_init() which takes a number of arguments including our new task function, stack, and priority. Much like blinky_task , we\u2019re going to initialize work_task inside init_tasks to keep our main function clean. int init_tasks ( void ) { /* \u2026 */ os_task_init ( &work_task , \"work\" , work_task_handler , NULL , WORK_TASK_PRIO , OS_WAIT_FOREVER , work_stack , WORK_STACK_SIZE ); tasks_initialized = 1 ; return 0 ; } And that\u2019s it! Now run your application using the newt run command. $ newt run arduino_blinky 0.0.0 When GDB appears press C then Enter to continue and \u2026 wait, why doesn't our LED blink anymore?","title":"Initialization"},{"location":"os/tutorials/tasks_lesson/#review","text":"Before we run our new app, let\u2019s review what we need in order to create a task. This is a general case for a new task called mytask: 1) Define a new task, task stack, and priority: /* My Task */ struct os_task mytask /* My Task Stack */ #define MYTASK_STACK_SIZE OS_STACK_ALIGN(256) os_stack_t mytask_stack [ MYTASK_STACK_SIZE ]; /* My Task Priority */ #define MYTASK_PRIO (0) 2) Define task function: void mytask_handler ( void *arg ) { while ( 1 ) { /* ... */ } } 3) Initialize task before calling os_start() : os_task_init ( &mytask , \"mytask\" , mytask_handler , NULL , MYTASK_PRIO , OS_WAIT_FOREVER , mytask_stack , MYTASK_STACK_SIZE );","title":"Review"},{"location":"os/tutorials/tasks_lesson/#task-priority-preempting-and-context-switching","text":"A preemptive RTOS is one in which a higher priority task that is ready to run will preempt (i.e. take the place of) the lower priority task which is running . When a lower priority task is preempted by a higher priority task, the lower priority task\u2019s context data (stack pointer, registers, etc.) is saved and the new task is switched in. In our example, work_task has a higher priority than blinky_task and, because it is never put into a sleep state, holds the processor focus on its context. Let\u2019s give work_task a delay and some simulated work to keep it busy. Because the delay is measured in os ticks, the actual number of ticks per second is dependent on the board. Therefore, we multiply OS_TICKS_PER_SEC , which is defined in the MCU, by the number of seconds we wish to delay. void work_task_handler ( void *arg ) { struct os_task *t ; g_led_pin = LED_BLINK_PIN ; hal_gpio_init_out ( g_led_pin , 1 ); while ( 1 ) { t = os_sched_get_current_t:ask (); assert ( t->t_func == work_task_handler ); /* Do work... */ int i ; for ( i = 0 ; i < 1000000 ; ++i ) { /* Simulate doing a noticeable amount of work */ hal_gpio_set ( g_led_pin ); } os_time_delay ( 3 *OS_TICKS_PER_SECOND ); } } In order to notice the LED changing, modify the time delay in blinky_task_handler() to blink at a higher frequency. os_time_delay ( OS_TICKS_PER_SEC/ 10 ); Before we run the app, let\u2019s predict the behavior. With the newest additions to work_task_handler() , our first action will be to sleep for three seconds. This will allow blinky_task to take over the CPU and blink to its heart\u2019s content. After three seconds, work_task will wake up and be made ready to run , causing it to preempt blinky_task . The LED will then remain lit for a short period while work_task loops, then blink again for another three seconds while work_task sleeps. Voila, you should see that our prediction was correct!","title":"Task Priority, Preempting, and Context Switching"},{"location":"os/tutorials/tasks_lesson/#priority-management-considerations","text":"When projects grow in scope, from blinking LEDs into more sophisticated applications, the number of tasks needed increases alongside complexity. It remains important, then, that each of our tasks is capable of doing its work within a reasonable amount of time. Some tasks, such as the Shell task, execute quickly and require almost instantaneous response. Therefore, the Shell task should be given a high priority. On the other hand, tasks which may be communicating over a network, or processing data, should be given a low priority in order to not hog the CPU. The diagram below showcases the different scheduling patterns we. would expect from swapping blinky and work tasks priorities. In the second case where blinky_task has a higher priority, the \u201cwork\u201d done by work_task would be executed during the millisecond delays in blinky_task , saving us idle time compared to the first case. Note: Defining the same priority for two tasks leads to somewhat undefined behavior and should be avoided.","title":"Priority Management Considerations"},{"location":"os/tutorials/tasks_lesson/#comparing-priority-strategies","text":"Instead of stepping through a bunch of changes to our blinky app, clone my task lesson application from github and copy an existing target. Change directory into apps and clone the repository to get our new files: $ cd apps $ git clone https://github.com/bgiori/mynewt_tasks_lesson.git Change directory back to your project root and copy the arduino_blinky target to a new target called task_tgt. $ newt target copy arduino_blinky task_tgt Set a new app location. $ newt target set task_tgt app=apps/mynewt_tasks_lesson Now let\u2019s take a look at our new code. First, notice that we have abandoned blinking, instead choosing t o use the console and shell to follow our tasks through execution. Additionally, we have a number of different tasks: Task A ( a_task ): Priority : 3 \u2192 2 Description : Task A is supposed to represent a task which frequently does a small amount of work, such as one which rapidly polls a sensor for data. Much like blinky_task , Task A will loop 10,000 times then wait 1 millisecond. Priority is changed by timer_task after the first simulation. Task B ( b_task ): Priority : 2 \u2192 3 Description : Task B is supposed to represent a task which does a large amount of work relatively infrequently, such as one which sends/receives data from the cloud. Like work_task, Task B will loop 1,000,000 times then wait 3 seconds. Priority is changed by timer_task after the first simulation. Timer Task ( timer_task ): Priority : 1 Description : With default settings, Timer Task will wait 20 seconds then print the first simulations data for Task A and B. Timer task will then swap A and B\u2019s priorities and restart the simulation. After the second simulation, timer will again print simulation data then compare the two and calculate a final speedup (simulation2 / simulation1). Shell Task : Priority : 0 Description : Task used by Shell behind the scenes to communicate with the serial port.","title":"Comparing Priority Strategies"},{"location":"os/tutorials/tasks_lesson/#connecting-to-the-serial-console","text":"Before running our new app, we must first connect to the serial console. First make sure the mynewt_arduino_zero repository is set to the develop branch. (Remove once changes have been moved to master). $ cd repos/mynewt_arduino_zero $ git checkout develop Open a new terminal window and list your serial connections to find our Arduino. $ ls /dev/tty . * /dev/tty . Bluetooth-Incoming-Port /dev/tty . usbmodem14132 In the same window, connect to the serial port using a serial communication program. In this case I\u2019ll be using mincom as it can scroll through output. $ minicom -D /dev/tty . usbmodem14132 -b 115200 If you see minicom welcome you, you\u2019re ready to move on!","title":"Connecting to the Serial Console"},{"location":"os/tutorials/tasks_lesson/#output-analysis","text":"Run our new target, task_tgt, and you should see an output similar to this: Starting First Simulation... 1: Task B: 0% 78: Task B: 1% 155: Task B: 2% 257: Task B: 3% 359: Task B: 4% 461: Task B: 5% <snip> ========== Timer Expired ========== >>> Task A <<< Priority: 3 Loop count: 162849 Cycle count: 16.28 Run time: 1.40 sec >>> Task B <<< Priority: 2 Loop count: 1345852 Cycle count: 1.34 Run time: 17.0 sec Total loops: 1508709 20023: Switching priorities and restarting... 20111: Task A looped 20113: Task B: 0% 20191: Task B: 1% 20297: Task A looped 20356: Task B: 2% 20483: Task A looped 20545: Task B: 3% 20669: Task A looped 20734: Task B: 4% 20855: Task A looped 20923: Task B: 5% <snip> ========== Timer Expired ========== >>> Task A <<< Priority: 2 Loop count: 1080000 Cycle count: 108.0 Run time: 9.28 sec >>> Task B <<< Priority: 3 Loop count: 830356 Cycle count: 0.83 Run time: 10.72 sec Total loops: 1910404 40058: Final Speedup (Sim2 / Sim1): 1.26 The console output reaffirms our previous prediction and makes both the scheduling differences and subsequent efficiency boost far more apparent. Let\u2019s take a look at scheduling differences before we delve into efficiency. In the first case, where Task B\u2019s priority is higher than that of Task A, we see A get starved by Task B\u2019s long execution time. Starvation occurs when one task hogs the processor, essentially \u201cstarving\u201d other tasks which also need to run. At the end of the first 20 second simulation period, Task A has only run for 1.4 seconds compared to task B\u2019s 17 second running time \u2013 ouch. As explained before, processes which are expected to run for long periods of time (e.g. network communication, data processing) should be given higher priorities in order to combat starvation. In the second simulation with priorities swapped, we can see Task B only running during the millisecond delays when Task A is sleeping . Although having Task B only run during these delays slows its execution time, we benefit from un-starving Task A and using the processor at a higher efficiency. The bottom line speedup gives us an immediate and clear indication that we have improved our ability to process work (i.e throughput). In our second run, we processed an additional 400,000 loop iterations, equating to a 26% increase in efficiency. On a standard multi-core processor found in every modern PC, a 1.26 speedup would be an ok result to adding multithreading capabilities to a serial program. However, we accomplished this by simply setting priorities on a single core processor \u2013 not bad! NOTE: Usually the the term \u201cspeedup\u201d is used within a parallel programming context and refers to the change in execution time between a serial and parallel program executing over the same problem. In this case we\u2019re using the term loosely to illustrate the priority change\u2019s effect on scheduling and throughput in our specific context.","title":"Output Analysis"},{"location":"os/tutorials/tasks_lesson/#efficiency-isnt-everything","text":"Using the processor during every OS tick isn\u2019t always the best course of action. If we modify Task A\u2019s delay to a tenth of a millisecond and turn off the console output, we can boost our speedup to 1.44. This, however, reduces our ability to process work from Task B who ends up only completing 18% of its work cycle after the second simulation. That would mean, at that rate, Task B would take over a minute to finish one cycle. Feel free to play around with the testing parameters to study the different changes yourself!","title":"Efficiency Isn\u2019t Everything"},{"location":"os/tutorials/tasks_lesson/#conclusion","text":"Moving forward, tasks are just the tip of the iceberg. The scheduler , event queues , semaphores , and mutexes also add to tasks functionality, increasing our ability as the developer to control greater numbers of tasks more intricately. For example, when we switch the tasks priority, we have to tell the scheduler that our tasks priorities have changed, allowing us us to use priorities dynamically. When running multiple tasks, logging through either the built-in Logs module (not covered in this lesson) or through the serial console/shell can be very useful for debugging your application. In the end, the way you manage your tasks depends on the context of your application. You should assign priorities based on execution time, urgency, and frequency, among other things. Keep blinking and happy hacking!","title":"Conclusion"},{"location":"os/tutorials/try_markdown/","text":"Try Markdown Heading3 Heading4 List Start with one # for the largest heading (Heading1). The next smaller heading (Heading2) starts with ##. You can go all the way up to Heading 6 (######). Heading4 (####) and Heading5 (#####) has been styled to show up underlined. Yes, it can be changed. If you are curious, you can look at the extra.css file in your repo branch. It's very easy to do bold and italics . See how this list has been made using * Click on \"Help\" in Mou and then on \"Markdown Syntax Reference\". Substitute a sentence of your own here Guinea Pig!!! Note! You will not be able to see the change immediately by refreshing your browser right after editign the Markdown file. You can only push the change to the Apache repository. So continue with the steps in how_to_edit_docs.md . You can see the change on the website if/when a doc builder on the project team merges your changes to the master branch and generates the pages for the website. You do have the option to download MkDocs and preview the change by hosting the pages locally using its built-in web server. The steps are described in how_to_edit_docs.md .","title":"Try markdown"},{"location":"os/tutorials/try_markdown/#try-markdown","text":"","title":"Try Markdown"},{"location":"os/tutorials/try_markdown/#heading3","text":"","title":"Heading3"},{"location":"os/tutorials/try_markdown/#heading4","text":"","title":"Heading4"},{"location":"os/tutorials/try_markdown/#list","text":"Start with one # for the largest heading (Heading1). The next smaller heading (Heading2) starts with ##. You can go all the way up to Heading 6 (######). Heading4 (####) and Heading5 (#####) has been styled to show up underlined. Yes, it can be changed. If you are curious, you can look at the extra.css file in your repo branch. It's very easy to do bold and italics . See how this list has been made using * Click on \"Help\" in Mou and then on \"Markdown Syntax Reference\". Substitute a sentence of your own here Guinea Pig!!! Note! You will not be able to see the change immediately by refreshing your browser right after editign the Markdown file. You can only push the change to the Apache repository. So continue with the steps in how_to_edit_docs.md . You can see the change on the website if/when a doc builder on the project team merges your changes to the master branch and generates the pages for the website. You do have the option to download MkDocs and preview the change by hosting the pages locally using its built-in web server. The steps are described in how_to_edit_docs.md .","title":"List"},{"location":"os/tutorials/tutorials/","text":"Tutorials If the introduction to Mynewt has piqued your interest and you want to familiarize yourself with some of its functionality, this series of tutorials is for you. The lessons are aimed at the beginner. The full list of tutorials can be seen in the navigation bar on the left. New ones are being constantly added and will show up there automatically. Prerequisites: You have installed Docker container of Newt tool and toolchains or you have installed them natively on your machine You have created a new project space (directory structure) and populated it with the core code repository (apache-mynewt-core) or know how to as explained in Creating Your First Project . Tutorial categories: The tutorials fall into a few broad categories. Some examples in each category are listed below. Making an LED blink (the \"Hello World\" equivalent in the electronics world) Blinky on Arduino Zero hardware Blinky on Olimex/STM32F407ZGT6 Cortex-M4 hardware Blinky on STM32F3 discovery kit from ST Micro Blinky on nRF52 Development Kit from Nordic Semiconductor Note: This supports BLE. Tweaking available apps to customize behavior e.g. making a more exciting LED blink pattern Pinwheel Blinky on STM32F3 discovery board Navigating the code and adding functionality Adding more repositories to your project Adding a unit test for a package Adding task to manage multiple events Bluetooth Low Energy Running the example BLE app included in the repo Using NewtMgr Enabling remote communication with a device running Mynewt OS Send us an email on the dev@ mailing list if you have comments or suggestions! If you haven't joined the mailing list, you will find the links here .","title":"toc"},{"location":"os/tutorials/tutorials/#tutorials","text":"If the introduction to Mynewt has piqued your interest and you want to familiarize yourself with some of its functionality, this series of tutorials is for you. The lessons are aimed at the beginner. The full list of tutorials can be seen in the navigation bar on the left. New ones are being constantly added and will show up there automatically.","title":"Tutorials"},{"location":"os/tutorials/tutorials/#prerequisites","text":"You have installed Docker container of Newt tool and toolchains or you have installed them natively on your machine You have created a new project space (directory structure) and populated it with the core code repository (apache-mynewt-core) or know how to as explained in Creating Your First Project .","title":"Prerequisites:"},{"location":"os/tutorials/tutorials/#tutorial-categories","text":"The tutorials fall into a few broad categories. Some examples in each category are listed below. Making an LED blink (the \"Hello World\" equivalent in the electronics world) Blinky on Arduino Zero hardware Blinky on Olimex/STM32F407ZGT6 Cortex-M4 hardware Blinky on STM32F3 discovery kit from ST Micro Blinky on nRF52 Development Kit from Nordic Semiconductor Note: This supports BLE. Tweaking available apps to customize behavior e.g. making a more exciting LED blink pattern Pinwheel Blinky on STM32F3 discovery board Navigating the code and adding functionality Adding more repositories to your project Adding a unit test for a package Adding task to manage multiple events Bluetooth Low Energy Running the example BLE app included in the repo Using NewtMgr Enabling remote communication with a device running Mynewt OS Send us an email on the dev@ mailing list if you have comments or suggestions! If you haven't joined the mailing list, you will find the links here .","title":"Tutorial categories:"},{"location":"os/tutorials/unit_test/","text":"Write a Test Suite for a Package This document presents a tutorial which guides the reader through writing a test suite for a Mynewt package (new or existing). Introduction Writing a test suite involves using the libs/testutil package within Mynewt core os. The testutil library provides the interface to the newt command tool and also provides the compile time hooks to include test suites into your code. Review the [ testutil introduction page ] (../modules/testutil/testutil.md) to learn about how the library works. Identify Your Package Identify the package for which you are writing a test suite. For this example we will use libs/json . To create a new package, see this Tutorial . Modify Pkg.yml Edit the package ( pkg.yml ) file for your package and add the test dependency for the Mynewt core OS libs/testutil . pkg . deps . TEST: - libs/testutil Create Your Test Suite Template Create a subdirectory test under your package main directory. Create a file pair for your test code and header files within the test directory created above. Below shows the libs/json directory within the Mynewt core, including the test directory. In this example, we used the convention test_xxx.c/h (in this case test_json ). \u251c\u2500\u2500 MSJSON_COPYING \u251c\u2500\u2500 include \u2502 \u2514\u2500\u2500 json \u2502 \u2514\u2500\u2500 json . h \u251c\u2500\u2500 pkg . yml \u2514\u2500\u2500 src \u251c\u2500\u2500 json_decode . c \u251c\u2500\u2500 json_encode . c \u2514\u2500\u2500 test \u251c\u2500\u2500 test_json . c \u2514\u2500\u2500 test_json . h Create Your Test Suite Code Edit the test_json.c file and add your test suite definition. NOTE that the test suite code requires #include <testutil/testutil.h> to get the Mynewt testutil definitions. Your test suite test_json.c file contains at a minimum two functions: A test Suite which is empty for now, but will contain calls to your test cases. A main function which must be #ifdef 'd using MYNEWT_SELFTEST to ensure that is does not get compiled in when this test suite is run with test suites from other packages Below shows the contents of the test_json.c file. #include <testutil/testutil.h> TEST_SUITE ( test_json_suite ) { /* empty for now, add test cases later */ } #ifdef MYNEWT_SELFTEST int main ( int argc , char **argv ) { tu_config . tc_print_results = 1 ; tu_init (); test_json_suite (); return tu_any_failed ; } #endif Try It Out At this point, you have a working test suite with no tests. This will by default pass the test. Your output will look something like this. You can use the newt test command to run the unit tests for any package. Just include the package name. These unit tests run via the project unittest which is a native project automatically included in the core os package. Below shows some of the test output of this command. $ newt test libs/json Archiving util . a Linking test_json Testing package libs/json Test ... /bin/unittest/libs/json/test_json ok! Create a Test To create a test within your test suite, there are two things to do. Add the functions to your test suite Implement the function using the testutil macros For this tutorial we will create two functions: one to test a simple json encode and one to test the decode of this simple message to ensure its coherent. Follow These steps; 1. Create function prototypes in test_json.h for your test functions. A macro in testutil.h hides the actual prototype, but as of this writing the prototype is int test_func(void); . #ifndef TEST_JSON_H #define TEST_JSON_H TEST_CASE_DECL ( test_json_simple_encode ); TEST_CASE_DECL ( test_json_simple_decode ); #endif /* TEST_JSON_H 2. create a new file test_json_simple.c to define these two functions. For now you can stub these functions. Below shows the contents of this file. The functions are defined using macros which reference back to the testutil library so the test can be enumerated and recorded automatically. #include \"testutil/testutil.h\" #include \"test_json.h\" TEST_CASE ( test_json_simple_encode ) { } TEST_CASE ( test_json_simple_decode ) { } #endif /* TEST_JSON_H 3. Add the tests to your test suite in test_json.c as shown below. TEST_SUITE ( test_json_suite ) { test_json_simple_encode (); test_json_simple_decode (); } Your test suite should still pass as shown below $newt test libs/json Testing package libs/json Test ... /bin/unittest/libs/json/test_json ok! Add Contents to your Tests At this point, you can add contents to your test and verify that the test suites pass. For now, lets just add a simple failure to show what it would look like when running from Newt. Edit test_json_simple.c and add a TEST_ASSERT to a test function. The test assert will fail if its argument is false . TEST_CASE ( test_json_simple_encode ) { TEST_ASSERT ( 0 ); } When running newt, you will see the test suite fails with something like the message shown below. Testing package libs/json [ FAIL ] test_json_suite/ ( null ) |test_json_simple . c: 24 | failed assertion: 0 Error : Test crashed: .. /bin/unittest/libs/json/test_json exit status 1 Congratulations Now you can begin the work of adding your test cases and test. Testing on your target","title":"Write a Test Suite for a Package"},{"location":"os/tutorials/unit_test/#write-a-test-suite-for-a-package","text":"This document presents a tutorial which guides the reader through writing a test suite for a Mynewt package (new or existing).","title":"Write a Test Suite for a Package"},{"location":"os/tutorials/unit_test/#introduction","text":"Writing a test suite involves using the libs/testutil package within Mynewt core os. The testutil library provides the interface to the newt command tool and also provides the compile time hooks to include test suites into your code. Review the [ testutil introduction page ] (../modules/testutil/testutil.md) to learn about how the library works.","title":"Introduction"},{"location":"os/tutorials/unit_test/#identify-your-package","text":"Identify the package for which you are writing a test suite. For this example we will use libs/json . To create a new package, see this Tutorial .","title":"Identify Your Package"},{"location":"os/tutorials/unit_test/#modify-pkgyml","text":"Edit the package ( pkg.yml ) file for your package and add the test dependency for the Mynewt core OS libs/testutil . pkg . deps . TEST: - libs/testutil","title":"Modify Pkg.yml"},{"location":"os/tutorials/unit_test/#create-your-test-suite-template","text":"Create a subdirectory test under your package main directory. Create a file pair for your test code and header files within the test directory created above. Below shows the libs/json directory within the Mynewt core, including the test directory. In this example, we used the convention test_xxx.c/h (in this case test_json ). \u251c\u2500\u2500 MSJSON_COPYING \u251c\u2500\u2500 include \u2502 \u2514\u2500\u2500 json \u2502 \u2514\u2500\u2500 json . h \u251c\u2500\u2500 pkg . yml \u2514\u2500\u2500 src \u251c\u2500\u2500 json_decode . c \u251c\u2500\u2500 json_encode . c \u2514\u2500\u2500 test \u251c\u2500\u2500 test_json . c \u2514\u2500\u2500 test_json . h","title":"Create Your Test Suite Template"},{"location":"os/tutorials/unit_test/#create-your-test-suite-code","text":"Edit the test_json.c file and add your test suite definition. NOTE that the test suite code requires #include <testutil/testutil.h> to get the Mynewt testutil definitions. Your test suite test_json.c file contains at a minimum two functions: A test Suite which is empty for now, but will contain calls to your test cases. A main function which must be #ifdef 'd using MYNEWT_SELFTEST to ensure that is does not get compiled in when this test suite is run with test suites from other packages Below shows the contents of the test_json.c file. #include <testutil/testutil.h> TEST_SUITE ( test_json_suite ) { /* empty for now, add test cases later */ } #ifdef MYNEWT_SELFTEST int main ( int argc , char **argv ) { tu_config . tc_print_results = 1 ; tu_init (); test_json_suite (); return tu_any_failed ; } #endif","title":"Create Your Test Suite Code"},{"location":"os/tutorials/unit_test/#try-it-out","text":"At this point, you have a working test suite with no tests. This will by default pass the test. Your output will look something like this. You can use the newt test command to run the unit tests for any package. Just include the package name. These unit tests run via the project unittest which is a native project automatically included in the core os package. Below shows some of the test output of this command. $ newt test libs/json Archiving util . a Linking test_json Testing package libs/json Test ... /bin/unittest/libs/json/test_json ok!","title":"Try It Out"},{"location":"os/tutorials/unit_test/#create-a-test","text":"To create a test within your test suite, there are two things to do. Add the functions to your test suite Implement the function using the testutil macros For this tutorial we will create two functions: one to test a simple json encode and one to test the decode of this simple message to ensure its coherent. Follow These steps; 1. Create function prototypes in test_json.h for your test functions. A macro in testutil.h hides the actual prototype, but as of this writing the prototype is int test_func(void); . #ifndef TEST_JSON_H #define TEST_JSON_H TEST_CASE_DECL ( test_json_simple_encode ); TEST_CASE_DECL ( test_json_simple_decode ); #endif /* TEST_JSON_H 2. create a new file test_json_simple.c to define these two functions. For now you can stub these functions. Below shows the contents of this file. The functions are defined using macros which reference back to the testutil library so the test can be enumerated and recorded automatically. #include \"testutil/testutil.h\" #include \"test_json.h\" TEST_CASE ( test_json_simple_encode ) { } TEST_CASE ( test_json_simple_decode ) { } #endif /* TEST_JSON_H 3. Add the tests to your test suite in test_json.c as shown below. TEST_SUITE ( test_json_suite ) { test_json_simple_encode (); test_json_simple_decode (); } Your test suite should still pass as shown below $newt test libs/json Testing package libs/json Test ... /bin/unittest/libs/json/test_json ok!","title":"Create a Test"},{"location":"os/tutorials/unit_test/#add-contents-to-your-tests","text":"At this point, you can add contents to your test and verify that the test suites pass. For now, lets just add a simple failure to show what it would look like when running from Newt. Edit test_json_simple.c and add a TEST_ASSERT to a test function. The test assert will fail if its argument is false . TEST_CASE ( test_json_simple_encode ) { TEST_ASSERT ( 0 ); } When running newt, you will see the test suite fails with something like the message shown below. Testing package libs/json [ FAIL ] test_json_suite/ ( null ) |test_json_simple . c: 24 | failed assertion: 0 Error : Test crashed: .. /bin/unittest/libs/json/test_json exit status 1","title":"Add Contents to your Tests"},{"location":"os/tutorials/unit_test/#congratulations","text":"Now you can begin the work of adding your test cases and test.","title":"Congratulations"},{"location":"os/tutorials/unit_test/#testing-on-your-target","text":"","title":"Testing on your target"},{"location":"os/tutorials/wi-fi_on_arduino/","text":"Start Wi-Fi on Arduino Zero This tutorial walks you through the steps to get your Arduino board on a Wi-Fi network. Note: Wi-Fi support is currently available in the develop branch of Mynewt only. It will be merged into master branch when version 0.10 is released. Prerequisites Before tackling this tutorial, it's best to read about Mynewt in the Introduction section of this documentation. Equipment You will need the following equipment An Arduino Zero, Zero Pro or M0 Pro. Note: Mynewt has not been tested on Arduino M0 which has no internal debugger support. An Arduino Wi-Fi Shield 101 A computer that can connect to the Arduino board over USB A local Wi-Fi network that the computer is connected to and which the Arduino board can join. A USB cable (Type A to micro B) that can connect the computer to the Arduino (or a USB hub between the computer and the Arduino board) The Mynewt Release Install Mynewt and Newt If you have not already done so, install Newt as shown in the Newt install tutorial . If you installed Newt previously but need to update it, go to the newt git repo directory, pull the latest code from develop branch, and install the updated code. user@~/dev$ cd $GOPATH/src/mynewt.apache.org/newt user@~/dev/go/src/mynewt.apache.org/newt$ git remote -v origin https://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt.git (fetch) origin https://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt.git (push) user@~/dev/go/src/mynewt.apache.org/newt$ git pull origin develop remote: Counting objects: 59, done. <snip> user@~/dev/go/src/mynewt.apache.org/newt$ cd newt user@~/dev/go/src/mynewt.apache.org/newt/newt$ go install user@~/dev$ cd ~/dev If you have not already done so, create a project as shown in the Quick Start guide on how to Create Your First Project . Skip the testing and building the project steps in that tutorial since you will be defining a target for your Arduino board in this tutorial. Let's say your new project is named arduinowifi . You will henceforth be working in that project directory. Fetch External Packages, Set correct version to download Mynewt uses source code provided directly from the chip manufacturer for low level operations. Sometimes this code is licensed only for the specific manufacturer of the chipset and cannot live in the Apache Mynewt repository. That happens to be the case for the Arduino Zero board which uses Atmel SAMD21. Runtime's github repository hosts such external third-party packages and the Newt tool can fetch them. To fetch the package with MCU support for Atmel SAMD21 for Arduino Zero from the Runtime git repository, you need to add the repository to the project.yml file in your base project directory ( arduinowifi ). user@~/dev/arduinowifi$ vi project.yml Here is an example project.yml file with the Arduino Zero repository added. The sections with mynewt_arduino_zero that need to be added to your project file are highlighted. Also highlighted is the 0-dev version for both the repositories to ensure code is downloaded from the develop branch. $ more project.yml project.name: \"my_project\" project.repositories: - apache-mynewt-core - mynewt_arduino_zero repository.apache-mynewt-core: type: github vers: 0-dev user: apache repo: incubator-mynewt-core repository.mynewt_arduino_zero: type: github vers: 0-dev user: runtimeinc repo: mynewt_arduino_zero $ Once you've edited your project.yml file, the next step is to install the project dependencies, this can be done with the newt install command (to see more output, provide the -v verbose option.): $ newt install apache-mynewt-core mynewt_arduino_zero $ Create your bootloader target Next, you need to tell Newt what to build. For the Arduino Zero, we are going to generate both a bootloader, and an image target. To generate the bootloader target, you need to specify the following options. The output of the commands (indicating success) have been suppressed for easier readability. $ newt target create arduino_boot $ newt target set arduino_boot bsp=@mynewt_arduino_zero/hw/bsp/arduino_zero $ newt target set arduino_boot app=@apache-mynewt-core/apps/boot $ newt target set arduino_boot build_profile=optimized If you have an Arduino Zero Pro or M0 Pro, you have to set the following next: $ newt target set arduino_boot features=arduino_zero_pro If you have an Arduino Zero, you have to set the following instead: $ newt target set arduino_boot features=arduino_zero Build your bootloader Once you've configured the bootloader target, the next step is to build the bootloader for your Arduino. You can do this by using the newt build command: $ newt build arduino_boot Compiling boot.c Archiving boot.a Compiling fs_cli.c Compiling fs_dirent.c Compiling fs_file.c Compiling fs_mkdir.c <snip> App successfully built: ~/dev/arduinowifi/bin/arduino_boot/apps/boot/boot.elf If this command finishes successfully, you have successfully built the Arduino bootloader, and the next step is to build your application for the Arduino board. Build your blinky app To create and download your application, you create another target, this one pointing to the application you want to download to the Arduino board. In this tutorial, we will use the Wi-Fi application that comes in the arduino repository, apps/winc1500_wifi : Note : Remember to set features to arduino_zero if your board is Arduino Zero and not a Pro! $ newt target create arduino_wifi $ newt target set arduino_wifi app=@mynewt_arduino_zero/apps/winc1500_wifi $ newt target set arduino_wifi bsp=@mynewt_arduino_zero/hw/bsp/arduino_zero $ newt target set arduino_wifi build_profile=debug $ newt target set arduino_wifi features=arduino_zero_pro You can now build the target, with newt build : $ newt build arduino_wifi Building target targets/arduino_wifi Compiling main.c Archiving winc1500_wifi.a Compiling fs_cli.c Compiling fs_dirent.c Compiling fs_file.c Compiling fs_mkdir.c <snip> Linking winc1500_wifi.elf App successfully built: ~/dev/arduinowifi/bin/arduino_wifi/apps/winc1500_wifi/winc1500_wifi.elf Congratulations! You have successfully built your Wi-Fi application. Now it's time to load both the bootloader and application onto the target. Connect the Target Place the Wi-Fi shield on top of the Arduino board and push it in place, making sure the pins and pinholes are properly aligned. Connect your computer to the Arduino board with the Micro-USB cable through the Programming Port as shown below. Mynewt will download and debug the target through this port. You should see a little green LED come on. That means the board has power. No external debugger is required. The Arduino boards listed in this tutorial come with an internal debugger that can be accessed by Mynewt. The picture below shows the setup. Download the Bootloader Execute the command to download the bootloader. $ newt load arduino_boot If the newt tool finishes without error, that means the bootloader has been successfully loaded onto the target. Reminder if you are using Docker: When working with actual hardware, remember that each board has an ID. If you swap boards and do not refresh the USB Device Filter on the VirtualBox UI, the ID might be stale and the Docker instance may not be able to see the board correctly. For example, you may see an error message like Error: unable to find CMSIS-DAP device when you try to load or run an image on the board. In that case, you need to click on the USB link in VirtualBox UI, remove the existing USB Device Filter (e.g. \"Atmel Corp. EDBG CMSIS-DAP[0101]\") by clicking on the \"Removes selected USB filter\" button, and add a new filter by clicking on the \"Adds new USB filter\" button. Load the Application Image Now that the bootloader is downloaded to the target, the next steps are to create an image and load it onto the target device. $ newt create-image arduino_wifi 1.0.0 App image succesfully generated: ~/dev/arduinowifi/bin/arduino_wifi/apps/winc1500_wifi/winc1500_wifi.img Build manifest: ~/dev/arduinowifi/bin/arduino_wifi/apps/winc1500_wifi/manifest.json $ newt load arduino_wifi Loading image $ Start Wi-Fi via console Use a terminal emulation program to communicate with the board over the serial port. This tutorial shows a Minicom set up. You will have to find out what the usbserial port number is on your computer/laptop ( ls /dev ) and specify it as the -D flag value. Type wifi start to start Wi-Fi. $ minicom -D /dev/tty.usbmodem141122 -b 115200 Welcome to minicom 2.7 OPTIONS: Compiled on Nov 24 2015, 16:14:21. Port /dev/tty.usbmodem141122, 10:11:40 Press Meta-Z for help on special keys wifi start 119470:(APP)(INFO)Chip ID 1502b1 (APP)(INFO)Firmware ver : 19.4.4 (APP)(INFO)Min driver ver : 19.3.0 (APP)(INFO)Curr driver ver: 19.3.0 wifi_init : 0 Connect to the local Wi-Fi network. Then start network services. The commands to be issued are highlighted below. In the example below, the network interface on the Arduino board gets an IP address of 192.168.0.117 . wifi connect <Wi-Fi network name> <password> 16906:wifi_request_scan : 0 17805:scan_results 16: 0 17816:wifi_connect : 0 18813:connect_done : 0 18821:dhcp done 192.168.0.117 18932:get sys time response 2016.8.2-18.4.43 net service Establish TCP connection and talk! From a terminal on your computer/laptop, try telneting to ports 7, 9, or 19 using the IP address your board has been assigned. Type something on this terminal and see the console output (on minicom). Can you see the difference in the behaviors? $ telnet 192.168.0.117 7 Trying 192.168.0.117... Connected to 192.168.0.117. Escape character is '^]'. hello hello ^] telnet> q $ One port echoes whatever is typed, one discards everything it gets, and the third spews out bits constantly. Type wifi stop to disable WiFi on the Arduino board. Hope you had fun!","title":"Wi fi on arduino"},{"location":"os/tutorials/wi-fi_on_arduino/#start-wi-fi-on-arduino-zero","text":"This tutorial walks you through the steps to get your Arduino board on a Wi-Fi network. Note: Wi-Fi support is currently available in the develop branch of Mynewt only. It will be merged into master branch when version 0.10 is released.","title":"Start Wi-Fi on Arduino Zero"},{"location":"os/tutorials/wi-fi_on_arduino/#prerequisites","text":"Before tackling this tutorial, it's best to read about Mynewt in the Introduction section of this documentation.","title":"Prerequisites"},{"location":"os/tutorials/wi-fi_on_arduino/#equipment","text":"You will need the following equipment An Arduino Zero, Zero Pro or M0 Pro. Note: Mynewt has not been tested on Arduino M0 which has no internal debugger support. An Arduino Wi-Fi Shield 101 A computer that can connect to the Arduino board over USB A local Wi-Fi network that the computer is connected to and which the Arduino board can join. A USB cable (Type A to micro B) that can connect the computer to the Arduino (or a USB hub between the computer and the Arduino board) The Mynewt Release","title":"Equipment"},{"location":"os/tutorials/wi-fi_on_arduino/#install-mynewt-and-newt","text":"If you have not already done so, install Newt as shown in the Newt install tutorial . If you installed Newt previously but need to update it, go to the newt git repo directory, pull the latest code from develop branch, and install the updated code. user@~/dev$ cd $GOPATH/src/mynewt.apache.org/newt user@~/dev/go/src/mynewt.apache.org/newt$ git remote -v origin https://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt.git (fetch) origin https://git-wip-us.apache.org/repos/asf/incubator-mynewt-newt.git (push) user@~/dev/go/src/mynewt.apache.org/newt$ git pull origin develop remote: Counting objects: 59, done. <snip> user@~/dev/go/src/mynewt.apache.org/newt$ cd newt user@~/dev/go/src/mynewt.apache.org/newt/newt$ go install user@~/dev$ cd ~/dev If you have not already done so, create a project as shown in the Quick Start guide on how to Create Your First Project . Skip the testing and building the project steps in that tutorial since you will be defining a target for your Arduino board in this tutorial. Let's say your new project is named arduinowifi . You will henceforth be working in that project directory.","title":"Install Mynewt and Newt"},{"location":"os/tutorials/wi-fi_on_arduino/#fetch-external-packages-set-correct-version-to-download","text":"Mynewt uses source code provided directly from the chip manufacturer for low level operations. Sometimes this code is licensed only for the specific manufacturer of the chipset and cannot live in the Apache Mynewt repository. That happens to be the case for the Arduino Zero board which uses Atmel SAMD21. Runtime's github repository hosts such external third-party packages and the Newt tool can fetch them. To fetch the package with MCU support for Atmel SAMD21 for Arduino Zero from the Runtime git repository, you need to add the repository to the project.yml file in your base project directory ( arduinowifi ). user@~/dev/arduinowifi$ vi project.yml Here is an example project.yml file with the Arduino Zero repository added. The sections with mynewt_arduino_zero that need to be added to your project file are highlighted. Also highlighted is the 0-dev version for both the repositories to ensure code is downloaded from the develop branch. $ more project.yml project.name: \"my_project\" project.repositories: - apache-mynewt-core - mynewt_arduino_zero repository.apache-mynewt-core: type: github vers: 0-dev user: apache repo: incubator-mynewt-core repository.mynewt_arduino_zero: type: github vers: 0-dev user: runtimeinc repo: mynewt_arduino_zero $ Once you've edited your project.yml file, the next step is to install the project dependencies, this can be done with the newt install command (to see more output, provide the -v verbose option.): $ newt install apache-mynewt-core mynewt_arduino_zero $","title":"Fetch External Packages, Set correct version to download"},{"location":"os/tutorials/wi-fi_on_arduino/#create-your-bootloader-target","text":"Next, you need to tell Newt what to build. For the Arduino Zero, we are going to generate both a bootloader, and an image target. To generate the bootloader target, you need to specify the following options. The output of the commands (indicating success) have been suppressed for easier readability. $ newt target create arduino_boot $ newt target set arduino_boot bsp=@mynewt_arduino_zero/hw/bsp/arduino_zero $ newt target set arduino_boot app=@apache-mynewt-core/apps/boot $ newt target set arduino_boot build_profile=optimized If you have an Arduino Zero Pro or M0 Pro, you have to set the following next: $ newt target set arduino_boot features=arduino_zero_pro If you have an Arduino Zero, you have to set the following instead: $ newt target set arduino_boot features=arduino_zero","title":"Create your bootloader target"},{"location":"os/tutorials/wi-fi_on_arduino/#build-your-bootloader","text":"Once you've configured the bootloader target, the next step is to build the bootloader for your Arduino. You can do this by using the newt build command: $ newt build arduino_boot Compiling boot.c Archiving boot.a Compiling fs_cli.c Compiling fs_dirent.c Compiling fs_file.c Compiling fs_mkdir.c <snip> App successfully built: ~/dev/arduinowifi/bin/arduino_boot/apps/boot/boot.elf If this command finishes successfully, you have successfully built the Arduino bootloader, and the next step is to build your application for the Arduino board.","title":"Build your bootloader"},{"location":"os/tutorials/wi-fi_on_arduino/#build-your-blinky-app","text":"To create and download your application, you create another target, this one pointing to the application you want to download to the Arduino board. In this tutorial, we will use the Wi-Fi application that comes in the arduino repository, apps/winc1500_wifi : Note : Remember to set features to arduino_zero if your board is Arduino Zero and not a Pro! $ newt target create arduino_wifi $ newt target set arduino_wifi app=@mynewt_arduino_zero/apps/winc1500_wifi $ newt target set arduino_wifi bsp=@mynewt_arduino_zero/hw/bsp/arduino_zero $ newt target set arduino_wifi build_profile=debug $ newt target set arduino_wifi features=arduino_zero_pro You can now build the target, with newt build : $ newt build arduino_wifi Building target targets/arduino_wifi Compiling main.c Archiving winc1500_wifi.a Compiling fs_cli.c Compiling fs_dirent.c Compiling fs_file.c Compiling fs_mkdir.c <snip> Linking winc1500_wifi.elf App successfully built: ~/dev/arduinowifi/bin/arduino_wifi/apps/winc1500_wifi/winc1500_wifi.elf Congratulations! You have successfully built your Wi-Fi application. Now it's time to load both the bootloader and application onto the target.","title":"Build your blinky app"},{"location":"os/tutorials/wi-fi_on_arduino/#connect-the-target","text":"Place the Wi-Fi shield on top of the Arduino board and push it in place, making sure the pins and pinholes are properly aligned. Connect your computer to the Arduino board with the Micro-USB cable through the Programming Port as shown below. Mynewt will download and debug the target through this port. You should see a little green LED come on. That means the board has power. No external debugger is required. The Arduino boards listed in this tutorial come with an internal debugger that can be accessed by Mynewt. The picture below shows the setup.","title":"Connect the Target"},{"location":"os/tutorials/wi-fi_on_arduino/#download-the-bootloader","text":"Execute the command to download the bootloader. $ newt load arduino_boot If the newt tool finishes without error, that means the bootloader has been successfully loaded onto the target. Reminder if you are using Docker: When working with actual hardware, remember that each board has an ID. If you swap boards and do not refresh the USB Device Filter on the VirtualBox UI, the ID might be stale and the Docker instance may not be able to see the board correctly. For example, you may see an error message like Error: unable to find CMSIS-DAP device when you try to load or run an image on the board. In that case, you need to click on the USB link in VirtualBox UI, remove the existing USB Device Filter (e.g. \"Atmel Corp. EDBG CMSIS-DAP[0101]\") by clicking on the \"Removes selected USB filter\" button, and add a new filter by clicking on the \"Adds new USB filter\" button.","title":"Download the Bootloader"},{"location":"os/tutorials/wi-fi_on_arduino/#load-the-application-image","text":"Now that the bootloader is downloaded to the target, the next steps are to create an image and load it onto the target device. $ newt create-image arduino_wifi 1.0.0 App image succesfully generated: ~/dev/arduinowifi/bin/arduino_wifi/apps/winc1500_wifi/winc1500_wifi.img Build manifest: ~/dev/arduinowifi/bin/arduino_wifi/apps/winc1500_wifi/manifest.json $ newt load arduino_wifi Loading image $","title":"Load the Application Image"},{"location":"os/tutorials/wi-fi_on_arduino/#start-wi-fi-via-console","text":"Use a terminal emulation program to communicate with the board over the serial port. This tutorial shows a Minicom set up. You will have to find out what the usbserial port number is on your computer/laptop ( ls /dev ) and specify it as the -D flag value. Type wifi start to start Wi-Fi. $ minicom -D /dev/tty.usbmodem141122 -b 115200 Welcome to minicom 2.7 OPTIONS: Compiled on Nov 24 2015, 16:14:21. Port /dev/tty.usbmodem141122, 10:11:40 Press Meta-Z for help on special keys wifi start 119470:(APP)(INFO)Chip ID 1502b1 (APP)(INFO)Firmware ver : 19.4.4 (APP)(INFO)Min driver ver : 19.3.0 (APP)(INFO)Curr driver ver: 19.3.0 wifi_init : 0 Connect to the local Wi-Fi network. Then start network services. The commands to be issued are highlighted below. In the example below, the network interface on the Arduino board gets an IP address of 192.168.0.117 . wifi connect <Wi-Fi network name> <password> 16906:wifi_request_scan : 0 17805:scan_results 16: 0 17816:wifi_connect : 0 18813:connect_done : 0 18821:dhcp done 192.168.0.117 18932:get sys time response 2016.8.2-18.4.43 net service","title":"Start Wi-Fi via console"},{"location":"os/tutorials/wi-fi_on_arduino/#establish-tcp-connection-and-talk","text":"From a terminal on your computer/laptop, try telneting to ports 7, 9, or 19 using the IP address your board has been assigned. Type something on this terminal and see the console output (on minicom). Can you see the difference in the behaviors? $ telnet 192.168.0.117 7 Trying 192.168.0.117... Connected to 192.168.0.117. Escape character is '^]'. hello hello ^] telnet> q $ One port echoes whatever is typed, one discards everything it gets, and the third spews out bits constantly. Type wifi stop to disable WiFi on the Arduino board. Hope you had fun!","title":"Establish TCP connection and talk!"},{"location":"os/tutorials/bleprph/bleprph-adv/","text":"BLE Peripheral Project Advertising Overview A peripheral announces its presence to the world by broadcasting advertisements. An advertisement typically contains additional information about the peripheral sending it, such as the device name and an abbreviated list of supported services. The presence of this information helps a listening central to determine whether it is interested in connecting to the peripheral. Advertisements are quite limited in the amount of information they can contain, so only the most important information should be included. When a listening device receives an advertisement, it can choose to connect to the peripheral, or query the sender for more information. This second action is known as an active scan . A peripheral responds to an active scan with some extra information that it couldn't fit in its advertisement. This additional information is known as scan response data . bleprph does not configure any scan response data, so this feature is not discussed in the remainder of this tutorial. bleprph constantly broadcasts advertisements until a central connects to it. When a connection is terminated, bleprph resumes advertising. Let's take a look at bleprph 's advertisement code ( main.c ): /** * Enables advertising with the following parameters: * o General discoverable mode. * o Undirected connectable mode. */ static void bleprph_advertise ( void ) { struct ble_hs_adv_fields fields ; int rc ; /* Set the advertisement data included in our advertisements. */ memset ( &fields , 0 , sizeof fields ); fields . name = ( uint8_t * ) bleprph_device_name ; fields . name_len = strlen ( bleprph_device_name ); fields . name_is_complete = 1 ; rc = ble_gap_adv_set_fields ( &fields ); if ( rc != 0 ) { BLEPRPH_LOG ( ERROR , \"error setting advertisement data; rc=%d\\n\" , rc ); return ; } /* Begin advertising. */ rc = ble_gap_adv_start ( BLE_GAP_DISC_MODE_GEN , BLE_GAP_CONN_MODE_UND , NULL , 0 , NULL , bleprph_on_connect , NULL ); if ( rc != 0 ) { BLEPRPH_LOG ( ERROR , \"error enabling advertisement; rc=%d\\n\" , rc ); return ; } } Now let's examine this code in detail. Setting advertisement data A NimBLE peripheral specifies what information to include in its advertisements with the following function: int ble_gap_adv_set_fields ( struct ble_hs_adv_fields *adv_fields ) The adv_fields argument specifies the fields and their contents to include in subsequent advertisements. The Bluetooth Core Specification Supplement defines a set of standard fields that can be included in an advertisement; the member variables of the struct ble_hs_adv_fields type correspond to these standard fields. Information that doesn't fit neatly into a standard field should be put in the manufacturing specific data field. As you can see in the above code listing, the struct ble_hs_adv_fields instance is allocated on the stack. It is OK to use the stack for this struct and the data it references, as the ble_gap_adv_set_fields() function makes a copy of all the advertisement data before it returns. bleprph doesn't take full advantange of this; it stores its device name in a static array. The code sets three members of the struct ble_hs_adv_fields instance: name name_len name_is_complete The first two fields are used to communicate the device's name and are quite straight-forward. The third field requires some explanation. Bluetooth specifies two name-related advertisement fields: Shortened Local Name and Complete Local Name . Setting the name_is_complete variable to 1 or 0 tells NimBLE which of these two fields to include in advertisements. Some other advertisement fields also correspond to multiple variables in the field struct, so it is a good idea to review the ble_hs_adv_fields reference to make sure you get the details right in your app. Begin advertising An app starts advertising with the following function: int ble_gap_adv_start ( uint8_t discoverable_mode , uint8_t connectable_mode , uint8_t *peer_addr , uint8_t peer_addr_type , struct hci_adv_params *adv_params , ble_gap_conn_fn *cb , void *cb_arg ) This function allows a lot of flexibility, and it might seem daunting at first glance. bleprph specifies a simple set of arguments that is appropriate for most peripherals. When getting started on a typical peripheral, we recommend you use the same arguments as bleprph , with the exception of the last two ( cb and cb_arg ). These last two arguments will be specific to your app, so let's talk about them. cb is a callback function. It gets executed when a central connects to your peripheral after receiving an advertisement. The cb_arg argument gets passed to the cb callback. If your callback doesn't need the cb_arg parameter, you can do what bleprph does and pass NULL . Once a connection is established, the cb callback becomes permanently associated with the connection. All subsequent events related to the connection are communicated to your app via calls to this callback function. Connection callbacks are an important part of building a BLE app, and we examine bleprph 's connection callback in detail in the next section of this tutorial. One final note: Your peripheral automatically stops advertising when a central connects to it. You can immediately resume advertising if you want to allow another central to connect, but you will need to do so explicitly by calling ble_gap_adv_start() again. Also, be aware NimBLE's default configuration only allows a single connection at a time. NimBLE supports multiple concurrent connections, but you must configure it to do so first.","title":"Advertising"},{"location":"os/tutorials/bleprph/bleprph-adv/#ble-peripheral-project","text":"","title":"BLE Peripheral Project"},{"location":"os/tutorials/bleprph/bleprph-adv/#advertising","text":"","title":"Advertising"},{"location":"os/tutorials/bleprph/bleprph-adv/#overview","text":"A peripheral announces its presence to the world by broadcasting advertisements. An advertisement typically contains additional information about the peripheral sending it, such as the device name and an abbreviated list of supported services. The presence of this information helps a listening central to determine whether it is interested in connecting to the peripheral. Advertisements are quite limited in the amount of information they can contain, so only the most important information should be included. When a listening device receives an advertisement, it can choose to connect to the peripheral, or query the sender for more information. This second action is known as an active scan . A peripheral responds to an active scan with some extra information that it couldn't fit in its advertisement. This additional information is known as scan response data . bleprph does not configure any scan response data, so this feature is not discussed in the remainder of this tutorial. bleprph constantly broadcasts advertisements until a central connects to it. When a connection is terminated, bleprph resumes advertising. Let's take a look at bleprph 's advertisement code ( main.c ): /** * Enables advertising with the following parameters: * o General discoverable mode. * o Undirected connectable mode. */ static void bleprph_advertise ( void ) { struct ble_hs_adv_fields fields ; int rc ; /* Set the advertisement data included in our advertisements. */ memset ( &fields , 0 , sizeof fields ); fields . name = ( uint8_t * ) bleprph_device_name ; fields . name_len = strlen ( bleprph_device_name ); fields . name_is_complete = 1 ; rc = ble_gap_adv_set_fields ( &fields ); if ( rc != 0 ) { BLEPRPH_LOG ( ERROR , \"error setting advertisement data; rc=%d\\n\" , rc ); return ; } /* Begin advertising. */ rc = ble_gap_adv_start ( BLE_GAP_DISC_MODE_GEN , BLE_GAP_CONN_MODE_UND , NULL , 0 , NULL , bleprph_on_connect , NULL ); if ( rc != 0 ) { BLEPRPH_LOG ( ERROR , \"error enabling advertisement; rc=%d\\n\" , rc ); return ; } } Now let's examine this code in detail.","title":"Overview"},{"location":"os/tutorials/bleprph/bleprph-adv/#setting-advertisement-data","text":"A NimBLE peripheral specifies what information to include in its advertisements with the following function: int ble_gap_adv_set_fields ( struct ble_hs_adv_fields *adv_fields ) The adv_fields argument specifies the fields and their contents to include in subsequent advertisements. The Bluetooth Core Specification Supplement defines a set of standard fields that can be included in an advertisement; the member variables of the struct ble_hs_adv_fields type correspond to these standard fields. Information that doesn't fit neatly into a standard field should be put in the manufacturing specific data field. As you can see in the above code listing, the struct ble_hs_adv_fields instance is allocated on the stack. It is OK to use the stack for this struct and the data it references, as the ble_gap_adv_set_fields() function makes a copy of all the advertisement data before it returns. bleprph doesn't take full advantange of this; it stores its device name in a static array. The code sets three members of the struct ble_hs_adv_fields instance: name name_len name_is_complete The first two fields are used to communicate the device's name and are quite straight-forward. The third field requires some explanation. Bluetooth specifies two name-related advertisement fields: Shortened Local Name and Complete Local Name . Setting the name_is_complete variable to 1 or 0 tells NimBLE which of these two fields to include in advertisements. Some other advertisement fields also correspond to multiple variables in the field struct, so it is a good idea to review the ble_hs_adv_fields reference to make sure you get the details right in your app.","title":"Setting advertisement data"},{"location":"os/tutorials/bleprph/bleprph-adv/#begin-advertising","text":"An app starts advertising with the following function: int ble_gap_adv_start ( uint8_t discoverable_mode , uint8_t connectable_mode , uint8_t *peer_addr , uint8_t peer_addr_type , struct hci_adv_params *adv_params , ble_gap_conn_fn *cb , void *cb_arg ) This function allows a lot of flexibility, and it might seem daunting at first glance. bleprph specifies a simple set of arguments that is appropriate for most peripherals. When getting started on a typical peripheral, we recommend you use the same arguments as bleprph , with the exception of the last two ( cb and cb_arg ). These last two arguments will be specific to your app, so let's talk about them. cb is a callback function. It gets executed when a central connects to your peripheral after receiving an advertisement. The cb_arg argument gets passed to the cb callback. If your callback doesn't need the cb_arg parameter, you can do what bleprph does and pass NULL . Once a connection is established, the cb callback becomes permanently associated with the connection. All subsequent events related to the connection are communicated to your app via calls to this callback function. Connection callbacks are an important part of building a BLE app, and we examine bleprph 's connection callback in detail in the next section of this tutorial. One final note: Your peripheral automatically stops advertising when a central connects to it. You can immediately resume advertising if you want to allow another central to connect, but you will need to do so explicitly by calling ble_gap_adv_start() again. Also, be aware NimBLE's default configuration only allows a single connection at a time. NimBLE supports multiple concurrent connections, but you must configure it to do so first.","title":"Begin advertising"},{"location":"os/tutorials/bleprph/bleprph-chr-access/","text":"BLE Peripheral Project Characteristic Access Review A characteristic's access callback implements its behavior. Recall that services and characteristics are registered with NimBLE via attribute tables. Each characteristic definition in an attribute table contains an access_cb field. The access_cb field is an application callback that gets executed whenever a peer device attempts to read or write the characteristic. Earlier in this tutorial, we looked at how bleprph implements the GAP service. Let's take another look at how bleprph specifies the first few characteristics in this service. static const struct ble_gatt_svc_def gatt_svr_svcs [] = { { /*** Service: GAP. */ . type = BLE_GATT_SVC_TYPE_PRIMARY , . uuid128 = BLE_UUID16 ( BLE_GAP_SVC_UUID16 ), . characteristics = ( struct ble_gatt_chr_def []) { { /*** Characteristic: Device Name. */ . uuid128 = BLE_UUID16 ( BLE_GAP_CHR_UUID16_DEVICE_NAME ), . access_cb = gatt_svr_chr_access_gap , . flags = BLE_GATT_CHR_F_READ , }, { /*** Characteristic: Appearance. */ . uuid128 = BLE_UUID16 ( BLE_GAP_CHR_UUID16_APPEARANCE ), . access_cb = gatt_svr_chr_access_gap , . flags = BLE_GATT_CHR_F_READ , }, { // [...] As you can see, bleprph uses the same access_cb function for all the GAP service characteristics, but the developer could have implemented separate functions for each characteristic if they preferred. Here is the access_cb function that the GAP service characteristics use: static int gatt_svr_chr_access_gap ( uint16_t conn_handle , uint16_t attr_handle , uint8_t op , union ble_gatt_access_ctxt *ctxt , void *arg ) { uint16_t uuid16 ; uuid16 = ble_uuid_128_to_16 ( ctxt->chr_access . chr->uuid128 ); assert ( uuid16 != 0 ); switch ( uuid16 ) { case BLE_GAP_CHR_UUID16_DEVICE_NAME : assert ( op == BLE_GATT_ACCESS_OP_READ_CHR ); ctxt->chr_access . data = ( void * ) bleprph_device_name ; ctxt->chr_access . len = strlen ( bleprph_device_name ); break ; case BLE_GAP_CHR_UUID16_APPEARANCE : assert ( op == BLE_GATT_ACCESS_OP_READ_CHR ); ctxt->chr_access . data = ( void * ) &bleprph_appearance ; ctxt->chr_access . len = sizeof bleprph_appearance ; break ; case BLE_GAP_CHR_UUID16_PERIPH_PRIV_FLAG : assert ( op == BLE_GATT_ACCESS_OP_READ_CHR ); ctxt->chr_access . data = ( void * ) &bleprph_privacy_flag ; ctxt->chr_access . len = sizeof bleprph_privacy_flag ; break ; case BLE_GAP_CHR_UUID16_RECONNECT_ADDR : assert ( op == BLE_GATT_ACCESS_OP_WRITE_CHR ); if ( ctxt->chr_access . len != sizeof bleprph_reconnect_addr ) { return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN ; } memcpy ( bleprph_reconnect_addr , ctxt->chr_access . data , sizeof bleprph_reconnect_addr ); break ; case BLE_GAP_CHR_UUID16_PERIPH_PREF_CONN_PARAMS : assert ( op == BLE_GATT_ACCESS_OP_READ_CHR ); ctxt->chr_access . data = ( void * ) &bleprph_pref_conn_params ; ctxt->chr_access . len = sizeof bleprph_pref_conn_params ; break ; default : assert ( 0 ); break ; } return 0 ; } After you've taken a moment to examine the structure of this function, let's explore some details. Function signature static int gatt_svr_chr_access_gap ( uint16_t conn_handle , uint16_t attr_handle , uint8_t op , union ble_gatt_access_ctxt *ctxt , void *arg ) A characteristic access function always takes this same set of parameters and always returns an int. The parameters to this function type are documented below. Parameter Purpose Notes conn_handle Indicates which connection the characteristic access was sent over. Use this value to determine which peer is accessing the characteristic. attr_handle The low-level ATT handle of the characteristic value attribute. Can be used to determine which characteristic is being accessed if you don't want to perform a UUID lookup. op Indicates whether this is a read or write operation Valid values are: BLE_GATT_ACCESS_OP_READ_CHR BLE_GATT_ACCESS_OP_WRITE_CHR ctxt Contains the characteristic value pointer that the application needs to access. For characteristic accesses, use the ctxt->chr_access member; for descriptor accesses, use the ctxt->dsc_access member. The return value of the access function tells the NimBLE stack how to respond to the peer performing the operation. A value of 0 indicates success. For failures, the function returns the specific ATT error code that the NimBLE stack should respond with. The ATT error codes are defined in net/nimble/host/include/host/ble_att.h . Determine characteristic being accessed { uint16_t uuid16 ; uuid16 = ble_uuid_128_to_16 ( ctxt->chr_access . chr->uuid128 ); assert ( uuid16 != 0 ); switch ( uuid16 ) { // [...] This function uses the UUID to determine which characteristic is being accessed. There are two alternative methods bleprph could have used to accomplish this task: Map characteristics to ATT handles during service registration; use the attr_handle parameter as a key into this table during characteristic access. Implement a dedicated function for each characteristic; each function inherently knows which characteristic it corresponds to. All the GAP service characteristics have 16-bit UUIDs, so this function uses the ble_uuid_128_to_16() function to convert the 128-bit UUID to its corresponding 16-bit UUID. This conversion function returns the corresponding 16-bit UUID on success, or 0 on failure. Success is asserted here to ensure the NimBLE stack is doing its job properly; the stack should only call this function for accesses to characteristics that it is registered with, and all GAP service characteristics have valid 16-bit UUIDs. Read access case BLE_GAP_CHR_UUID16_DEVICE_NAME : assert ( op == BLE_GATT_ACCESS_OP_READ_CHR ); ctxt->chr_access . data = ( void * ) bleprph_device_name ; ctxt->chr_access . len = strlen ( bleprph_device_name ); break ; This code excerpt handles read accesses to the device name characteristic. The assert() here is another case of making sure the NimBLE stack is doing its job; this characteristic was registered as read-only, so the stack should have prevented write accesses. To fulfill a characteristic read request, the application needs to assign the ctxt->chr_access.data field to point to the attribute data to respond with, and fill the ctxt->chr_access.len field with the length of the attribute data. bleprph stores the device name in read-only memory as follows: const char *bleprph_device_name = \"nimble-bleprph\" ; The cast to pointer-to-void is a necessary annoyance to remove the const qualifier from the device name variable. You will need to \"cast away const\" whenever you respond to read requests with read-only data. It is not shown in the above snippet, but this function ultimately returns 0. By returning 0, bleprph indicates that the characteristic data in ctxt->chr_access is valid and that NimBLE should include it in its response to the peer. A word of warning: The attribute data that ctxt->chr_access.data points to must remain valid after the access function returns, as the NimBLE stack needs to use it to form a GATT read response. In other words, you must not allocate the characteristic value data on the stack of the access function. Two characteristic accesses never occur at the same time, so it is OK to use the same memory for repeated accesses. Write access case BLE_GAP_CHR_UUID16_RECONNECT_ADDR : assert ( op == BLE_GATT_ACCESS_OP_WRITE_CHR ); if ( ctxt->chr_access . len != sizeof bleprph_reconnect_addr ) { return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN ; } memcpy ( bleprph_reconnect_addr , ctxt->chr_access . data , sizeof bleprph_reconnect_addr ); break ; This code excerpt handles writes to the reconnect address characteristic. This characteristic was registered as write-only, so the assert() here is just a safety precaution to ensure the NimBLE stack is doing its job. For writes, the roles of the ctxt->chr_access.data and ctxt->chr_access.len fields are the reverse of the read case. The NimBLE stack uses these fields to indicate the data written by the peer. Many characteristics have strict length requirements for write operations. This characteristic has such a restriction; if the written data is not a 48-bit BR address, the application tells NimBLE to respond with an invalid attribute value length error. For writes, the ctxt->chr_access.data pointer is only valid for the duration of the access function. If the application needs to save the written data, it should store it elsewhere before the function returns. In this case, bleprph stores the specified address in a global variable called bleprph_reconnect_addr .","title":"Characteristic Access"},{"location":"os/tutorials/bleprph/bleprph-chr-access/#ble-peripheral-project","text":"","title":"BLE Peripheral Project"},{"location":"os/tutorials/bleprph/bleprph-chr-access/#characteristic-access","text":"","title":"Characteristic Access"},{"location":"os/tutorials/bleprph/bleprph-chr-access/#review","text":"A characteristic's access callback implements its behavior. Recall that services and characteristics are registered with NimBLE via attribute tables. Each characteristic definition in an attribute table contains an access_cb field. The access_cb field is an application callback that gets executed whenever a peer device attempts to read or write the characteristic. Earlier in this tutorial, we looked at how bleprph implements the GAP service. Let's take another look at how bleprph specifies the first few characteristics in this service. static const struct ble_gatt_svc_def gatt_svr_svcs [] = { { /*** Service: GAP. */ . type = BLE_GATT_SVC_TYPE_PRIMARY , . uuid128 = BLE_UUID16 ( BLE_GAP_SVC_UUID16 ), . characteristics = ( struct ble_gatt_chr_def []) { { /*** Characteristic: Device Name. */ . uuid128 = BLE_UUID16 ( BLE_GAP_CHR_UUID16_DEVICE_NAME ), . access_cb = gatt_svr_chr_access_gap , . flags = BLE_GATT_CHR_F_READ , }, { /*** Characteristic: Appearance. */ . uuid128 = BLE_UUID16 ( BLE_GAP_CHR_UUID16_APPEARANCE ), . access_cb = gatt_svr_chr_access_gap , . flags = BLE_GATT_CHR_F_READ , }, { // [...] As you can see, bleprph uses the same access_cb function for all the GAP service characteristics, but the developer could have implemented separate functions for each characteristic if they preferred. Here is the access_cb function that the GAP service characteristics use: static int gatt_svr_chr_access_gap ( uint16_t conn_handle , uint16_t attr_handle , uint8_t op , union ble_gatt_access_ctxt *ctxt , void *arg ) { uint16_t uuid16 ; uuid16 = ble_uuid_128_to_16 ( ctxt->chr_access . chr->uuid128 ); assert ( uuid16 != 0 ); switch ( uuid16 ) { case BLE_GAP_CHR_UUID16_DEVICE_NAME : assert ( op == BLE_GATT_ACCESS_OP_READ_CHR ); ctxt->chr_access . data = ( void * ) bleprph_device_name ; ctxt->chr_access . len = strlen ( bleprph_device_name ); break ; case BLE_GAP_CHR_UUID16_APPEARANCE : assert ( op == BLE_GATT_ACCESS_OP_READ_CHR ); ctxt->chr_access . data = ( void * ) &bleprph_appearance ; ctxt->chr_access . len = sizeof bleprph_appearance ; break ; case BLE_GAP_CHR_UUID16_PERIPH_PRIV_FLAG : assert ( op == BLE_GATT_ACCESS_OP_READ_CHR ); ctxt->chr_access . data = ( void * ) &bleprph_privacy_flag ; ctxt->chr_access . len = sizeof bleprph_privacy_flag ; break ; case BLE_GAP_CHR_UUID16_RECONNECT_ADDR : assert ( op == BLE_GATT_ACCESS_OP_WRITE_CHR ); if ( ctxt->chr_access . len != sizeof bleprph_reconnect_addr ) { return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN ; } memcpy ( bleprph_reconnect_addr , ctxt->chr_access . data , sizeof bleprph_reconnect_addr ); break ; case BLE_GAP_CHR_UUID16_PERIPH_PREF_CONN_PARAMS : assert ( op == BLE_GATT_ACCESS_OP_READ_CHR ); ctxt->chr_access . data = ( void * ) &bleprph_pref_conn_params ; ctxt->chr_access . len = sizeof bleprph_pref_conn_params ; break ; default : assert ( 0 ); break ; } return 0 ; } After you've taken a moment to examine the structure of this function, let's explore some details.","title":"Review"},{"location":"os/tutorials/bleprph/bleprph-chr-access/#function-signature","text":"static int gatt_svr_chr_access_gap ( uint16_t conn_handle , uint16_t attr_handle , uint8_t op , union ble_gatt_access_ctxt *ctxt , void *arg ) A characteristic access function always takes this same set of parameters and always returns an int. The parameters to this function type are documented below. Parameter Purpose Notes conn_handle Indicates which connection the characteristic access was sent over. Use this value to determine which peer is accessing the characteristic. attr_handle The low-level ATT handle of the characteristic value attribute. Can be used to determine which characteristic is being accessed if you don't want to perform a UUID lookup. op Indicates whether this is a read or write operation Valid values are: BLE_GATT_ACCESS_OP_READ_CHR BLE_GATT_ACCESS_OP_WRITE_CHR ctxt Contains the characteristic value pointer that the application needs to access. For characteristic accesses, use the ctxt->chr_access member; for descriptor accesses, use the ctxt->dsc_access member. The return value of the access function tells the NimBLE stack how to respond to the peer performing the operation. A value of 0 indicates success. For failures, the function returns the specific ATT error code that the NimBLE stack should respond with. The ATT error codes are defined in net/nimble/host/include/host/ble_att.h .","title":"Function signature"},{"location":"os/tutorials/bleprph/bleprph-chr-access/#determine-characteristic-being-accessed","text":"{ uint16_t uuid16 ; uuid16 = ble_uuid_128_to_16 ( ctxt->chr_access . chr->uuid128 ); assert ( uuid16 != 0 ); switch ( uuid16 ) { // [...] This function uses the UUID to determine which characteristic is being accessed. There are two alternative methods bleprph could have used to accomplish this task: Map characteristics to ATT handles during service registration; use the attr_handle parameter as a key into this table during characteristic access. Implement a dedicated function for each characteristic; each function inherently knows which characteristic it corresponds to. All the GAP service characteristics have 16-bit UUIDs, so this function uses the ble_uuid_128_to_16() function to convert the 128-bit UUID to its corresponding 16-bit UUID. This conversion function returns the corresponding 16-bit UUID on success, or 0 on failure. Success is asserted here to ensure the NimBLE stack is doing its job properly; the stack should only call this function for accesses to characteristics that it is registered with, and all GAP service characteristics have valid 16-bit UUIDs.","title":"Determine characteristic being accessed"},{"location":"os/tutorials/bleprph/bleprph-chr-access/#read-access","text":"case BLE_GAP_CHR_UUID16_DEVICE_NAME : assert ( op == BLE_GATT_ACCESS_OP_READ_CHR ); ctxt->chr_access . data = ( void * ) bleprph_device_name ; ctxt->chr_access . len = strlen ( bleprph_device_name ); break ; This code excerpt handles read accesses to the device name characteristic. The assert() here is another case of making sure the NimBLE stack is doing its job; this characteristic was registered as read-only, so the stack should have prevented write accesses. To fulfill a characteristic read request, the application needs to assign the ctxt->chr_access.data field to point to the attribute data to respond with, and fill the ctxt->chr_access.len field with the length of the attribute data. bleprph stores the device name in read-only memory as follows: const char *bleprph_device_name = \"nimble-bleprph\" ; The cast to pointer-to-void is a necessary annoyance to remove the const qualifier from the device name variable. You will need to \"cast away const\" whenever you respond to read requests with read-only data. It is not shown in the above snippet, but this function ultimately returns 0. By returning 0, bleprph indicates that the characteristic data in ctxt->chr_access is valid and that NimBLE should include it in its response to the peer. A word of warning: The attribute data that ctxt->chr_access.data points to must remain valid after the access function returns, as the NimBLE stack needs to use it to form a GATT read response. In other words, you must not allocate the characteristic value data on the stack of the access function. Two characteristic accesses never occur at the same time, so it is OK to use the same memory for repeated accesses.","title":"Read access"},{"location":"os/tutorials/bleprph/bleprph-chr-access/#write-access","text":"case BLE_GAP_CHR_UUID16_RECONNECT_ADDR : assert ( op == BLE_GATT_ACCESS_OP_WRITE_CHR ); if ( ctxt->chr_access . len != sizeof bleprph_reconnect_addr ) { return BLE_ATT_ERR_INVALID_ATTR_VALUE_LEN ; } memcpy ( bleprph_reconnect_addr , ctxt->chr_access . data , sizeof bleprph_reconnect_addr ); break ; This code excerpt handles writes to the reconnect address characteristic. This characteristic was registered as write-only, so the assert() here is just a safety precaution to ensure the NimBLE stack is doing its job. For writes, the roles of the ctxt->chr_access.data and ctxt->chr_access.len fields are the reverse of the read case. The NimBLE stack uses these fields to indicate the data written by the peer. Many characteristics have strict length requirements for write operations. This characteristic has such a restriction; if the written data is not a 48-bit BR address, the application tells NimBLE to respond with an invalid attribute value length error. For writes, the ctxt->chr_access.data pointer is only valid for the duration of the access function. If the application needs to save the written data, it should store it elsewhere before the function returns. In this case, bleprph stores the specified address in a global variable called bleprph_reconnect_addr .","title":"Write access"},{"location":"os/tutorials/bleprph/bleprph-conn/","text":"BLE Peripheral Project Connection callbacks Overview Every BLE connection has a connection callback associated with it. A connection callback is a bit of application code which NimBLE uses to inform you of connection-related events. For example, if a connection is terminated, NimBLE lets you know about it with a call to that connection's callback. In the advertising section of this tutorial, we saw how the application specifies a connection callback when it begins advertising. NimBLE uses this callback to notify the application that a central has connected to your peripheral after receiving an advertisement. Let's revisit how bleprph specifies its connection callback when advertising: /* Begin advertising. */ rc = ble_gap_adv_start ( BLE_GAP_DISC_MODE_GEN , BLE_GAP_CONN_MODE_UND , NULL , 0 , NULL , bleprph_on_connect , NULL ); if ( rc != 0 ) { BLEPRPH_LOG ( ERROR , \"error enabling advertisement; rc=%d\\n\" , rc ); return ; } bleprph_on_connect() The bleprph_on_connect() function is bleprph 's connection callback; NimBLE calls this function when the advertising operation leads to connection establishment. Upon connecting, this callback becomes permanently associated with the connection; all subsequent events related to this connection are communicated through this callback. Now let's look at the function that bleprph uses for all its connection callbacks: bleprph_on_connect() . static int bleprph_on_connect ( int event , int status , struct ble_gap_conn_ctxt *ctxt , void *arg ) { switch ( event ) { case BLE_GAP_EVENT_CONN : BLEPRPH_LOG ( INFO , \"connection %s; status=%d \" , status == 0 ? \"up\" : \"down\" , status ); bleprph_print_conn_desc ( ctxt->desc ); BLEPRPH_LOG ( INFO , \"\\n\" ); if ( status != 0 ) { /* Connection terminated; resume advertising. */ bleprph_advertise (); } break ; } return 0 ; } Connection callbacks are used to communicate a variety of events related to a connection. An application determines the type of event that occurred by inspecting the value of the event parameter. The full list of event codes can be found in net/nimble/host/include/host/ble_gatt.h . bleprph only concerns itself with a single event type: BLE_GAP_EVENT_CONN . This event indicates that a new connection has been established, or an existing connection has been terminated; the status parameter clarifies which. As you can see, bleprph uses the status parameter to determine if it should resume advertising. The ctxt parameter contains additional information about the connection event. bleprph does nothing more than log some fields of this struct, but some apps will likely want to perform further actions, e.g., perform service discovery on the connected device. The struct ble_gap_conn_ctxt type is defined as follows: struct ble_gap_conn_ctxt { struct ble_gap_conn_desc *desc ; union { struct { struct ble_gap_upd_params *self_params ; struct ble_gap_upd_params *peer_params ; } update ; struct ble_gap_sec_params *sec_params ; }; }; As shown, a connection context object consists of two parts: desc: The connection descriptor; indicates properties of the connection. anonymous union: The contents are event-specific; check the event code to determine which member field (if any) is relevant. For events of type BLE_GAP_EVENT_CONN , the anonymous union is not used at all, so the only information carried by the context struct is the connection descriptor. The struct ble_gap_conn_desc type is defined as follows: struct ble_gap_conn_desc { uint8_t peer_addr [ 6 ]; uint16_t conn_handle ; uint16_t conn_itvl ; uint16_t conn_latency ; uint16_t supervision_timeout ; uint8_t peer_addr_type ; }; We will examine these fields in a slightly different order from how they appear in the struct definition. Field Purpose Notes peer_addr The 48-bit address of the peer device. peer_addr_type Whether the peer is using a public or random address. The address type list is documented in net/nimble/include/nimble/hci_common.h . conn_handle The 16-bit handle associated with this connection. This number is how your app and the NimBLE stack refer to this connection. conn_itvl, conn_latency, supervision_timeout Low-level properties of the connection. Guarantees It is important to know what your application code is allowed to do from within a connection callback. No restrictions on NimBLE operations Your app is free to make calls into the NimBLE stack from within a connection callback. bleprph takes advantage of this freedom when it resumes advertising upon connection termination. All other NimBLE operations are also allowed (service discovery, pairing initiation, etc). All context data is transient Pointers in the context object point to data living on the stack. Your callback is free to read (or write, if appropriate) through these pointers, but you should not store these pointers for later use. If your application needs to retain some data from a context object, it needs to make a copy.","title":"Connection Callbacks"},{"location":"os/tutorials/bleprph/bleprph-conn/#ble-peripheral-project","text":"","title":"BLE Peripheral Project"},{"location":"os/tutorials/bleprph/bleprph-conn/#connection-callbacks","text":"","title":"Connection callbacks"},{"location":"os/tutorials/bleprph/bleprph-conn/#overview","text":"Every BLE connection has a connection callback associated with it. A connection callback is a bit of application code which NimBLE uses to inform you of connection-related events. For example, if a connection is terminated, NimBLE lets you know about it with a call to that connection's callback. In the advertising section of this tutorial, we saw how the application specifies a connection callback when it begins advertising. NimBLE uses this callback to notify the application that a central has connected to your peripheral after receiving an advertisement. Let's revisit how bleprph specifies its connection callback when advertising: /* Begin advertising. */ rc = ble_gap_adv_start ( BLE_GAP_DISC_MODE_GEN , BLE_GAP_CONN_MODE_UND , NULL , 0 , NULL , bleprph_on_connect , NULL ); if ( rc != 0 ) { BLEPRPH_LOG ( ERROR , \"error enabling advertisement; rc=%d\\n\" , rc ); return ; }","title":"Overview"},{"location":"os/tutorials/bleprph/bleprph-conn/#bleprph_on_connect","text":"The bleprph_on_connect() function is bleprph 's connection callback; NimBLE calls this function when the advertising operation leads to connection establishment. Upon connecting, this callback becomes permanently associated with the connection; all subsequent events related to this connection are communicated through this callback. Now let's look at the function that bleprph uses for all its connection callbacks: bleprph_on_connect() . static int bleprph_on_connect ( int event , int status , struct ble_gap_conn_ctxt *ctxt , void *arg ) { switch ( event ) { case BLE_GAP_EVENT_CONN : BLEPRPH_LOG ( INFO , \"connection %s; status=%d \" , status == 0 ? \"up\" : \"down\" , status ); bleprph_print_conn_desc ( ctxt->desc ); BLEPRPH_LOG ( INFO , \"\\n\" ); if ( status != 0 ) { /* Connection terminated; resume advertising. */ bleprph_advertise (); } break ; } return 0 ; } Connection callbacks are used to communicate a variety of events related to a connection. An application determines the type of event that occurred by inspecting the value of the event parameter. The full list of event codes can be found in net/nimble/host/include/host/ble_gatt.h . bleprph only concerns itself with a single event type: BLE_GAP_EVENT_CONN . This event indicates that a new connection has been established, or an existing connection has been terminated; the status parameter clarifies which. As you can see, bleprph uses the status parameter to determine if it should resume advertising. The ctxt parameter contains additional information about the connection event. bleprph does nothing more than log some fields of this struct, but some apps will likely want to perform further actions, e.g., perform service discovery on the connected device. The struct ble_gap_conn_ctxt type is defined as follows: struct ble_gap_conn_ctxt { struct ble_gap_conn_desc *desc ; union { struct { struct ble_gap_upd_params *self_params ; struct ble_gap_upd_params *peer_params ; } update ; struct ble_gap_sec_params *sec_params ; }; }; As shown, a connection context object consists of two parts: desc: The connection descriptor; indicates properties of the connection. anonymous union: The contents are event-specific; check the event code to determine which member field (if any) is relevant. For events of type BLE_GAP_EVENT_CONN , the anonymous union is not used at all, so the only information carried by the context struct is the connection descriptor. The struct ble_gap_conn_desc type is defined as follows: struct ble_gap_conn_desc { uint8_t peer_addr [ 6 ]; uint16_t conn_handle ; uint16_t conn_itvl ; uint16_t conn_latency ; uint16_t supervision_timeout ; uint8_t peer_addr_type ; }; We will examine these fields in a slightly different order from how they appear in the struct definition. Field Purpose Notes peer_addr The 48-bit address of the peer device. peer_addr_type Whether the peer is using a public or random address. The address type list is documented in net/nimble/include/nimble/hci_common.h . conn_handle The 16-bit handle associated with this connection. This number is how your app and the NimBLE stack refer to this connection. conn_itvl, conn_latency, supervision_timeout Low-level properties of the connection.","title":"bleprph_on_connect()"},{"location":"os/tutorials/bleprph/bleprph-conn/#guarantees","text":"It is important to know what your application code is allowed to do from within a connection callback. No restrictions on NimBLE operations Your app is free to make calls into the NimBLE stack from within a connection callback. bleprph takes advantage of this freedom when it resumes advertising upon connection termination. All other NimBLE operations are also allowed (service discovery, pairing initiation, etc). All context data is transient Pointers in the context object point to data living on the stack. Your callback is free to read (or write, if appropriate) through these pointers, but you should not store these pointers for later use. If your application needs to retain some data from a context object, it needs to make a copy.","title":"Guarantees"},{"location":"os/tutorials/bleprph/bleprph-intro/","text":"BLE Peripheral Project Introduction Overview bleprph is an example app included in the apache-mynewt-core repository. This app implements a simple BLE peripheral with the following properties: Supports three services: GAP, GATT, and alert notification service (ANS). Supports a single concurrent connection. Automatically advertises connectability when not connected to a central device. This tutorial aims to provide a guided tour through the bleprph app source code. This document builds on some concepts described elsewhere in the Apache Mynewt documentation. Before proceeding with this tutorial, you might want to familiarize yourself with the following pages: Create Your First Mynewt Project NimBLE Stack Initialization Services, Characteristics, Descriptors A BLE peripheral interfaces with other BLE devices by exposing services , characteristics , and descriptors . All three of these entities are implemented at a lower layer via attributes . If you are not familiar with these concepts, you will probably want to check out this overview from the Bluetooth Developer's site before proceeding. Now let's dig in to some C code.","title":"toc"},{"location":"os/tutorials/bleprph/bleprph-intro/#ble-peripheral-project","text":"","title":"BLE Peripheral Project"},{"location":"os/tutorials/bleprph/bleprph-intro/#introduction","text":"","title":"Introduction"},{"location":"os/tutorials/bleprph/bleprph-intro/#overview","text":"bleprph is an example app included in the apache-mynewt-core repository. This app implements a simple BLE peripheral with the following properties: Supports three services: GAP, GATT, and alert notification service (ANS). Supports a single concurrent connection. Automatically advertises connectability when not connected to a central device. This tutorial aims to provide a guided tour through the bleprph app source code. This document builds on some concepts described elsewhere in the Apache Mynewt documentation. Before proceeding with this tutorial, you might want to familiarize yourself with the following pages: Create Your First Mynewt Project NimBLE Stack Initialization","title":"Overview"},{"location":"os/tutorials/bleprph/bleprph-intro/#services-characteristics-descriptors","text":"A BLE peripheral interfaces with other BLE devices by exposing services , characteristics , and descriptors . All three of these entities are implemented at a lower layer via attributes . If you are not familiar with these concepts, you will probably want to check out this overview from the Bluetooth Developer's site before proceeding. Now let's dig in to some C code.","title":"Services, Characteristics, Descriptors"},{"location":"os/tutorials/bleprph/bleprph-svc-reg/","text":"BLE Peripheral Project Service Registration Attribute Set The NimBLE host uses a table-based design for GATT server configuration. The set of supported attributes are expressed as a series of tables that resides in your C code. When possible, we recommend using a single monolithic table, as it results in code that is simpler and less error prone. Multiple tables can be used if it is impractical for the entire attribute set to live in one place in your code. bleprph uses a single attribute table located in the gatt_svr.c file, so let's take a look at that now. The attribute table is called gatt_svr_svcs ; here are the first several lines from this table: static const struct ble_gatt_svc_def gatt_svr_svcs [] = { { /*** Service: GAP. */ . type = BLE_GATT_SVC_TYPE_PRIMARY , . uuid128 = BLE_UUID16 ( BLE_GAP_SVC_UUID16 ), . characteristics = ( struct ble_gatt_chr_def []) { { /*** Characteristic: Device Name. */ . uuid128 = BLE_UUID16 ( BLE_GAP_CHR_UUID16_DEVICE_NAME ), . access_cb = gatt_svr_chr_access_gap , . flags = BLE_GATT_CHR_F_READ , }, { /*** Characteristic: Appearance. */ . uuid128 = BLE_UUID16 ( BLE_GAP_CHR_UUID16_APPEARANCE ), . access_cb = gatt_svr_chr_access_gap , . flags = BLE_GATT_CHR_F_READ , }, { // [...] As you can see, the table is an array of service definitions ( struct ble_gatt_svc_def ). This code excerpt contains a small part of the GAP service . The GAP service exposes generic information about a device, such as its name and appearance. Support for the GAP service is mandatory for all BLE peripherals. Let's now consider the contents of this table in more detail. A service definition consists of the following fields: Field Meaning Notes type Specifies whether this is a primary or secondary service. Secondary services are not very common. When in doubt, specify BLE_GATT_SVC_TYPE_PRIMARY for new services. uuid128 The 128-bit UUID of this service. If the service has a 16-bit UUID, you can convert it to its corresponding 128-bit UUID with the BLE_UUID16() macro. characteristics The array of characteristics that belong to this service. A service is little more than a container of characteristics; the characteristics themselves are where the real action happens. A characteristic definition consists of the following fields: Field Meaning Notes uuid128 The 128-bit UUID of this characteristic. If the characteristic has a 16-bit UUID, you can convert it to its corresponding 128-bit UUID with the BLE_UUID16() macro. access_cb A callback function that gets executed whenever a peer device accesses this characteristic. For reads: this function generates the value that gets sent back to the peer. For writes: this function provides the written value as an argument. flags Indicates which operations are permitted for this characteristic. The NimBLE stack responds negatively when a peer attempts an unsupported operation. The full list of flags can be found under ble_gatt_chr_flags in net/nimble/host/include/host/ble_gatt.h . The access callback is what implements the characteristic's behavior. Access callbacks are described in detail in the next section: BLE Peripheral - Characteristic Access . The service definition array and each characteristic definition array is terminated with an empty entry, represented with a 0. The below code listing shows the last service in the array, including terminating zeros for the characteristic array and service array. { /*** Alert Notification Service. */ . type = BLE_GATT_SVC_TYPE_PRIMARY , . uuid128 = BLE_UUID16 ( GATT_SVR_SVC_ALERT_UUID ), . characteristics = ( struct ble_gatt_chr_def []) { { . uuid128 = BLE_UUID16 ( GATT_SVR_CHR_SUP_NEW_ALERT_CAT_UUID ), . access_cb = gatt_svr_chr_access_alert , . flags = BLE_GATT_CHR_F_READ , }, { . uuid128 = BLE_UUID16 ( GATT_SVR_CHR_NEW_ALERT ), . access_cb = gatt_svr_chr_access_alert , . flags = BLE_GATT_CHR_F_NOTIFY , }, { . uuid128 = BLE_UUID16 ( GATT_SVR_CHR_SUP_UNR_ALERT_CAT_UUID ), . access_cb = gatt_svr_chr_access_alert , . flags = BLE_GATT_CHR_F_READ , }, { . uuid128 = BLE_UUID16 ( GATT_SVR_CHR_UNR_ALERT_STAT_UUID ), . access_cb = gatt_svr_chr_access_alert , . flags = BLE_GATT_CHR_F_NOTIFY , }, { . uuid128 = BLE_UUID16 ( GATT_SVR_CHR_ALERT_NOT_CTRL_PT ), . access_cb = gatt_svr_chr_access_alert , . flags = BLE_GATT_CHR_F_WRITE , }, { 0 , /* No more characteristics in this service. */ } }, }, { 0 , /* No more services. */ }, Registration function After you have created your service table, your app needs to register it with the NimBLE stack. This is done by calling the following function: int ble_gatts_register_svcs ( const struct ble_gatt_svc_def *svcs , ble_gatt_register_fn *cb , void *cb_arg ) The function parameters are documented below. Parameter Meaning Notes svcs The table of services to register. cb A callback that gets executed each time a service, characteristic, or descriptor is registered. Optional; pass NULL if you don't want to be notified. cb_arg An argument that gets passed to the callback function on each invocation. Optional; pass NULL if there is no callback or if you don't need a special argument. The ble_gatts_register_svcs() function returns 0 on success, or a BLE_HS_E[...] error code on failure. More detailed information about the registration callback function can be found in the BLE User Guide (TBD). The bleprph app registers its services as follows: rc = ble_gatts_register_svcs ( gatt_svr_svcs , gatt_svr_register_cb , NULL ); assert ( rc == 0 ); Descriptors and Included Services Your peripheral can also expose descriptors and included services. These are less common, so they are not covered in this tutorial. For more information, see the BLE User Guide .","title":"Service Registration"},{"location":"os/tutorials/bleprph/bleprph-svc-reg/#ble-peripheral-project","text":"","title":"BLE Peripheral Project"},{"location":"os/tutorials/bleprph/bleprph-svc-reg/#service-registration","text":"","title":"Service Registration"},{"location":"os/tutorials/bleprph/bleprph-svc-reg/#attribute-set","text":"The NimBLE host uses a table-based design for GATT server configuration. The set of supported attributes are expressed as a series of tables that resides in your C code. When possible, we recommend using a single monolithic table, as it results in code that is simpler and less error prone. Multiple tables can be used if it is impractical for the entire attribute set to live in one place in your code. bleprph uses a single attribute table located in the gatt_svr.c file, so let's take a look at that now. The attribute table is called gatt_svr_svcs ; here are the first several lines from this table: static const struct ble_gatt_svc_def gatt_svr_svcs [] = { { /*** Service: GAP. */ . type = BLE_GATT_SVC_TYPE_PRIMARY , . uuid128 = BLE_UUID16 ( BLE_GAP_SVC_UUID16 ), . characteristics = ( struct ble_gatt_chr_def []) { { /*** Characteristic: Device Name. */ . uuid128 = BLE_UUID16 ( BLE_GAP_CHR_UUID16_DEVICE_NAME ), . access_cb = gatt_svr_chr_access_gap , . flags = BLE_GATT_CHR_F_READ , }, { /*** Characteristic: Appearance. */ . uuid128 = BLE_UUID16 ( BLE_GAP_CHR_UUID16_APPEARANCE ), . access_cb = gatt_svr_chr_access_gap , . flags = BLE_GATT_CHR_F_READ , }, { // [...] As you can see, the table is an array of service definitions ( struct ble_gatt_svc_def ). This code excerpt contains a small part of the GAP service . The GAP service exposes generic information about a device, such as its name and appearance. Support for the GAP service is mandatory for all BLE peripherals. Let's now consider the contents of this table in more detail. A service definition consists of the following fields: Field Meaning Notes type Specifies whether this is a primary or secondary service. Secondary services are not very common. When in doubt, specify BLE_GATT_SVC_TYPE_PRIMARY for new services. uuid128 The 128-bit UUID of this service. If the service has a 16-bit UUID, you can convert it to its corresponding 128-bit UUID with the BLE_UUID16() macro. characteristics The array of characteristics that belong to this service. A service is little more than a container of characteristics; the characteristics themselves are where the real action happens. A characteristic definition consists of the following fields: Field Meaning Notes uuid128 The 128-bit UUID of this characteristic. If the characteristic has a 16-bit UUID, you can convert it to its corresponding 128-bit UUID with the BLE_UUID16() macro. access_cb A callback function that gets executed whenever a peer device accesses this characteristic. For reads: this function generates the value that gets sent back to the peer. For writes: this function provides the written value as an argument. flags Indicates which operations are permitted for this characteristic. The NimBLE stack responds negatively when a peer attempts an unsupported operation. The full list of flags can be found under ble_gatt_chr_flags in net/nimble/host/include/host/ble_gatt.h . The access callback is what implements the characteristic's behavior. Access callbacks are described in detail in the next section: BLE Peripheral - Characteristic Access . The service definition array and each characteristic definition array is terminated with an empty entry, represented with a 0. The below code listing shows the last service in the array, including terminating zeros for the characteristic array and service array. { /*** Alert Notification Service. */ . type = BLE_GATT_SVC_TYPE_PRIMARY , . uuid128 = BLE_UUID16 ( GATT_SVR_SVC_ALERT_UUID ), . characteristics = ( struct ble_gatt_chr_def []) { { . uuid128 = BLE_UUID16 ( GATT_SVR_CHR_SUP_NEW_ALERT_CAT_UUID ), . access_cb = gatt_svr_chr_access_alert , . flags = BLE_GATT_CHR_F_READ , }, { . uuid128 = BLE_UUID16 ( GATT_SVR_CHR_NEW_ALERT ), . access_cb = gatt_svr_chr_access_alert , . flags = BLE_GATT_CHR_F_NOTIFY , }, { . uuid128 = BLE_UUID16 ( GATT_SVR_CHR_SUP_UNR_ALERT_CAT_UUID ), . access_cb = gatt_svr_chr_access_alert , . flags = BLE_GATT_CHR_F_READ , }, { . uuid128 = BLE_UUID16 ( GATT_SVR_CHR_UNR_ALERT_STAT_UUID ), . access_cb = gatt_svr_chr_access_alert , . flags = BLE_GATT_CHR_F_NOTIFY , }, { . uuid128 = BLE_UUID16 ( GATT_SVR_CHR_ALERT_NOT_CTRL_PT ), . access_cb = gatt_svr_chr_access_alert , . flags = BLE_GATT_CHR_F_WRITE , }, { 0 , /* No more characteristics in this service. */ } }, }, { 0 , /* No more services. */ },","title":"Attribute Set"},{"location":"os/tutorials/bleprph/bleprph-svc-reg/#registration-function","text":"After you have created your service table, your app needs to register it with the NimBLE stack. This is done by calling the following function: int ble_gatts_register_svcs ( const struct ble_gatt_svc_def *svcs , ble_gatt_register_fn *cb , void *cb_arg ) The function parameters are documented below. Parameter Meaning Notes svcs The table of services to register. cb A callback that gets executed each time a service, characteristic, or descriptor is registered. Optional; pass NULL if you don't want to be notified. cb_arg An argument that gets passed to the callback function on each invocation. Optional; pass NULL if there is no callback or if you don't need a special argument. The ble_gatts_register_svcs() function returns 0 on success, or a BLE_HS_E[...] error code on failure. More detailed information about the registration callback function can be found in the BLE User Guide (TBD). The bleprph app registers its services as follows: rc = ble_gatts_register_svcs ( gatt_svr_svcs , gatt_svr_register_cb , NULL ); assert ( rc == 0 );","title":"Registration function"},{"location":"os/tutorials/bleprph/bleprph-svc-reg/#descriptors-and-included-services","text":"Your peripheral can also expose descriptors and included services. These are less common, so they are not covered in this tutorial. For more information, see the BLE User Guide .","title":"Descriptors and Included Services"},{"location":"os/tutorials/repo/add_repos/","text":"Adding Repositories to your Project What is a Repository A repository is a version-ed Mynewt project, which is a collection of Mynewt packages organized in a specific way for redistribution. What differentiates a repository from a Mynewt project is the presence of a repository.yml file describing the repository. This will be described below. For a basic understanding of repositories you may read the Newt Tool Manual and How to create repos . Note: For the remainder of this document we'll use the term repo as shorthand for a Mynewt repository. Repos are useful because they are an organized way for the community to share Mynewt packages and projects. In fact, the Mynewt-core is distributed as a repo. Why does Mynewt need additional repos? Repos add functionality not included in the Mynewt core. New repos might be created for several reasons. Expertise . Individuals or organizations may have expertise that they want to share in the form of repos. For example a chip vendor may create a repo to hold the Mynewt support for their chips. Non-Core component . Some components, although very useful to Mynewt users are not core to all Mynewt users. These are likely candidates to be held in different repos. Software licensing . Some software have licenses that make them incompatible with the ASF (Apache Software Foundation) license policies. These may be valuable components to some Mynewt users, but cannot be contained in the apache-Mynewt-core . What Repos are in my Project The list of repos used by your project are contained within the project.yml file. An example can be seen by creating a new project: $ mkdir ~/dev $ cd ~/dev $ newt new myproj $ cd myproj View the project.yml section and you will see a line describing the repos: project.repositories: - apache-Mynewt-core By default, this newly created project uses a single repo called apache-Mynewt-core . If you wish to add additional repos, you would add additional lines to the project.repositories variable like this. project.repositories: - apache-Mynewt-core - another_repo_named_x Repo Descriptors In addition to the repo name, the project.yml file must also contain a repo descriptor for each repository you include that gives newt information on obtaining the repo. In the same myproj above you will see the following repo descriptor. repository.apache-Mynewt-core: type: github vers: 0-latest user: apache repo: incubator-mynewt-core A repo descriptor starts with repository.<name>. . In this example, the descriptor specifies the information for the apache-Mynewt-core . The fields within the descriptor have the following definitions: type -- The type of code storage the repo uses. The current version of newt only supports github. Future versions may support generic git or other code storage mechanisms. vers -- The version of the repo to use for your project. A source code repository contains many versions of the source. This field is used to specify the one to use for this project. See the section on versions below for a detailed description of the format of this field. user -- The username for the repo. On github, this is the name after github.com in the repo path. Consider the repository https://github.com/apache/incubator-mynewt-core . It has username apache . repo -- The name of the repo. On github, this is the name after the username described above. Consider the repository https://github.com/apache/incubator-mynewt-core . It has username incubator-mynewt-core . This is a path to the source control and should not be confused with the name of the repo that you used in the repository.<name> declaration above. That name is contained elsewhere within the repo. See Below. Adding Existing Repos to my Project To add a new repo to your project, you have to complete two steps. Edit the project.yml file and add a new repo descriptor. The previous section includes information on the field required in your repo descriptor. Edit the project/yml file and add a new line to the project.repositories variable with the name of the repo you are adding. An example of a project.yml file with two repositories is shown below: project.name: \"my_project\" project.repositories: - apache-Mynewt-core - Mynewt_arduino_zero # Use github's distribution mechanism for core ASF libraries. # This provides mirroring automatically for us. # repository.apache-Mynewt-core: type: github vers: 0-latest user: apache repo: incubator-mynewt-core # a special repo to hold hardware specific stuff for arduino zero repository.Mynewt_arduino_zero: type: github vers: 0-latest user: runtimeinc repo: Mynewt_arduino_zero What Version of the Repo to use Mynewt repos are version-ed artifacts. They are stored in source control systems like github. The repo descriptor in your project.yml file must specify the version of the repo you will accept into your project. For now, we are at the beginnings of Mynewt. For testing and evaluation please use 0-latest in the vers field in your repo descriptor. vers:0-latest See Create a Repo for a description of the versioning system and all the possible ways to specify a version to use. Identifying a Repo A repo contains Mynewt packages organized in a specific way and stored in one of the supported code storage methods described above. In other words, it is a Mynewt project with an additional file repository.yml which describes the repo for use by newt (and humans browsing them). It contains a mapping of version numbers to the actual github branches containing the source code. Note that the repository.yml file lives only in the master branch of the git repository. Newt will always fetch this file from the master branch and then use that to determine the actual branch required depending on the version specified in your project.yml file. Special care should be taken to ensure that this file exists only in the master branch. Here is the repository.yml file from the apache-Mynewt-core: repo.name: apache-mynewt-core repo.versions: \"0.7.9\": \"Mynewt_0_8_0_b2_tag\" \"0-latest\": \"0.7.9\" \"0.8-latest\": \"0.7.9\" It contains the following: repo.name The external name that is used to include the library in your project.yml file. This is the name you in include in the project.repositories variable when adding this repository to your project. repo.versions A description of what versions to give the user depending on the settings in their project.yml file. Repo Version The repo version number resolves to an actual git branch depending on the mapping specified in repository.yml for that repo. The version field argument in your project.yml file supports multiple formats for flexibility: <major_num>.<minor_num>.<revision_num> or <major_num>.<minor_num>-<stability string> or <major_num>-<stability string> The stability string can be one of 3 pre-defined stability values. stable -- A stable release version of the repository dev -- A development version from the repository latest -- The latest from the repository In your project.yml file you can specify different combinations of the version number and stability value. For example: 0-latest -- The latest version with major number 0 1.2-stable -- The latest stable version with major and minor number 1.2 1.2-dev -- The development version from 1.2 1.1.1 -- a specific version 1.1.1 You cannot specify a stability string with a fully numbered version, e.g. 1.2.8-stable Repo Versions Available A repository.yml file contains information to match a version request into a git branch to fetch for your project. It's up to the repository maintainer to map these to branches of the repository. For example, let's say in a fictitious repository the following are defined. repo.versions: \"0.8.0\": \"xxx_branch_0_8_0\" \"1.0.0\": \"xxx_branch_1_0_0\" \"1.0.2\": \"xxx_branch_1_0_2\" \"1.1.1\": \"xxx_branch_1_1_0\" \"1.1.2\": \"xxx_branch_1_1_2\" \"1.2.0\": \"xxx_branch_1_2_0\" \"1.2.1\": \"xxx_branch_1_2_1\" \"1.2-dev\": \"1.2.1\" \"1-dev\": \"1.2-dev\" \"1.2-stable\": \"1.2.0\" \"0-latest\": \"0.8.0\" \"1-latest\": \"1-dev\" .... When the project.yml file asks for 1.2-stable it is resolved to version 1.2.0 (perhaps 1.2.1 is not stable yet), which in turn resolves to a specific branch xxx_branch_1_2_0 . This is the branch that newt fetches into your project. Note: Make sure a repo version exists in the repository.yml file of a repo you wish to add. Otherwise Newt will not be able to resolve the version and will fail to fetch the repo into your project. How to find out what Repos are available for Mynewt components Currently, there is no newt command to locate/search Mynewt package repositories. However, since the newt tool supports only github, searching github by keyword is a satisfactory option until a search tool is created. When searching github, recall that a Mynewt repository must have a repository.yml file in its root directory. If you don't see that file, it's not a Mynewt repository and can't be included in your project via the newt tool. Once you find a repository, the github URL and repository.yml file should give you all the information to add it to your project.yml file.","title":"toc"},{"location":"os/tutorials/repo/add_repos/#adding-repositories-to-your-project","text":"","title":"Adding Repositories to your Project"},{"location":"os/tutorials/repo/add_repos/#what-is-a-repository","text":"A repository is a version-ed Mynewt project, which is a collection of Mynewt packages organized in a specific way for redistribution. What differentiates a repository from a Mynewt project is the presence of a repository.yml file describing the repository. This will be described below. For a basic understanding of repositories you may read the Newt Tool Manual and How to create repos . Note: For the remainder of this document we'll use the term repo as shorthand for a Mynewt repository. Repos are useful because they are an organized way for the community to share Mynewt packages and projects. In fact, the Mynewt-core is distributed as a repo.","title":"What is a Repository"},{"location":"os/tutorials/repo/add_repos/#why-does-mynewt-need-additional-repos","text":"Repos add functionality not included in the Mynewt core. New repos might be created for several reasons. Expertise . Individuals or organizations may have expertise that they want to share in the form of repos. For example a chip vendor may create a repo to hold the Mynewt support for their chips. Non-Core component . Some components, although very useful to Mynewt users are not core to all Mynewt users. These are likely candidates to be held in different repos. Software licensing . Some software have licenses that make them incompatible with the ASF (Apache Software Foundation) license policies. These may be valuable components to some Mynewt users, but cannot be contained in the apache-Mynewt-core .","title":"Why does Mynewt need additional repos?"},{"location":"os/tutorials/repo/add_repos/#what-repos-are-in-my-project","text":"The list of repos used by your project are contained within the project.yml file. An example can be seen by creating a new project: $ mkdir ~/dev $ cd ~/dev $ newt new myproj $ cd myproj View the project.yml section and you will see a line describing the repos: project.repositories: - apache-Mynewt-core By default, this newly created project uses a single repo called apache-Mynewt-core . If you wish to add additional repos, you would add additional lines to the project.repositories variable like this. project.repositories: - apache-Mynewt-core - another_repo_named_x","title":"What Repos are in my Project"},{"location":"os/tutorials/repo/add_repos/#repo-descriptors","text":"In addition to the repo name, the project.yml file must also contain a repo descriptor for each repository you include that gives newt information on obtaining the repo. In the same myproj above you will see the following repo descriptor. repository.apache-Mynewt-core: type: github vers: 0-latest user: apache repo: incubator-mynewt-core A repo descriptor starts with repository.<name>. . In this example, the descriptor specifies the information for the apache-Mynewt-core . The fields within the descriptor have the following definitions: type -- The type of code storage the repo uses. The current version of newt only supports github. Future versions may support generic git or other code storage mechanisms. vers -- The version of the repo to use for your project. A source code repository contains many versions of the source. This field is used to specify the one to use for this project. See the section on versions below for a detailed description of the format of this field. user -- The username for the repo. On github, this is the name after github.com in the repo path. Consider the repository https://github.com/apache/incubator-mynewt-core . It has username apache . repo -- The name of the repo. On github, this is the name after the username described above. Consider the repository https://github.com/apache/incubator-mynewt-core . It has username incubator-mynewt-core . This is a path to the source control and should not be confused with the name of the repo that you used in the repository.<name> declaration above. That name is contained elsewhere within the repo. See Below.","title":"Repo Descriptors"},{"location":"os/tutorials/repo/add_repos/#adding-existing-repos-to-my-project","text":"To add a new repo to your project, you have to complete two steps. Edit the project.yml file and add a new repo descriptor. The previous section includes information on the field required in your repo descriptor. Edit the project/yml file and add a new line to the project.repositories variable with the name of the repo you are adding. An example of a project.yml file with two repositories is shown below: project.name: \"my_project\" project.repositories: - apache-Mynewt-core - Mynewt_arduino_zero # Use github's distribution mechanism for core ASF libraries. # This provides mirroring automatically for us. # repository.apache-Mynewt-core: type: github vers: 0-latest user: apache repo: incubator-mynewt-core # a special repo to hold hardware specific stuff for arduino zero repository.Mynewt_arduino_zero: type: github vers: 0-latest user: runtimeinc repo: Mynewt_arduino_zero","title":"Adding Existing Repos to my Project"},{"location":"os/tutorials/repo/add_repos/#what-version-of-the-repo-to-use","text":"Mynewt repos are version-ed artifacts. They are stored in source control systems like github. The repo descriptor in your project.yml file must specify the version of the repo you will accept into your project. For now, we are at the beginnings of Mynewt. For testing and evaluation please use 0-latest in the vers field in your repo descriptor. vers:0-latest See Create a Repo for a description of the versioning system and all the possible ways to specify a version to use.","title":"What Version of the Repo to use"},{"location":"os/tutorials/repo/add_repos/#identifying-a-repo","text":"A repo contains Mynewt packages organized in a specific way and stored in one of the supported code storage methods described above. In other words, it is a Mynewt project with an additional file repository.yml which describes the repo for use by newt (and humans browsing them). It contains a mapping of version numbers to the actual github branches containing the source code. Note that the repository.yml file lives only in the master branch of the git repository. Newt will always fetch this file from the master branch and then use that to determine the actual branch required depending on the version specified in your project.yml file. Special care should be taken to ensure that this file exists only in the master branch. Here is the repository.yml file from the apache-Mynewt-core: repo.name: apache-mynewt-core repo.versions: \"0.7.9\": \"Mynewt_0_8_0_b2_tag\" \"0-latest\": \"0.7.9\" \"0.8-latest\": \"0.7.9\" It contains the following: repo.name The external name that is used to include the library in your project.yml file. This is the name you in include in the project.repositories variable when adding this repository to your project. repo.versions A description of what versions to give the user depending on the settings in their project.yml file.","title":"Identifying a Repo"},{"location":"os/tutorials/repo/add_repos/#repo-version","text":"The repo version number resolves to an actual git branch depending on the mapping specified in repository.yml for that repo. The version field argument in your project.yml file supports multiple formats for flexibility: <major_num>.<minor_num>.<revision_num> or <major_num>.<minor_num>-<stability string> or <major_num>-<stability string> The stability string can be one of 3 pre-defined stability values. stable -- A stable release version of the repository dev -- A development version from the repository latest -- The latest from the repository In your project.yml file you can specify different combinations of the version number and stability value. For example: 0-latest -- The latest version with major number 0 1.2-stable -- The latest stable version with major and minor number 1.2 1.2-dev -- The development version from 1.2 1.1.1 -- a specific version 1.1.1 You cannot specify a stability string with a fully numbered version, e.g. 1.2.8-stable","title":"Repo Version"},{"location":"os/tutorials/repo/add_repos/#repo-versions-available","text":"A repository.yml file contains information to match a version request into a git branch to fetch for your project. It's up to the repository maintainer to map these to branches of the repository. For example, let's say in a fictitious repository the following are defined. repo.versions: \"0.8.0\": \"xxx_branch_0_8_0\" \"1.0.0\": \"xxx_branch_1_0_0\" \"1.0.2\": \"xxx_branch_1_0_2\" \"1.1.1\": \"xxx_branch_1_1_0\" \"1.1.2\": \"xxx_branch_1_1_2\" \"1.2.0\": \"xxx_branch_1_2_0\" \"1.2.1\": \"xxx_branch_1_2_1\" \"1.2-dev\": \"1.2.1\" \"1-dev\": \"1.2-dev\" \"1.2-stable\": \"1.2.0\" \"0-latest\": \"0.8.0\" \"1-latest\": \"1-dev\" .... When the project.yml file asks for 1.2-stable it is resolved to version 1.2.0 (perhaps 1.2.1 is not stable yet), which in turn resolves to a specific branch xxx_branch_1_2_0 . This is the branch that newt fetches into your project. Note: Make sure a repo version exists in the repository.yml file of a repo you wish to add. Otherwise Newt will not be able to resolve the version and will fail to fetch the repo into your project.","title":"Repo Versions Available"},{"location":"os/tutorials/repo/add_repos/#how-to-find-out-what-repos-are-available-for-mynewt-components","text":"Currently, there is no newt command to locate/search Mynewt package repositories. However, since the newt tool supports only github, searching github by keyword is a satisfactory option until a search tool is created. When searching github, recall that a Mynewt repository must have a repository.yml file in its root directory. If you don't see that file, it's not a Mynewt repository and can't be included in your project via the newt tool. Once you find a repository, the github URL and repository.yml file should give you all the information to add it to your project.yml file.","title":"How to find out what Repos are available for Mynewt components"},{"location":"os/tutorials/repo/create_repo/","text":"Create a Repo out of a Project In order to create a repository out of a project, all you need to do is create a repository.yml file, and check it into the master branch of your project. NOTE: Currently only github source control service is supported by our package management system, but support for plain git will be added soon. The repository.yml defines all versions of the repository and the corresponding source control tags that these versions correspond to. As an example, if the repository.yml file has the following content, it means there is one version of the apache-mynewt-core operating system available, which is 0.0.0 (implying we haven't released yet!). Such a version number corresponds to the \"develop\" branch in this repository. 0-latest would also resolved to this same 0.0.0 version. The next section explains the versioning system a bit more. $ more repository.yml repo.name: apache-mynewt-core repo.versions: \"0.0.0\": \"develop\" \"0-latest\": \"0.0.0\" Where should the repository.yml file be? The repository.yml file lives only in the master branch of the git repository. Newt will always fetch this file from the master branch and then use that to resolve the actual branch required depending on the version specified in the project. Special care should be taken to ensure that this file exists only in the master branch. Here is the repository.yml file from a certain snapshot of apache-Mynewt-core: repo.name: apache-mynewt-core repo.versions: \"0.7.9\": \"Mynewt_0_8_0_b2_tag\" \"0-latest\": \"0.7.9\" \"0.8-latest\": \"0.7.9\" It contains the following: repo.name The external name that is used to include the library in your project.yml file. This is the name you in include in the project.repositories variable when adding this repository to your project. repo.versions A description of what versions to give the user depending on the settings in their project.yml file. See below for a thorough description on versioning. Its a flexible mapping between version numbers and git branches. Repo Version Specification The version field argument for a repo has the following format: <major_num>.<minor_num>.<revision_num> or <major_num>.<minor_num>-<stability string> or <major_num>-<stability string> The stability string can be one of 3 pre-defined stability values. stable -- A stable release version of the repository dev -- A development version from the repository latest -- The latest from the repository In your project.yml file you can specify different combinations of the version number and stability value. For example: 0-latest -- The latest version with major number 0 1.2-stable -- The latest stable version with major and minor number 1.2 1.2-dev -- The development version from 1.2 1.1.1 -- a specific version 1.1.1 You cannot specify a stability string with a fully numbered version, e.g. 1.2.8-stable Repo Version Resolution A repository.yml file contains information to match this version request into a git branch to fetch for your project. It's up to you as the repository maintainer to map these to actual github branches of the repository. For example, let's say in a fictitious repository the following are defined. repo.versions: \"0.8.0\": \"xxx_branch_0_8_0\" \"1.0.0\": \"xxx_branch_1_0_0\" \"1.0.2\": \"xxx_branch_1_0_2\" \"1.1.1\": \"xxx_branch_1_1_0\" \"1.1.2\": \"xxx_branch_1_1_2\" \"1.2.0\": \"xxx_branch_1_2_0\" \"1.2.1\": \"xxx_branch_1_2_1\" \"1.2-dev\": \"1.2.1\" \"1-dev\": \"1.2-dev\" \"1.2-stable\": \"1.2.0\" \"0-latest\": \"0.8.0\" \"1-latest\": \"1-dev\" .... When the project.yml file asks for 1.2-stable it will be resolved to version 1.2.0 which in turn will resolve to a specific branch xxx_branch_1_2_0 . This is the branch that newt will fetch into the project with that project.yml file. Dependencies on other repos Repositories can also have dependencies on other repositories. These dependencies should be listed out on a per-tag basis. So, for example, if apache-mynewt-core were to depend on sterlys-little-repo, you might have the following directives in the repository.yml: develop.repositories: sterlys-little-repo: type: github vers: 0.8-latest user: sterlinghughes repo: sterlys-little-repo This would tell Newt that for anything that resolves to the develop branch, this repository requires the sterlys-little-repo repository. Dependencies are resolved circularly by the newt tool, and every dependent repository is placed as a sibling in the repos directory. Currently, if two repositories have the same name, they will conflict and bad things will happen. When a repository is installed to the repos/ directory, the current version of that repository is written to the \"project.state\" file. The project state file contains the currently installed version of any given repository. This way, the current set of repositories can be recreated from the project.state file reliably, whereas the project.yml file can have higher level directives (i.e. include 0.8-stable.) Resolving dependencies At the moment, all dependencies must match, otherwise newt will provide an error. As an example, if you have a set of dependencies such that: apache-mynewt-core depends on sterlys-little-repo 0.6-stable apache-mynewt-core depends on sterlys-big-repo 0.5.1 sterlys-big-repo-0.5.1 depends on sterlys-little-repo 0.6.2 where 0.6-stable is 0.6.3, the newt tool will try and resolve the dependency to sterlys-little-repo. It will notice that there are two conflicting versions of the same repository, and not perform installation. In the future Newt will be smarter about loading in all dependencies, and then looking to satisfy those dependencies to the best match of all potential options.","title":"Turn project into a repo"},{"location":"os/tutorials/repo/create_repo/#create-a-repo-out-of-a-project","text":"In order to create a repository out of a project, all you need to do is create a repository.yml file, and check it into the master branch of your project. NOTE: Currently only github source control service is supported by our package management system, but support for plain git will be added soon. The repository.yml defines all versions of the repository and the corresponding source control tags that these versions correspond to. As an example, if the repository.yml file has the following content, it means there is one version of the apache-mynewt-core operating system available, which is 0.0.0 (implying we haven't released yet!). Such a version number corresponds to the \"develop\" branch in this repository. 0-latest would also resolved to this same 0.0.0 version. The next section explains the versioning system a bit more. $ more repository.yml repo.name: apache-mynewt-core repo.versions: \"0.0.0\": \"develop\" \"0-latest\": \"0.0.0\"","title":"Create a Repo out of a Project"},{"location":"os/tutorials/repo/create_repo/#where-should-the-repositoryyml-file-be","text":"The repository.yml file lives only in the master branch of the git repository. Newt will always fetch this file from the master branch and then use that to resolve the actual branch required depending on the version specified in the project. Special care should be taken to ensure that this file exists only in the master branch. Here is the repository.yml file from a certain snapshot of apache-Mynewt-core: repo.name: apache-mynewt-core repo.versions: \"0.7.9\": \"Mynewt_0_8_0_b2_tag\" \"0-latest\": \"0.7.9\" \"0.8-latest\": \"0.7.9\" It contains the following: repo.name The external name that is used to include the library in your project.yml file. This is the name you in include in the project.repositories variable when adding this repository to your project. repo.versions A description of what versions to give the user depending on the settings in their project.yml file. See below for a thorough description on versioning. Its a flexible mapping between version numbers and git branches.","title":"Where should the repository.yml file be?"},{"location":"os/tutorials/repo/create_repo/#repo-version-specification","text":"The version field argument for a repo has the following format: <major_num>.<minor_num>.<revision_num> or <major_num>.<minor_num>-<stability string> or <major_num>-<stability string> The stability string can be one of 3 pre-defined stability values. stable -- A stable release version of the repository dev -- A development version from the repository latest -- The latest from the repository In your project.yml file you can specify different combinations of the version number and stability value. For example: 0-latest -- The latest version with major number 0 1.2-stable -- The latest stable version with major and minor number 1.2 1.2-dev -- The development version from 1.2 1.1.1 -- a specific version 1.1.1 You cannot specify a stability string with a fully numbered version, e.g. 1.2.8-stable","title":"Repo Version Specification"},{"location":"os/tutorials/repo/create_repo/#repo-version-resolution","text":"A repository.yml file contains information to match this version request into a git branch to fetch for your project. It's up to you as the repository maintainer to map these to actual github branches of the repository. For example, let's say in a fictitious repository the following are defined. repo.versions: \"0.8.0\": \"xxx_branch_0_8_0\" \"1.0.0\": \"xxx_branch_1_0_0\" \"1.0.2\": \"xxx_branch_1_0_2\" \"1.1.1\": \"xxx_branch_1_1_0\" \"1.1.2\": \"xxx_branch_1_1_2\" \"1.2.0\": \"xxx_branch_1_2_0\" \"1.2.1\": \"xxx_branch_1_2_1\" \"1.2-dev\": \"1.2.1\" \"1-dev\": \"1.2-dev\" \"1.2-stable\": \"1.2.0\" \"0-latest\": \"0.8.0\" \"1-latest\": \"1-dev\" .... When the project.yml file asks for 1.2-stable it will be resolved to version 1.2.0 which in turn will resolve to a specific branch xxx_branch_1_2_0 . This is the branch that newt will fetch into the project with that project.yml file.","title":"Repo Version Resolution"},{"location":"os/tutorials/repo/create_repo/#dependencies-on-other-repos","text":"Repositories can also have dependencies on other repositories. These dependencies should be listed out on a per-tag basis. So, for example, if apache-mynewt-core were to depend on sterlys-little-repo, you might have the following directives in the repository.yml: develop.repositories: sterlys-little-repo: type: github vers: 0.8-latest user: sterlinghughes repo: sterlys-little-repo This would tell Newt that for anything that resolves to the develop branch, this repository requires the sterlys-little-repo repository. Dependencies are resolved circularly by the newt tool, and every dependent repository is placed as a sibling in the repos directory. Currently, if two repositories have the same name, they will conflict and bad things will happen. When a repository is installed to the repos/ directory, the current version of that repository is written to the \"project.state\" file. The project state file contains the currently installed version of any given repository. This way, the current set of repositories can be recreated from the project.state file reliably, whereas the project.yml file can have higher level directives (i.e. include 0.8-stable.)","title":"Dependencies on other repos"},{"location":"os/tutorials/repo/create_repo/#resolving-dependencies","text":"At the moment, all dependencies must match, otherwise newt will provide an error. As an example, if you have a set of dependencies such that: apache-mynewt-core depends on sterlys-little-repo 0.6-stable apache-mynewt-core depends on sterlys-big-repo 0.5.1 sterlys-big-repo-0.5.1 depends on sterlys-little-repo 0.6.2 where 0.6-stable is 0.6.3, the newt tool will try and resolve the dependency to sterlys-little-repo. It will notice that there are two conflicting versions of the same repository, and not perform installation. In the future Newt will be smarter about loading in all dependencies, and then looking to satisfy those dependencies to the best match of all potential options.","title":"Resolving dependencies"},{"location":"os/tutorials/repo/upgrade_repo/","text":"Upgrade a repo In order to upgrade a previously installed repository, the \"newt upgrade\" command should be issued: $ newt upgrade Newt upgrade will look at the current desired version in project.yml , and compare it to the version in project.state . If these two differ, it will upgrade the dependency. Upgrade works not just for the dependency in project.yml , but for all the sub-dependencies that they might have.","title":"Upgrade a repo"},{"location":"os/tutorials/repo/upgrade_repo/#upgrade-a-repo","text":"In order to upgrade a previously installed repository, the \"newt upgrade\" command should be issued: $ newt upgrade Newt upgrade will look at the current desired version in project.yml , and compare it to the version in project.state . If these two differ, it will upgrade the dependency. Upgrade works not just for the dependency in project.yml , but for all the sub-dependencies that they might have.","title":"Upgrade a repo"}]}