User Manual. DA16200 Example Application Guide. UM-WI-007. ... 3. Select File > New Session for the test. User Manual. CFR0012. Figure 11: Start IO Ninja Utility.
User Manual DA16200 Example Application Guide UM-WI-007 Abstract The DA16200 is a highly integrated ultra-low power Wi-Fi system on a chip (SoC) and allows users to develop the Wi-Fi solution on a single chip. This document is an SDK guide document intended for developers who want to program using the DA16200 chipset. And describes the SDK API and peripheral device drivers and interfaces. UM-WI-007 DA16200 Example Application Guide Contents Abstract ................................................................................................................................................ 1 Contents ............................................................................................................................................... 2 Figures.................................................................................................................................................. 8 Terms and Definitions ....................................................................................................................... 10 References ......................................................................................................................................... 11 1 How to Start ................................................................................................................................ 12 1.1 The Sample Project............................................................................................................. 12 1.2 Build the Sample Project..................................................................................................... 12 1.2.1 IAR: Open and Build a Sample Workspace File.................................................. 12 1.3 Start Sample Application..................................................................................................... 14 1.3.1 How to Start Sample main() ................................................................................ 14 1.3.2 Pre-configure to Start Sample Code.................................................................... 17 2 Network Examples: Socket Communication ............................................................................ 19 2.1 Test Environment for Socket Examples.............................................................................. 19 2.1.1 DA16200 .............................................................................................................. 19 2.1.2 Test DUT ............................................................................................................. 20 2.1.2.1 Example of Test DUT (for Windows) ............................................... 20 2.2 TCP Client Sample.............................................................................................................. 22 2.2.1 How to Run .......................................................................................................... 22 2.2.2 How it Works........................................................................................................ 23 2.2.3 Details .................................................................................................................. 23 2.2.3.1 Registration...................................................................................... 23 2.2.3.2 Data Transmission........................................................................... 24 2.2.3.3 Disconnection .................................................................................. 25 2.3 TCP Client in DPM .............................................................................................................. 25 2.3.1 How to Run .......................................................................................................... 26 2.3.2 How it Works........................................................................................................ 26 2.3.3 Details .................................................................................................................. 26 2.3.3.1 Registration...................................................................................... 26 2.3.3.2 Data Transmission........................................................................... 27 2.4 TCP Server ......................................................................................................................... 28 2.4.1 How to Run .......................................................................................................... 28 2.4.2 How it Works........................................................................................................ 28 2.4.3 Details .................................................................................................................. 29 2.4.3.1 Connection....................................................................................... 29 2.4.3.2 Data Transmission........................................................................... 30 2.4.3.3 Disconnection .................................................................................. 31 2.4.3.4 To Stop Listening on a Server Port ................................................. 31 2.5 TCP Server in DPM............................................................................................................. 31 2.5.1 How to Run .......................................................................................................... 32 2.5.2 How it Works........................................................................................................ 32 2.5.3 Details .................................................................................................................. 32 2.5.3.1 Registration...................................................................................... 32 User Manual CFR0012 Revision 2.2 2 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 2.5.3.2 Data Transmission........................................................................... 33 2.6 TCP Client with KeepAlive .................................................................................................. 33 2.6.1 How to Run .......................................................................................................... 34 2.6.2 How it Works........................................................................................................ 34 2.6.3 Details .................................................................................................................. 34 2.6.3.1 Registration...................................................................................... 34 2.6.3.2 Data Transmission........................................................................... 35 2.6.3.3 Disconnection .................................................................................. 36 2.7 TCP Client with KeepAlive in DPM ..................................................................................... 37 2.7.1 How to Run .......................................................................................................... 37 2.7.2 Details .................................................................................................................. 37 2.7.2.1 Registration...................................................................................... 37 2.7.2.2 Data Transmission........................................................................... 38 2.7.3 How it Works........................................................................................................ 39 2.8 UDP Socket......................................................................................................................... 39 2.8.1 How to Run .......................................................................................................... 39 2.8.2 How it Works........................................................................................................ 40 2.8.3 Details .................................................................................................................. 40 2.8.3.1 Initialization ...................................................................................... 40 2.8.3.2 Data Transmission........................................................................... 41 2.9 UDP Server in DPM ............................................................................................................ 42 2.9.1 How to Run .......................................................................................................... 42 2.9.2 How it Works........................................................................................................ 42 2.9.3 Details .................................................................................................................. 43 2.9.3.1 Registration...................................................................................... 43 2.9.3.2 Data transmission ............................................................................ 43 2.10 UDP Client in DPM.............................................................................................................. 44 2.10.1 How to Run .......................................................................................................... 44 2.10.2 How it Works........................................................................................................ 44 2.10.3 Details .................................................................................................................. 45 2.10.3.1 Registration...................................................................................... 45 2.10.3.2 Data Transmission........................................................................... 46 3 Network Examples: Security ...................................................................................................... 47 3.1 Test DUT ............................................................................................................................. 47 3.1.1 Example of Test DUT (for MS Windows® OS).................................................... 47 3.1.1.1 TLS Server....................................................................................... 47 3.1.1.2 TLS Client ........................................................................................ 47 3.1.1.3 DTLS Server .................................................................................... 48 3.1.1.4 DTLS Client ..................................................................................... 48 3.2 TLS Server .......................................................................................................................... 48 3.2.1 How to Run .......................................................................................................... 49 3.2.2 How it Works........................................................................................................ 49 3.2.3 Details .................................................................................................................. 49 3.2.3.1 Initialization ...................................................................................... 49 3.2.3.2 TLS Handshake ............................................................................... 51 3.2.3.3 Data Transmission........................................................................... 51 3.3 TLS Server in DPM ............................................................................................................. 52 User Manual CFR0012 Revision 2.2 3 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 3.3.1 How to Run .......................................................................................................... 52 3.3.2 How it Works........................................................................................................ 53 3.3.3 Details .................................................................................................................. 53 3.3.3.1 Registration...................................................................................... 53 3.3.3.2 TLS Setup ........................................................................................ 54 3.3.3.3 Data Transmission........................................................................... 55 3.4 TLS Client ........................................................................................................................... 55 3.4.1 How to Run .......................................................................................................... 55 3.4.2 How it Works........................................................................................................ 56 3.4.3 Details .................................................................................................................. 56 3.4.3.1 Registration...................................................................................... 56 3.4.3.2 TLS Handshake ............................................................................... 57 3.4.3.3 Data Transmission........................................................................... 57 3.5 TLS Client in DPM............................................................................................................... 58 3.5.1 How to Run .......................................................................................................... 59 3.5.2 How it Works........................................................................................................ 59 3.5.3 Details .................................................................................................................. 59 3.5.3.1 Registration...................................................................................... 59 3.5.3.2 TLS Setup ........................................................................................ 61 3.5.3.3 Data Transmission........................................................................... 61 3.6 DTLS Server ....................................................................................................................... 62 3.6.1 How to Run .......................................................................................................... 62 3.6.2 How it Works........................................................................................................ 62 3.6.3 Details .................................................................................................................. 62 3.6.3.1 Initialization ...................................................................................... 62 3.6.3.2 DTLS Handshake ............................................................................ 64 3.6.3.3 Data Transmission........................................................................... 65 3.7 DTLS Server in DPM........................................................................................................... 66 3.7.1 How to Run .......................................................................................................... 67 3.7.2 How it Works........................................................................................................ 67 3.7.3 Details .................................................................................................................. 67 3.7.3.1 Registration...................................................................................... 67 3.7.3.2 DTLS Setup ..................................................................................... 68 3.7.3.3 Data Transmission........................................................................... 69 3.8 DTLS Client ......................................................................................................................... 70 3.8.1 How to Run .......................................................................................................... 70 3.8.2 How it Works........................................................................................................ 70 3.8.3 Details .................................................................................................................. 71 3.8.3.1 Initialization ...................................................................................... 71 3.8.3.2 DTLS Handshake ............................................................................ 72 3.8.3.3 Data Transmission........................................................................... 72 3.9 DTLS Client in DPM ............................................................................................................ 73 3.9.1 How to Run .......................................................................................................... 73 3.9.2 How it Works........................................................................................................ 74 3.9.3 Details .................................................................................................................. 74 3.9.3.1 Registration...................................................................................... 74 3.9.3.2 DTLS Setup ..................................................................................... 75 User Manual CFR0012 Revision 2.2 4 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 3.9.3.3 Data Transmission........................................................................... 76 4 Network Examples: Protocols / Applications........................................................................... 77 4.1 CoAP Client......................................................................................................................... 77 4.1.1 Test DUT ............................................................................................................. 77 4.1.2 How to Run .......................................................................................................... 77 4.1.3 CoAP Client Initialization ..................................................................................... 77 4.1.4 CoAP Client Deinitialization ................................................................................. 78 4.1.5 CoAP Client Request and Response .................................................................. 79 4.1.5.1 CoAP URI and Proxy-URI ............................................................... 79 4.1.5.2 GET Method .................................................................................... 79 4.1.5.3 POST Method .................................................................................. 80 4.1.5.4 PUT Method..................................................................................... 82 4.1.5.5 DELETE Method.............................................................................. 83 4.1.5.6 CoAP PING...................................................................................... 84 4.1.5.7 CoAP Response .............................................................................. 85 4.1.6 CoAP Observe ..................................................................................................... 86 4.1.6.1 Registration...................................................................................... 86 4.1.6.2 Deregistration .................................................................................. 88 4.2 DNS Query .......................................................................................................................... 88 4.2.1 How to Run .......................................................................................................... 88 4.2.2 Application Initialization ....................................................................................... 89 4.2.3 Get Single IPv4 Address...................................................................................... 89 4.2.4 Get Multiple IPv4 Addresses ............................................................................... 90 4.3 SNTP and Get Current Time............................................................................................... 90 4.3.1 How to Run .......................................................................................................... 91 4.3.2 Operation ............................................................................................................. 91 4.4 SNTP and Get Current Time in DPM Function ................................................................... 93 4.4.1 How to Run .......................................................................................................... 93 4.4.2 Operation ............................................................................................................. 94 4.5 HTTP Client......................................................................................................................... 96 4.5.1 How to Run .......................................................................................................... 96 4.5.2 Operation ............................................................................................................. 96 4.6 HTTP Client in DPM Function ............................................................................................. 99 4.6.1 How to Run .......................................................................................................... 99 4.6.2 Operation ............................................................................................................. 99 4.7 HTTP Server ..................................................................................................................... 101 4.7.1 How to Run ........................................................................................................ 102 4.7.2 Operation ........................................................................................................... 102 4.8 OTA FW update ................................................................................................................ 105 4.8.1 How to Run ........................................................................................................ 106 4.8.2 Operation ........................................................................................................... 106 4.8.2.1 DA16200 Firmware Update ........................................................... 106 4.8.2.2 Certificates Update ........................................................................ 107 4.8.2.3 MCU Firmware Update .................................................................. 107 5 Additional Examples ................................................................................................................. 108 5.1 ThreadX API Sample ........................................................................................................ 108 5.1.1 How to Run ........................................................................................................ 108 User Manual CFR0012 Revision 2.2 5 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 5.1.2 Sample Overview............................................................................................... 108 5.1.3 Thread Creation and Resource Initialization ..................................................... 108 5.1.4 Initial Execution.................................................................................................. 109 5.1.5 Threads Operation in Detail............................................................................... 111 5.2 RTC Timer with DPM Function ......................................................................................... 116 5.2.1 How to Run ........................................................................................................ 116 5.2.2 Application Initialization ..................................................................................... 116 5.2.3 Timer Creation: DPM Sleep mode 1.................................................................. 117 5.2.4 Timer Creation: DPM Sleep mode 2.................................................................. 117 5.2.5 Timer Creation: DPM Sleep mode 3.................................................................. 118 5.2.6 Timer Creation: DPM Sleep mode 3.................................................................. 119 5.3 Get SCAN Result Sample ................................................................................................. 119 5.3.1 How to Run ........................................................................................................ 119 5.3.2 Sample Overview............................................................................................... 120 5.3.3 Application Initialization ..................................................................................... 120 5.3.4 Get SCAN Result ............................................................................................... 120 5.4 SoftAP Provisioning Sample ............................................................................................. 121 5.4.1 How to Run ........................................................................................................ 121 5.4.2 Application Initialize ........................................................................................... 121 5.4.3 Data Communication with the Mobile App......................................................... 122 5.4.4 SoftAP Provisioning Scenario............................................................................ 124 6 Crypto Examples ....................................................................................................................... 126 6.1 Crypto Algorithms AES .................................................................................................. 126 6.1.1 How to Run ........................................................................................................ 126 6.1.2 Application Initialization ..................................................................................... 127 6.1.3 Crypto Algorithm for AES-CBC-128, 192, and 256 ........................................... 127 6.1.4 Crypto Algorithm for AES-CFB128-128, 192, and 256...................................... 128 6.1.5 Crypto Algorithm for AES-ECB-128, 192, and 256 ........................................... 129 6.1.6 Crypto Algorithm for AES-CTR-128................................................................... 130 6.1.7 Crypto Algorithm for AES-CCM-128, 192, and 256........................................... 130 6.1.8 Crypto Algorithm for AES-GCM-128, 192, and 256 .......................................... 131 6.1.9 Crypto Algorithm for AES-OFB-128, 192, and 256 ........................................... 132 6.2 Crypto Algorithms DES .................................................................................................. 133 6.2.1 How to Run ........................................................................................................ 133 6.2.2 Application Initialization ..................................................................................... 133 6.2.3 Crypto Algorithm for DES-CBC-56, DES3-CBC-112, and 168.......................... 134 6.3 Crypto Algorithms HASH & HMAC ................................................................................ 135 6.3.1 How to Run ........................................................................................................ 135 6.3.2 Application Initialization ..................................................................................... 136 6.3.3 Crypto Algorithm for SHA-1 Hash...................................................................... 137 6.3.4 Crypto Algorithm for SHA-224 Hash.................................................................. 138 6.3.5 Crypto Algorithm for SHA-256 Hash.................................................................. 139 6.3.6 Crypto Algorithm for SHA-384 Hash.................................................................. 140 6.3.7 Crypto Algorithm for SHA-512 Hash.................................................................. 141 6.3.8 Crypto Algorithm for MD5 Hash......................................................................... 141 6.3.9 Crypto Algorithm for Hash and HMAC with the Generic Message-Digest Wrapper ............................................................................................................. 142 User Manual CFR0012 Revision 2.2 6 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 6.4 Crypto Algorithms DRBG ............................................................................................... 149 6.4.1 How to Run ........................................................................................................ 149 6.4.2 Application Initialization ..................................................................................... 150 6.4.3 CTR_DRBG with Prediction Resistance............................................................ 150 6.4.4 CTR_DRBG without Prediction Resistance....................................................... 151 6.4.5 HMAC_DRBG with Prediction Resistance ........................................................ 152 6.4.6 HMAC_DRBG Without Prediction Resistance................................................... 154 6.5 Crypto Algorithms ECDSA ............................................................................................. 154 6.5.1 How to Run ........................................................................................................ 154 6.5.2 Application Initialization ..................................................................................... 154 6.5.3 Generates ECDSA Key Pair and Verifies ECDSA Signature............................ 155 6.6 Crypto Algorithms Diffie-Hellman Key Exchange .......................................................... 158 6.6.1 How to Run ........................................................................................................ 158 6.6.2 Application Initialization ..................................................................................... 158 6.6.3 Load Diffie-Hellman Parameters ....................................................................... 158 6.6.4 How Diffie-Hellman Works................................................................................. 159 6.7 Crypto Algorithms RSA PKCS#1 ................................................................................... 163 6.7.1 How to Run ........................................................................................................ 163 6.7.2 Application Initialization ..................................................................................... 163 6.7.3 How RSA PKCS#1 Works ................................................................................. 163 6.8 Crypto Algorithms ECDH ............................................................................................... 167 6.8.1 How to Run ........................................................................................................ 167 6.8.2 Application Initialization ..................................................................................... 168 6.8.3 How ECDH Key Exchange Works..................................................................... 168 6.9 Crypto Algorithms KDF .................................................................................................. 172 6.9.1 How to Run ........................................................................................................ 172 6.9.2 Application Initialization ..................................................................................... 172 6.9.3 How KDF Works ................................................................................................ 173 6.10 Crypto Algorithms Public Key Abstraction Layer ........................................................... 174 6.10.1 How to Run ........................................................................................................ 174 6.10.2 User Thread ....................................................................................................... 174 6.10.3 Application Initialization ..................................................................................... 175 6.10.4 How Public Key Abstraction Layer is Used ....................................................... 176 6.11 Crypto Algorithms Generic Cipher Wrapper .................................................................. 186 6.11.1 How to Run ........................................................................................................ 186 6.11.2 Application Initialization ..................................................................................... 186 6.11.3 How Generic Cipher Wrapper is Used .............................................................. 186 7 Peripheral Examples ................................................................................................................. 194 7.1 UART................................................................................................................................. 194 7.1.1 How to Run ........................................................................................................ 194 7.1.2 Application Initialization ..................................................................................... 194 7.1.3 Data Read / Write .............................................................................................. 195 7.2 GPIO ................................................................................................................................. 197 7.2.1 How to Run ........................................................................................................ 197 7.2.2 Operation ........................................................................................................... 197 7.3 GPIO Retention ................................................................................................................. 198 7.3.1 How to Run ........................................................................................................ 198 User Manual CFR0012 Revision 2.2 7 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 7.3.2 Operation ........................................................................................................... 198 7.4 I2C ..................................................................................................................................... 199 7.4.1 How to Run ........................................................................................................ 199 7.4.2 Operation ........................................................................................................... 199 7.5 I2S ..................................................................................................................................... 200 7.5.1 How to Run ........................................................................................................ 200 7.5.2 User Thread ....................................................................................................... 201 7.5.3 Operation ........................................................................................................... 201 7.6 PWM.................................................................................................................................. 201 7.6.1 How to Run ........................................................................................................ 201 7.6.2 Operation ........................................................................................................... 202 7.7 ADC ................................................................................................................................... 203 7.7.1 How to Run ........................................................................................................ 203 7.7.2 Operation ........................................................................................................... 203 7.8 SPI..................................................................................................................................... 205 7.8.1 How to Run ........................................................................................................ 205 7.8.2 Operation ........................................................................................................... 205 7.9 SDIO.................................................................................................................................. 206 7.9.1 How to Run ........................................................................................................ 206 7.9.2 Operation ........................................................................................................... 207 7.10 SD/eMMC.......................................................................................................................... 207 7.10.1 How to Run ........................................................................................................ 207 7.10.2 Operation ........................................................................................................... 208 7.11 User SFLASH Read / Write Example ............................................................................... 209 7.11.1 User Thread ....................................................................................................... 209 7.11.2 Application Initialization ..................................................................................... 209 7.11.3 Sflash Read and Write....................................................................................... 210 Appendix A....................................................................................................................................... 212 Revision History .............................................................................................................................. 213 Figures Figure 1: Overall Test Setup................................................................................................................ 12 Figure 2: Start IAR Workbench............................................................................................................ 12 Figure 3: Open the DA16200 Sample Workspace .............................................................................. 13 Figure 4: Rebuild or Make to Compile ................................................................................................. 13 Figure 5: Compiler Feature for Sample Project................................................................................... 14 Figure 6: The Flow of the Sample Code.............................................................................................. 14 Figure 7: Startup Files on IAR Project ................................................................................................. 15 Figure 8: sample_apps File on IAR Project......................................................................................... 16 Figure 9: Overall Test Setup................................................................................................................ 19 Figure 10: DA16200 EVB AP Connection Done .............................................................................. 19 Figure 11: Start IO Ninja Utility ............................................................................................................ 20 Figure 12: Select TCP Server Session................................................................................................ 21 Figure 13: TCP Server Session Windows ........................................................................................... 21 Figure 14: Start TCP Server Session .................................................................................................. 21 Figure 15: TCP Connection with TCP Client ....................................................................................... 22 Figure 16: TCP Data Communication with TCP Client ....................................................................... 22 Figure 17: Workflow of TCP Client ...................................................................................................... 23 Figure 18: Workflow of TCP Client in DPM ......................................................................................... 26 User Manual CFR0012 Revision 2.2 8 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide Figure 19: Workflow of TCP Server..................................................................................................... 29 Figure 20: Workflow of TCP Server in DPM........................................................................................ 32 Figure 21: Workflow of TCP Client with KeepAlive ............................................................................. 34 Figure 22: Workflow of TCP Client with KeepAlive in DPM ................................................................ 39 Figure 23: Workflow of UDP Socket.................................................................................................... 40 Figure 24: Workflow of UDP Server in DPM ....................................................................................... 42 Figure 25: Workflow of UDP Client in DPM......................................................................................... 44 Figure 26: Start of TLS Server Application .......................................................................................... 47 Figure 27: Start of TLS Client Application ........................................................................................... 47 Figure 28: Timeout of TLS Client Application...................................................................................... 48 Figure 29: Start of DTLS Server Application ....................................................................................... 48 Figure 30: Start of DTLS Client Application......................................................................................... 48 Figure 31: Workflow of TLS Server ..................................................................................................... 49 Figure 32: Workflow of TLS Server in DPM ........................................................................................ 53 Figure 33: Workflow of TLS Client....................................................................................................... 56 Figure 34: Workflow of TLS Client in DPM.......................................................................................... 59 Figure 35: Workflow of DTLS Server................................................................................................... 62 Figure 36: Workflow of DTLS Server in DPM...................................................................................... 67 Figure 37: Workflow of DTLS Client .................................................................................................... 70 Figure 38: Workflow of DTLS Client in DPM ....................................................................................... 74 Figure 39: Start of CoAP Server Application ....................................................................................... 77 Figure 40: GET Method of CoAP Client #1 ......................................................................................... 80 Figure 41: GET Method of CoAP Client #2 ......................................................................................... 80 Figure 42: GET Method of CoAP Client #3 ......................................................................................... 80 Figure 43: POST Method of CoAP Client #1 ....................................................................................... 81 Figure 44: POST Method of CoAP Client #2 ....................................................................................... 82 Figure 45: POST Method of CoAP Client #3 ....................................................................................... 82 Figure 46: PUT Method of CoAP Client #1 ......................................................................................... 83 Figure 47: PUT Method of CoAP Client #2 ......................................................................................... 83 Figure 48: PUT Method of CoAP Client #3 ......................................................................................... 83 Figure 49: DELETE Method of CoAP Client #1................................................................................... 84 Figure 50: DELETE Method of CoAP Client #2................................................................................... 84 Figure 51: DELETE Method of CoAP Client #3................................................................................... 84 Figure 52: PING Method of CoAP Client #1 ........................................................................................ 85 Figure 53: PING Method of CoAP Client #2........................................................................................ 85 Figure 54: CoAP Observe of CoAP Client #1...................................................................................... 87 Figure 55: CoAP Observe of CoAP Client #2...................................................................................... 88 Figure 56: CoAP Observe of CoAP Client #3...................................................................................... 88 Figure 57: The Result of the DA16200 HTTP Server........................................................................ 104 Figure 58: The DA16200 HTTP Server Test with POSTMAN Tool................................................... 105 Figure 59: ThreadX APIs Test ........................................................................................................... 108 Figure 60: get_scan_result Sample Test........................................................................................... 120 Figure 61: SPI Loopback Communication......................................................................................... 205 Figure 62: SDIO and SD/eMMC Connector ...................................................................................... 208 Figure 63: sflash Example Sample Test............................................................................................ 209 User Manual CFR0012 Revision 2.2 9 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide Terms and Definitions AP UART ADC AES API AT CCM CTR DAC DER DES DHCP DNS DPM DRBG DUT ECDH ECDSA EVB EVK GCM GPIO HMAC HTTP HTML I2C I2S KDF MD5 MCU NVRAM OFB PEM POR PWM RSA PKCS RTC RTM RTOS SD/eMMC SDIO SNTP SPI SRAM STA TCP Access Point Universal Asynchronous Receiver-Transmitter Analog-to-Digital Converter Advanced Encryption Standard Application Programming Interface Attention Counter with CBC-MAC Counter Digital-To-Analog Converter Distinguished Encoding Rules Data Encryption Standard Dynamic Host Configuration Protocol Domain Name Server Dynamic Power Management Deterministic Random Bit Generator Device Under Test Elliptic Curve Diffie-Hellman Elliptic Curve Digital Signature Algorithm Evaluation Board Evaluation Kit Galois/Counter Mode General-Purpose Input/Output Hash(-based) Message Authentication Code Hypertext Transfer Protocol Hypertext Markup Language Inter-Integrated Circuit Inter-IC Sound Key Derivation Function Message Digest 5 Microcontroller Unit Non-volatile random-access memory Output Feedback Privacy-Enhanced Mail Power-On Reset Pulse Width Modulation RSA Public Key Cryptography Standards Real-Time Clock Retention Memory Real-Time Operating System Secure Digital/Embedded Multimedia Card Secure Digital Input Output Simple Network Time Protocol Serial Peripheral Interface Static Random-Access Memory Station Transmission Control Protocol User Manual CFR0012 Revision 2.2 10 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide TLS UDP Transport Layer Security User Datagram Protocol References [1] NetX, The high-performance real-time implementation of TCP/IP standards User Guide, NetX_User_Guide, Express Logic, version5. [2] UM-WI-023, DA16200 Evaluation Kit, EVK_User_Manual, Revision 2v0, Dialog Semiconductor. [3] NetX, The high-performance embedded kernel User Guide, ThreadX_User_Guide_V5, Express Logic, version5.0. [4] NetX Duo, Hypertext Transfer Protocol (NetX Duo HTTP) User Guide, nxd_http, Express Logic. User Manual CFR0012 Revision 2.2 11 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 1 How to Start This document describes how to start one of the samples that are included in the DA16200 SDK. The customer/developer can simply check the defined operation with these sample codes before the start of the development/implementation of the customer application in the DA16200 SDK. 1.1 The Sample Project The DA16200 Sample Projects are categorized into five functional categories: Crypto, DPM, Network, Peripheral, and ETC (another sample code). The samples are available in the SDK. See Figure 1. The customer/developer can check how the sample operates by selecting the sample folder. Figure 1: Overall Test Setup 1.2 Build the Sample Project To check the operation status of the DA16200 with the sample code, do the steps in the order described below. 1.2.1 IAR: Open and Build a Sample Workspace File 1. Open the DA16xxx.eww (Figure 2), right-click on the project name (main) in the IAR Embedded Workbench workspace. User Manual CFR0012 Figure 2: Start IAR Workbench Revision 2.2 12 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide Figure 3: Open the DA16200 Sample Workspace 2. Run the command Make or Rebuild All in the IAR workbench compiler. If compilation is done for the first time, then first run command Clean, and then run command Make. See Figure 4. Figure 4: Rebuild or Make to Compile 3. The sample function source file is available in the "src" folder of each sample code. There are three files in the "src" folder. main.c: Include main() function to start applications of the DA16200 NOTE The customer/developer can change the HW PinMux configuration in this file: int config_pin_mux(void) sample_apps.c: Sample application register table XXX_sample.c: Sample application function User Manual CFR0012 Revision 2.2 13 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 1.3 Start Sample Application All Sample Applications in the DA16200 SDK need to adopt the compile feature for the sample project. All the Sample Applications depend on the __ENABLE_SAMPLE_APP__ compile feature To avoid customer/developer's confusion about the sample code, __ENABLE_SAMPLE_APP__ is defined in the sample IAR project predefined feature. See Figure 5. Customer/Developer does not need to add an additional compiler feature anymore for the sample Figure 5: Compiler Feature for Sample Project 1.3.1 How to Start Sample main() In order to analyze the flow of sample code, the customer/developer can start from the main () function. See Figure 6. User Manual CFR0012 Figure 6: The Flow of the Sample Code Revision 2.2 14 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide After the DA16200 is booted, the system library invokes function main(). The following steps are run: Initialize HW resources (PIN_MUX, RTC, Console, ... ) Start function system_start() to run the DA16200 as a Wi-Fi IoT device NOTE This system_start() function is provided in the DA16200 SDK source package, not in the sample folder. Customer/developer can check the code flow in main.c and system_start.c. See Figure 7. Figure 7: Startup Files on IAR Project [ ~/SDK/sample/Sample_Category/Sample_XXX/src/main.c ] int main(char init_state) { ... ... /* Entry point for customer main */ if (init_state == TRUE) { status = system_start(); } ... ... } After the basic HW resources are initialized, function system_start() is called to run the Wi-Fi operation. The following happens: Configure H/W and S/W feature Configure system resources for system clock and TX power Initialize Wi-Fi function in wlaninit() Start system provided applications in start_sys_apps() [ ~/customer/main/src/system_start.c ] int system_start(void) { ... ... /* Initialize WLAN interface */ wlaninit(); User Manual CFR0012 Revision 2.2 15 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide ... ... /* Start system applications for DA16XXX */ start_sys_apps(); ... ... } To start the sample application, the customer/developer should register function sample_app_start_cb, which is the Sample thread creation function to operate the sample application. The customer/developer can check the code flow in sample_apps.c. See Figure 8. Figure 8: sample_apps File on IAR Project If function sample_app_start_cb exists in the DA16200 SDK, then the corresponding sample function in sample_apps_table is automatically executed. Register sample_app_start_cb in case of Sample project Create system and user applications that do non-network related operations Check network status [ ~/src/sys_apps/src/sys_apps.c ] void start_sys_apps(void) { /* Start user application functions */ run_sys_apps(); } static void run_sys_apps(void) { ... ... #if defined (__ENABLE_SAMPLE_APP__) /* For sample codes ... */ register_sample_cb(); #endif // __ENABLE_SAMPLE_APP__ ... ... /* Create network apps */ create_sys_apps(sysmode, TRUE); } Create system applications that do network-related operations Run a Sample Application that is defined in the sample feature User Manual CFR0012 Revision 2.2 16 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide [ ~/SDK/sample/Sample_Category/Sample_XXX/src/sample_apps.c ] void regist_sample_cb(void) { sample_app_start_cb = create_sample_apps; sample_app_dpm_reg_cb = dpm_reg_sample_app; // For DPM operation sample_app_dpm_unreg_cb = dpm_unreg_sample_app;// For DPM operation } static void create_sys_apps(int sysmode, UCHAR net_chk_flag) { ... ... /* Create test samples apps */ if (sample_app_start_cb != NULL) { sample_app_start_cb(net_chk_flag); } } void create_sample_apps(UCHAR net_chk_flag) { ... ... mode = get_run_mode(); for (i = 0 ; sample_apps_table[i].name != NULL ; i++) { /* Run matched apps with net_chk_flag */ if (sample_apps_table[i].net_chk_flag == net_chk_flag) { cur_tx = create_new_app(cur_tx, &(sample_apps_table[i]), mode); } } } All the sample applications are registered in the management table as shown below: [ ~/SDK/sample/Sample_Category/Sample_XXX/src/sample_apps.c ] For example, TCP Client Sample: static const app_thread_info_t sample_apps_table[] = { /******* Start regist thread *************************************/ ////// For testing sample code ... //////////////////////////////// { SAMPLE_TCP_CLI, tcp_client_sample, 1024, USER_PRI_APP(0), TRUE, FALSE, TCPC_PORT, RUN_ALL_MODE }, /******* End of List *********************************************/ { NULL, NULL, 0, 0, FALSE, FALSE, UNDEF_PORT, 0 } }; 1.3.2 Pre-configure to Start Sample Code In the DA16200 sample code, Customer/Developer can configure with a specified Customer's/Developer's test environment or other pre-defined configuration values for test sample. User Manual CFR0012 Revision 2.2 17 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide To do pre-configuration the sampel code, the DA16200 SDK sample code provides pre-configuration evnironment as source code. If no add pre-configure code in this file, each sample code starts with already saved Wi-Fi profile and other saved NVRAM environment varibles. [ ~/SDK/sample/common_config/sample_preconfig.c ] /* Sample for Customer's Wi-Fi configuration */ #define SAMPLE_AP_SSID "TEST_AP_SSID" #define SAMPLE_AP_PSK "12345678" // CC_VAL_AUTH_OPEN, CC_VAL_AUTH_WEP, CC_VAL_AUTH_WPA, CC_VAL_AUTH_WPA2, CC_VAL_AUTH_WPA_AUTO #define SAMPLE_AP_AUTH_TYPE CC_VAL_AUTH_WPA_AUTO /* Required when WEP security mode */ #define SAMPLE_AP_WEP_INDEX 0 // CC_VAL_ENC_TKIP, CC_VAL_ENC_CCMP, CC_VAL_ENC_AUTO #define SAMPLE_AP_ENCRPT_INDEX CC_VAL_ENC_AUTO void sample_preconfig(void) { // // Need to change as Customer's profile information // #if 0 // Customer's code to config Wi-Fi profile for sample code char reply[32]; // Delete existed Wi-Fi profile da16x_cli_reply("remove_network 0", NULL, reply); // Set new Wi-Fi profile for sample test da16x_set_nvcache_int(DA16X_CONF_INT_MODE, 0); da16x_set_nvcache_str(DA16X_CONF_STR_SSID_0, SAMPLE_AP_SSID); da16x_set_nvcache_int(DA16X_CONF_INT_AUTH_MODE_0, SAMPLE_AP_AUTH_TYPE); if (SAMPLE_AP_AUTH_TYPE == CC_VAL_AUTH_WEP) { da16x_set_nvcache_str(DA16X_CONF_STR_WEP_KEY0 + SAMPLE_AP_WEP_INDEX, SAMPLE_AP_PSK); da16x_set_nvcache_int(DA16X_CONF_INT_WEP_KEY_INDEX, SAMPLE_AP_WEP_INDEX); } else if (SAMPLE_AP_AUTH_TYPE > CC_VAL_AUTH_WEP) { da16x_set_nvcache_str(DA16X_CONF_STR_PSK_0, SAMPLE_AP_PSK); da16x_set_nvcache_int(DA16X_CONF_INT_ENCRYPTION_0, SAMPLE_AP_ENCRPT_INDEX); } // Save new Wi-Fi profile to NVRAM area da16x_nvcache2flash(); tx_thread_sleep(10); // Enable new sample Wi-Fi profile da16x_cli_reply("select_network 0", NULL, reply); #endif // 0 } User Manual CFR0012 Revision 2.2 18 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 2 Network Examples: Socket Communication This section describes how to develop TCP or UDP socket applications with NetX Duo APIs on the DA16200 SDK. As a companion document, see the NetX_Duo_User_Guide.pdf [1] for any nx_xx() functions. To easily understand the DPM API and to help implement a DPM function, we provide each example as a non-DPM function version and a DPM function version. To try the examples, please set up a test environment first as shown in Figure 9. 2.1 Test Environment for Socket Examples Figure 9: Overall Test Setup 2.1.1 DA16200 The example source files are included in the DA16200 SDK. All examples introduced in this section do not have code for Wi-Fi station interface setup. For that, see section "Wi-Fi Mode Setup" in the DA16200 EVK User Guide [2] and set up STA mode with the console command. Also, make a note of the IP address of the DA16200 EVB to use for the examples. The IP address is printed after connecting to an AP and then TCP/UDP example application will run. See Figure 10. Figure 10: DA16200 EVB AP Connection Done User Manual CFR0012 Revision 2.2 19 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 2.1.2 Test DUT A peer Test DUT that runs a TCP/UDP counterpart application. This Test DUT is connected to an AP, either through a wired (LAN or WAN) or a wireless connection. NOTE The customer/developer needs to install a proper application (for example, Packet Sender, Hercules, IO Ninja, and so on) when a Windows OS system is used. For a Linux system, proper test utilities are needed, or a test sample application is needed. 2.1.2.1 Example of Test DUT (for Windows) This section describes how to run the Test DUT on an MS Windows® operating system. 1. Make sure that the IO Ninja utility is installed on the test PC. NOTE Customer/Developer can download the MS Windows version of the IO Ninja utility from http://ioninja.com. 2. Start the IO Ninja utility on the test PC. 3. Select File > New Session for the test. User Manual CFR0012 Figure 11: Start IO Ninja Utility Revision 2.2 20 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 4. To test the TCP Client, start the TCP Server. Figure 12: Select TCP Server Session 5. If TCP Listener Socket is selected, IO Ninja utility shows the TCP server test window. In the case of TCP client test, select TCP Connection Socket. Figure 13: TCP Server Session Windows 6. Start the TCP Server session (for example, in the case of a TCP Client test). User Manual CFR0012 Figure 14: Start TCP Server Session Revision 2.2 21 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 7. Connect to the TCP Client (with the DA16200 TCP Client Sample). Figure 15: TCP Connection with TCP Client 8. Run data communication (with the DA16200 TCP Client Sample). Figure 16: TCP Data Communication with TCP Client 2.2 TCP Client Sample The TCP client sample is an example of the simplest TCP echo client application. The Transmission Control Protocol is one of the main protocols of the Internet protocol suite. TCP provides a reliable, ordered, and error-checked delivery of a stream of octets (bytes) between applications that run on hosts that communicate via an IP network. The DA16200 SDK provides a NetX Duo's TCP protocol. NetX Duo is a high-performance real-time implementation of the TCP/IP standards designed exclusively for embedded ThreadX-based applications. This section describes how the TCP client sample application is built and works. 2.2.1 How to Run 1. Run a socket application on the peer PC (see Section 2.1.2) and open a TCP server socket with port number 10192 (default TCP Client test port). 2. In the IAR workbench, open the workspace for the TCP Client sample application as follows: User Manual CFR0012 Revision 2.2 22 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide ~/SDK/sample/Network/TCP_Client/build/DA16xxx.eww 3. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB, and reboot. 4. Use the console command to set up the Wi-Fi station interface. 5. There are two ways to set the IP address and port for the Test DUT in the TCP Client Sample. a. Edit the source code: ~/SDK/sample/Network/TCP_Client/src/tcp_client_sample.c #define TCP_CLIENT_SAMPLE_DEF_SERVER_IP #define TCP_CLIENT_SAMPLE_DEF_SERVER_PORT "192.168.0.11" TCP_CLI_TEST_PORT b. Use the DA16200 console to save the values in NVRAM: [/DA16200] # nvram.setenv TCPC_SERVER_IP 192.168.0.11 [/DA16200] # nvram.setenv TCPC_SERVER_PORT 10192 [/DA16200] # reboot 6. The example application will connect to the Test DUT after a connection is made to the Wi-Fi AP. 2.2.2 How it Works The DA16200 TCP Client sample application is a simple echo message. When the TCP server sends a message, then the DA16200 TCP client will echo that message to the TCP server. Figure 17: Workflow of TCP Client 2.2.3 Details The DA16200 SDK provides the NetX Duo's TCP protocol. This sample application describes how a TCP socket is created, deleted, and configured. 2.2.3.1 Registration The client side of the TCP connection initiates a connection request to a TCP server. Before a connection request can be made, TCP must be enabled on the client IP instance with function get_thread_netx(). In addition, the client TCP socket must be created next with the nx_tcp_socket_create() service and bound to a port via the nx_tcp_client_socket_bind() service. After the client socket is bound, the nx_tcp_client_socket_connect() service is used to establish a connection with a TCP server. void tcp_client_sample_run() { NX_IP *ip_ptr = NULL; NX_PACKET_POOL *pool_ptr = NULL; NX_TCP_SOCKET *sock_ptr = NULL; // Get informations of current ip interface and packet pool get_thread_netx((void **)&pool_ptr, (void **)&ip_ptr, WLAN0_IFACE); User Manual CFR0012 Revision 2.2 23 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide // Create TCP socket status = nx_tcp_socket_create(ip_ptr, sock_ptr, TCP_CLIENT_SAMPLE_SOCKET_NAME, NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, TCP_CLIENT_SAMPLE_TCP_WINDOW_SZ, NX_NULL, NX_NULL); // Bind TCP socket status = nx_tcp_client_socket_bind(sock_ptr, TCP_CLIENT_SAMPLE_DEF_CLIENT_PORT, NX_WAIT_FOREVER); // Connect to TCP server status = nx_tcp_client_socket_connect(sock_ptr, srv_info.ip_addr, srv_info.port, TCP_CLIENT_SAMPLE_DEF_MAX_CONNECTION_TIMEOUT); ... } 2.2.3.2 Data Transmission TCP data is received when function nx_tcp_socket_receive() is called. The TCP receive packet processing is responsible for handling various connection and disconnection actions as well as transmit acknowledge processing. In addition, the TCP receive packet processing is responsible for putting packets with receive data on the appropriate TCP socket's receive queue or delivering the packet to the first suspended thread that waits for a packet. TCP data is sent when function nx_tcp_socket_send() is called. This service first builds a TCP header in front of the packet (including the checksum calculation). If the receiver's window size is larger than the data in this packet, the packet is sent on the Internet with the internal IP send routine. Otherwise, the caller may suspend and wait for the receiver`s window size to increase enough for this packet to be sent. At any given time, only one sender may suspend while trying to send TCP data. void tcp_client_sample_run() { ... while (NX_TRUE) { /* * Receive a packet from the connected TCP client socket. * If no packet is available, * wait for 100(TCP_CLIENT_SAMPLE_DEF_TIMEOUT) timer ticks before giving up. */ status = nx_tcp_socket_receive(sock_ptr, &recv_ptr, TCP_CLIENT_SAMPLE_DEF_TIMEOUT); if (status == NX_SUCCESS) { // Get the length of the received packet. status = nx_packet_length_get(recv_ptr, &recv_bytes); // Copy data from a packet into the buffer. status = nx_packet_data_retrieve(recv_ptr, data_buf, &data_buflen); User Manual CFR0012 Revision 2.2 24 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide // Display received packet PRINTF(" =====> Received Packet(%ld) \n", recv_bytes); // Allocate a packet from the packet pool status = nx_packet_allocate(pool_ptr, &send_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); // Copy data to the end of the packet. status = nx_packet_data_append(send_ptr, data_buf, data_buflen, pool_ptr, NX_WAIT_FOREVER); // Send a TCP packet through the socket. status = nx_tcp_socket_send(sock_ptr, send_ptr, NX_WAIT_FOREVER); // Display sent packet PRINTF(" <===== Sent Packet(%ld) \n", data_buflen); } } ... } 2.2.3.3 Disconnection The connection is closed when function nx_tcp_socket_disconnect() is called. To unbind the port and client socket, the application calls function nx_tcp_client_socket_unbind(). The socket must be in a CLOSED state or in the process of disconnecting before the port is released. Otherwise, an error is returned. Finally, if the application no longer needs the client socket, the nx_tcp_socket_delete() function is called to delete the socket. void tcp_client_sample_run() { ... // Disconnect the client socket from the server status = nx_tcp_socket_disconnect(sock_ptr, TCP_CLIENT_SAMPLE_DEF_TIMEOUT); // Unbind the TCP client socket structure from the previously bound TCP port status = nx_tcp_client_socket_unbind(sock_ptr); // Delete the socket status = nx_tcp_socket_delete(sock_ptr); ... } 2.3 TCP Client in DPM The TCP client in the DPM sample application is an example of the simplest TCP echo client application in DPM mode. The DA16200 SDK can work in DPM mode. The user application requires an additional operation to work in DPM mode. The DA16200 SDK provides a DPM manager feature for the user network application. The DPM manager feature supports the user to develop and manage a network application in Non-DPM and DPM modes. This section describes how the TCP client in the DPM sample application is built and works. User Manual CFR0012 Revision 2.2 25 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 2.3.1 How to Run 1. Run a socket application on the peer PC (see Section 2.1.2) and open a TCP server socket with port number 10192. 2. Open the workspace for the TCP Client in the DPM sample application as follows: ~/SDK/sample/Network/TCP_Client_DPM/build/DA16xxx.eww 3. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. 4. Use the console command to set up the Wi-Fi station interface. 5. There are two ways to set the IP address and the port for the Test DUT in the TCP Client Sample. a. Edit the source code: ~/SDK/sample/Network/TCP_Client_DPM/src/tcp_client_dpm_sample.c #define TCP_CLIENT_SAMPLE_DEF_SERVER_IP #define TCP_CLIENT_SAMPLE_DEF_SERVER_PORT "192.168.0.11" TCP_CLI_TEST_PORT b. Use the DA16200 console to save the values in NVRAM: [/DA16200] # nvram.setenv TCPC_SERVER_IP 192.168.0.11 [/DA16200] # nvram.setenv TCPC_SERVER_PORT 10192 [/DA16200] # reboot 6. After a connection is made to a Wi-Fi AP, the sample application will connect to the Test DUT. 2.3.2 How it Works The DA16200 TCP Client in the DPM sample application is a simple echo message. When the TCP server sends a message, then the DA16200 TCP client will echo that message to the TCP server. Figure 18: Workflow of TCP Client in DPM 2.3.3 Details 2.3.3.1 Registration The TCP client in the DPM sample application works in DPM mode. The basic code is similar to the TCP client sample application. The difference with the TCP client sample application is two things: An initial callback function is added, named tcp_client_dpm_sample_wakeup_callback in the code. The callback is called when the DPM state changes from sleep to wakeup An additional user configuration can be stored in RTM In this sample, TCP server information will be stored. void tcp_client_dpm_sample_init_user_config(dpm_user_config_t *user_config) { const int session_idx = 0; //Set Boot init callback user_config->bootInitCallback = tcp_client_dpm_sample_init_callback; User Manual CFR0012 Revision 2.2 26 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide //Set DPM wakeup init callback user_config->wakeupInitCallback = tcp_client_dpm_sample_wakeup_callback; //Set External wakeup callback user_config->externWakeupCallback = tcp_client_dpm_sample_external_callback; //Set Error callback user_config->errorCallback = tcp_client_dpm_sample_error_callback; //Set session type(TCP Client) user_config->sessionConfig[session_idx].session_type = REG_TYPE_TCP_CLIENT; //Set local port user_config->sessionConfig[session_idx].session_myPort = TCP_CLIENT_DPM_SAMPLE_DEF_CLIENT_PORT; //Set server IP address memcpy(user_config->sessionConfig[session_idx].session_serverIp, srv_info.ip_addr, strlen(srv_info.ip_addr)); //Set server port user_config->sessionConfig[session_idx].session_serverPort = srv_info.port; //Set Connection callback user_config->sessionConfig[session_idx].session_connectCallback = tcp_client_dpm_sample_connect_callback; //Set Recv callback user_config->sessionConfig[session_idx].session_recvCallback = tcp_client_dpm_sample_recv_callback; //Set connection retry count user_config->sessionConfig[session_idx].session_conn_retry_cnt = TCP_CLIENT_DPM_SAMPLE_DEF_MAX_CONNECTION_RETRY; //Set connection timeout user_config->sessionConfig[session_idx].session_conn_wait_time = TCP_CLIENT_DPM_SAMPLE_DEF_MAX_CONNECTION_TIMEOUT; //Set auto reconnection flag user_config->sessionConfig[session_idx].session_auto_reconn = NX_TRUE; //Set user configuration user_config->ptrDataFromRetentionMemory = (UCHAR *)&srv_info; user_config->sizeOfRetentionMemory = sizeof(tcp_client_dpm_sample_svr_info_t); return ; } 2.3.3.2 Data Transmission The callback function is called when a TCP packet is received from a TCP server. In this sample, the received data is printed out and an echo message is sent to the TCP server. void tcp_client_dpm_sample_recv_callback(void *sock, UCHAR *rx_buf, UINT rx_len, ULONG rx_ip, ULONG rx_port) { //Display received packet PRINTF(" =====> Received Packet(%ld) \n", rx_len); User Manual CFR0012 Revision 2.2 27 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide //Echo message status = dpm_mng_send_to_session(SESSION1, rx_ip, rx_port, (char *)rx_buf, rx_len); //Display sent packet PRINTF(" <===== Sent Packet(%ld) \n", rx_len); dpm_mng_job_done(); //Done opertaion } 2.4 TCP Server The TCP server sample application is an example of the simplest TCP echo server application. The Transmission Control Protocol is one of the main protocols of the Internet protocol suite. TCP provides a reliable, ordered, and error-checked delivery of a stream of octets (bytes) between applications running on hosts that communicate via an IP network. The DA16200 SDK provides the NetX Duo's TCP protocol. NetX Duo is a high-performance real-time implementation of the TCP/IP standards designed exclusively for embedded ThreadX-based applications. This section describes how the TCP server sample application is built and works. 2.4.1 How to Run 1. Open the workspace for the TCP Server sample application as follows: ~/SDK/sample/Network/TCP_Server/build/DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. 3. There are two ways to set the IP address and the port for the Test DUT in the TCP Server Sample. a. Edit the source code: ~/SDK/sample/Network/TCP_Server/src/tcp_server_sample.c #define TCP_SERVER_SAMPLE_DEF_SERVER_PORT TCP_SVR_TEST_PORT b. Use the DA16200 console to save the values in NVRAM: [/DA16200] # nvram.setenv TCP_SVR_PORT 10190 [/DA16200] # reboot 4. Set up the Wi-Fi station interface using console commands. 5. After a connection is made to an AP, the sample application will create a TCP server socket with port number 10190 and wait for a client connection. 6. Run a socket application on the peer PC (See Section 2.1.2). 7. Open a TCP client socket. 2.4.2 How it Works The DA16200 TCP Server sample application is a simple echo server. When a TCP client sends a message, the DA16200 TCP server will echo that message to the TCP client. User Manual CFR0012 Revision 2.2 28 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide Figure 19: Workflow of TCP Server 2.4.3 Details The DA16200 SDK provides the NetX Duo's TCP protocol. This sample application describes how a TCP socket is created, deleted, and configured. 2.4.3.1 Connection The server waits for a client connection request. To accept a client connection, TCP must first be enabled on the IP instance by function get_thread_netx(). Next, the application must create a TCP socket with the nx_tcp_socket_create() service. The server socket must also be set up to listen for connection requests with the nx_tcp_server_socket_listen() service. This service puts the server socket in the LISTEN state and binds the specified server port to the server socket. If the socket connection has already been established, the function simply returns a successful status. void tcp_server_sample_run() { NX_IP *ip_ptr = NULL; NX_PACKET_POOL *pool_ptr = NULL; NX_TCP_SOCKET *sock_ptr = NULL; // Get informations of current ip instance and packet pool get_thread_netx((void **)&pool_ptr, (void **)&ip_ptr, WLAN0_IFACE); // Create TCP socket status = nx_tcp_socket_create(ip_ptr, sock_ptr, TCP_SERVER_SAMPLE_SOCKET_NAME, NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, TCP_SERVER_SAMPLE_TCP_WINDOW_SZ, NX_NULL, NX_NULL); // Listen TCP socket status = nx_tcp_server_socket_listen(ip_ptr, srv_info.port, sock_ptr, TCP_SERVER_SAMPLE_LISTEN_BAGLOG, NX_NULL); // Accept TCP session do { /* * Wait for 100(TCP_SERVER_SAMPLE_DEF_TIMEOUT) ticks * for the client socket connection to complete. */ User Manual CFR0012 Revision 2.2 29 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide status = nx_tcp_server_socket_accept(sock_ptr, TCP_SERVER_SAMPLE_DEF_TIMEOUT); if (status) { // Unaccept the server socket. nx_tcp_server_socket_unaccept(sock_ptr); // Setup server socket for listening with this socket again. nx_tcp_server_socket_relisten(ip_ptr, srv_info.port, sock_ptr); } } while (status); ... } 2.4.3.2 Data Transmission TCP data is received when function nx_tcp_socket_receive() is called. The TCP receive packet process is responsible for handling the various connection and disconnection actions as well as transmit acknowledge process. In addition, the TCP receive packet process is responsible for putting packets with receive data on the appropriate TCP socket's receive queue or delivering the packet to the first suspended thread that waits for a packet. TCP data is sent when function nx_tcp_socket_send() is called. This service first builds a TCP header in front of the packet (including the checksum calculation). If the receiver's window size is larger than the data in this packet, the packet is sent on the Internet with the internal IP send routine. Otherwise, the caller may suspend and wait for the receiver`s window size to increase enough for this packet to be sent. At any given time, only one sender may suspend while trying to send TCP data. void tcp_server_sample_run() { ... while (NX_TRUE) { /* * Receive a packet from the connected TCP server socket. * If no packet is available, * wait for 100(TCP_SERVER_SAMPLE_DEF_TIMEOUT) timer ticks before giving up. */ status = nx_tcp_socket_receive(sock_ptr, &recv_ptr, TCP_SERVER_SAMPLE_DEF_TIMEOUT); if (status == NX_SUCCESS) { // Get the length of the received packet. status = nx_packet_length_get(recv_ptr, &recv_bytes); // Copy data from a packet into the buffer. status = nx_packet_data_retrieve(recv_ptr, data_buf, &data_buflen); // Display received packet PRINTF(" =====> Received Packet(%ld) \n", recv_bytes); // Allocate a packet from the packet pool status = nx_packet_allocate(pool_ptr, &send_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); // Copy data to the end of the packet. status = nx_packet_data_append(send_ptr, User Manual CFR0012 Revision 2.2 30 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide data_buf, data_buflen, pool_ptr, NX_WAIT_FOREVER); // Send a TCP packet through the socket. status = nx_tcp_socket_send(sock_ptr, send_ptr, NX_WAIT_FOREVER); // Display sent packet PRINTF(" <===== Sent Packet(%ld) \n", data_buflen); } } ... } 2.4.3.3 Disconnection The connection is closed when function nx_tcp_socket_disconnect() is called. After the disconnect process is completed and the server socket is in the CLOSED state, the application must call the nx_tcp_server_socket_unaccept() service to end the association of this socket with the server port. After the nx_tcp_server_socket_unaccept() returns, the socket can be used as a client or server socket, or even be deleted if no longer needed. In this sample, the TCP socket is deleted. void tcp_server_sample_run() { ... // Disconnect the client socket from the server status = nx_tcp_socket_disconnect(sock_ptr, TCP_SERVER_SAMPLE_DEF_TIMEOUT); // Unbind the TCP client socket structure from the previously bound TCP port status = nx_tcp_server_socket_unaccept(sock_ptr); // Delete the socket status = nx_tcp_socket_delete(sock_ptr); ... } 2.4.3.4 To Stop Listening on a Server Port If the application no longer wishes to listen for client connection requests on a server port that was previously specified by a call to the nx_tcp_server_socket_listen() service, the application simply calls the nx_tcp_server_socket_unlisten() service. This service puts any socket that waits for a connection back in the CLOSED state and releases any queued client connection request packets. If the acceptance of another client connection on the same server port is desired, the nx_tcp_server_socket_relisten() service should be called with this socket. void tcp_server_sample_run() { ... // Unlisten on server port. status = nx_tcp_server_socket_unlisten(ip_ptr, srv_info.port); ... } 2.5 TCP Server in DPM The TCP server in the DPM sample application is an example of the simplest TCP echo server application. The DA16200 SDK can work in DPM mode. The user application is required to work in DPM mode. The DA16200 SDK provides a DPM manager feature for the user network application. The DPM manager feature supports the user to develop and manage a network application in Non- User Manual CFR0012 Revision 2.2 31 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide DPM and DPM modes. The codes are almost the same as for the TCP Server example. This section describes how the TCP server is built and works in the DPM sample application. 2.5.1 How to Run 1. Open the workspace for the TCP Server DPM sample application as follows: ~/SDK/sample/Network/TCP_Server_DPM/build/DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. 3. There are two ways to set the IP address and the port for the Test DUT in the TCP Server Sample. a. Edit the source code: ~/SDK/sample/Network/TCP_Server_DPM/src/tcp_server_dpm_sample.c #define TCP_SERVER_SAMPLE_DEF_SERVER_PORT TCP_SVR_TEST_PORT b. Use the DA16200 console to save the values in NVRAM: [/DA16200] # nvram.setenv TCP_SVR_PORT 10190 [/DA16200] # reboot 4. Use the console command to set up the Wi-Fi station interface. 5. After a connection is made to an AP, the sample application will create a TCP server socket with port number 10190 (Default test port number) and wait for a client connection. 6. Run a socket application on the peer PC (See Section 2.1.2). 7. Open a TCP client socket. 2.5.2 How it Works The DA16200 TCP Server in the DPM sample application is a simple echo server. When a TCP client sends a message, then the DA16200 TCP server will echo that message to the TCP client. Figure 20: Workflow of TCP Server in DPM 2.5.3 Details 2.5.3.1 Registration The TCP server in the DPM sample application works in DPM mode. The basic code is similar to the TCP server sample application. The difference with the TCP server sample application is two things: An initial callback function is added, named tcp_server_dpm_sample_wakeup_callback in the code. The callback is called when the DPM state changes from sleep to wakeup An additional user configuration can be stored in RTM In this sample, the TCP server information will be stored. void tcp_server_dpm_sample_init_user_config(dpm_user_config_t *user_config) { const int session_idx = 0; User Manual CFR0012 Revision 2.2 32 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide //Set Boot init callback user_config->bootInitCallback = tcp_server_dpm_sample_init_callback; //Set DPM wakkup init callback user_config->wakeupInitCallback = tcp_server_dpm_sample_wakeup_callback; //Set Error callback user_config->errorCallback = tcp_server_dpm_sample_error_callback; //Set session type(TCP Server) user_config->sessionConfig[session_idx].session_type = REG_TYPE_TCP_SERVER; //Set local port user_config->sessionConfig[session_idx].session_myPort = TCP_SERVER_DPM_SAMPLE_DEF_SERVER_PORT; //Set Connection callback user_config->sessionConfig[session_idx].session_connectCallback = tcp_server_dpm_sample_connect_callback; //Set Recv callback user_config->sessionConfig[session_idx].session_recvCallback = tcp_server_dpm_sample_recv_callback; //Set user configuration user_config->ptrDataFromRetentionMemory = (UCHAR *)&srv_info; user_config->sizeOfRetentionMemory = sizeof(tcp_server_dpm_sample_svr_info_t); return ; } 2.5.3.2 Data Transmission The callback function is called when a TCP packet is received from a TCP client. In this sample, the received data is printed out and an echo message is sent to the TCP client. void tcp_server_dpm_sample_recv_callback(void *sock, UCHAR *rx_buf, UINT rx_len, ULONG rx_ip, ULONG rx_port) { //Display received packet PRINTF(" =====> Received Packet(%ld) \n", rx_len); //Echo message status = dpm_mng_send_to_session(SESSION1, rx_ip, rx_port, (char *)rx_buf, rx_len); //Display sent packet PRINTF(" <===== Sent Packet(%ld) \n", rx_len); dpm_mng_job_done(); //Done opertaion } 2.6 TCP Client with KeepAlive The TCP client with KeepAlive sample application is an example of the simplest TCP echo client application. Especially, this sample application sends TCP KeepAlive messages to the TCP server periodically. The Transmission Control Protocol (TCP) is one of the main protocols of the Internet protocol suite. TCP provides a reliable, ordered, and error-checked delivery of a stream of octets (bytes) between applications that run on hosts and communicate via an IP network. The DA16200 SDK provides a NetX Duo's TCP protocol. NetX Duo is a high-performance real-time implementation of the TCP/IP standards designed exclusively for embedded ThreadX-based applications. User Manual CFR0012 Revision 2.2 33 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide This section describes how the TCP client with KeepAlive sample application is built and works. 2.6.1 How to Run 1. Run a socket application on the peer PC (See Section 2.1.2) and open a TCP server socket with port number 10193 (Default TCP Client test port). 2. In the IAR workbench, open the workspace for the TCP Client sample application as follows: ~/SDK/sample/Network/TCP_Client_KeepAlive/build/DA16xxx.eww 3. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB, and reboot. 4. Use the console command to set up the Wi-Fi station interface. 5. There are two ways to set the IP address and the port for the Test DUT in the TCP Client KA Sample. Edit the source code: ~/SDK/sample/Network/TCP_Client_KeepAlive/src/tcp_client_ka_sample.c #define TCP_CLIENT_SAMPLE_DEF_SERVER_IP "192.168.0.11" #define TCP_CLIENT_SAMPLE_DEF_SERVER_PORT TCP_CLI_TEST_PORT Use the DA16200 console to save the values in NVRAM: [/DA16200] # nvram.setenv TCPC_SERVER_IP 192.168.0.11 [/DA16200] # nvram.setenv TCPC_SERVER_PORT 10192 [/DA16200] # reboot After a connection is made to a Wi-Fi AP, the example application will connect with Test DUT. 2.6.2 How it Works The DA16200 TCP Client with KeepAlive in the sample application is a simple echo message. When a TCP server sends a message, then the DA16200 TCP client will echo that message to the TCP server. And, a TCP KeepAlive message will be periodically sent to the TCP server every 55 seconds. Figure 21: Workflow of TCP Client with KeepAlive 2.6.3 Details The DA16200 SDK provides a NetX Duo's TCP protocol. This sample application describes how the TCP socket is created, deleted, and configured to send TCP KeepAlive. 2.6.3.1 Registration The client side of the TCP connection initiates a connection request to a TCP server. Before a connection request can be made, TCP must be enabled on the client IP instance with function get_thread_netx(). In addition, the client TCP socket must next be created with the User Manual CFR0012 Revision 2.2 34 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide nx_tcp_socket_create() service and bound to a port via the nx_tcp_client_socket_bind() service. In order to send TCP KeepAlive messages, the configuration is done with function nx_tcp_socket_option(). In this sample application, the period of TCP KeepAlive messages is 55 seconds. After the client socket is bound, the nx_tcp_client_socket_connect() service is used to establish a connection with a TCP server. void tcp_client_ka_sample_run() { NX_IP *ip_ptr = NULL; NX_PACKET_POOL *pool_ptr = NULL; NX_TCP_SOCKET *sock_ptr = NULL; NX_TCP_SOCKET_OPTION sock_opt; // Get informations of current ip interface and packet pool get_thread_netx((void **)&pool_ptr, (void **)&ip_ptr, WLAN0_IFACE); // Create TCP socket status = nx_tcp_socket_create(ip_ptr, sock_ptr, TCP_CLIENT_SAMPLE_SOCKET_NAME, NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, TCP_CLIENT_KA_SAMPLE_TCP_WINDOW_SZ, NX_NULL, NX_NULL); // Bind TCP socket status = nx_tcp_client_socket_bind(sock_ptr, TCP_CLIENT_KA_SAMPLE_DEF_CLIENT_PORT, NX_WAIT_FOREVER); // Set TCP KeepAlive sock_opt.keepalive_enabled = NX_TRUE; sock_opt.keepalive_timeout = TCP_CLIENT_KA_SAMPLE_DEF_KEEPALIVE_TIMEOUT; status = nx_tcp_socket_option(sock_ptr, NX_SO_KEEPALIVE, &sock_opt); // Connect to TCP server status = nx_tcp_client_socket_connect(sock_ptr, srv_info.ip_addr, srv_info.port, TCP_CLIENT_KA_SAMPLE_DEF_MAX_CONNECTION_TIMEOUT); ... } 2.6.3.2 Data Transmission To receive TCP data, function nx_tcp_socket_receive() is called. The TCP receive packet process is responsible for handling various connection and disconnection actions as well as the transmit acknowledge process. In addition, the TCP receive packet process is responsible for putting packets with receive data on the appropriate TCP socket's receive queue or delivering the packet to the first suspended thread that waits for a packet. To send TCP data, function nx_tcp_socket_send() is called. This service first builds a TCP header in front of the packet (this includes a checksum calculation). If the receiver's window size is larger than the data in this packet, the packet is sent on the Internet with an internal IP send routine. Otherwise, the caller may suspend and wait for the receiver`s window size to increase enough for this packet to be sent. At any given time, only one sender may suspend while trying to send TCP data. void tcp_client_ka_sample_run() User Manual CFR0012 Revision 2.2 35 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide { ... while (NX_TRUE) { /* * Receive a packet from the connected TCP client socket. * If no packet is available, * wait for 100(TCP_CLIENT_KA_SAMPLE_DEF_TIMEOUT) timer ticks before giving up. */ status = nx_tcp_socket_receive(sock_ptr, &recv_ptr, TCP_CLIENT_KA_SAMPLE_DEF_TIMEOUT); if (status == NX_SUCCESS) { // Get the length of the received packet. status = nx_packet_length_get(recv_ptr, &recv_bytes); // Copy data from a packet into the buffer. status = nx_packet_data_retrieve(recv_ptr, data_buf, &data_buflen); // Display received packet PRINTF(" =====> Received Packet(%ld) \n", recv_bytes); // Allocate a packet from the packet pool status = nx_packet_allocate(pool_ptr, &send_ptr, NX_TCP_PACKET, NX_WAIT_FOREVER); // Copy data to the end of the packet. status = nx_packet_data_append(send_ptr, data_buf, data_buflen, pool_ptr, NX_WAIT_FOREVER); // Send a TCP packet through the socket. status = nx_tcp_socket_send(sock_ptr, send_ptr, NX_WAIT_FOREVER); // Display sent packet PRINTF(" <===== Sent Packet(%ld) \n", data_buflen); } } ... } 2.6.3.3 Disconnection A connection is closed when function nx_tcp_socket_disconnect() is called. To unbind the port and client socket, the application calls function nx_tcp_client_socket_unbind(). The socket must be in a CLOSED state or in the process of disconnecting before the port is released. Otherwise, an error is returned. Finally, if the application no longer needs the client socket, function nx_tcp_socket_delete() is called to delete the socket. void tcp_client_ka_sample_run() { ... // Disconnect the client socket from the server status = nx_tcp_socket_disconnect(sock_ptr, TCP_CLIENT_KA_SAMPLE_DEF_TIMEOUT); User Manual CFR0012 Revision 2.2 36 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide // Unbind the TCP client socket structure from the previously bound TCP port status = nx_tcp_client_socket_unbind(sock_ptr); // Delete the socket status = nx_tcp_socket_delete(sock_ptr); ... } 2.7 TCP Client with KeepAlive in DPM The TCP client with KeepAlive in the DPM sample application is an example of the simplest TCP echo client application in DPM mode. The DA16200 SDK can work in DPM mode. The user application requires to work in DPM mode. The DA16200 SDK provides a DPM manager feature for the user network application. The DPM manager feature supports the user to develop and manage a network application in Non-DPM and DPM modes. This section describes how the TCP client with KeepAlive in DPM sample application is built and works. 2.7.1 How to Run 1. Run a socket application on the peer PC (see Section 2.1.2) and open a TCP server socket with port number 10193 (Default TCP Client test port). 2. In the IAR workbench, open the workspace for the TCP Client sample application as follows: ~/SDK/sample/Network/TCP_Client_KeepAlive_DPM/build/DA16xxx.eww 3. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB, and reboot. 4. Use the console command to set up the Wi-Fi station interface. 5. There are two ways to set the IP address and the port for the Test DUT in the TCP Client KA DPM Sample: Edit the source code: ~/SDK/sample/Network/TCP_Client_KeepAlive_DPM/src/tcp_client_ka_dpm_sample.c //Default TCP Server configuration #define TCP_CLIENT_SAMPLE_DEF_SERVER_IP "192.168.0.11" #define TCP_CLIENT_SAMPLE_DEF_SERVER_PORT TCP_CLI_TEST_PORT Use the DA16200 console to save the values in NVRAM: [/DA16200] # nvram.setenv TCPC_SERVER_IP 192.168.0.11 [/DA16200] # nvram.setenv TCPC_SERVER_PORT 10192 [/DA16200] # reboot After a connection is made to a Wi-Fi AP, the example application will connect to the Test DUT. Details 2.7.2.1 Registration The TCP client with KeepAlive in the DPM sample application works in DPM mode. The basic code is similar to the TCP client with KeepAlive sample application. The time period is 55 seconds to send a TCP KeepAlive message to the TCP server. The difference with the TCP client sample application is two things compared to the TCP client in the DPM sample application: An initial callback function is added, named `tcp_client_ka_dpm_sample_wakeup_callback` in the code. The callback function is called when the DPM state changes from sleep to wakeup An additional user configuration can be stored in RTM In this example, TCP server information will be stored. void tcp_client_ka_dpm_sample_init_user_config(dpm_user_config_t *user_config) { const int session_idx = 0; User Manual CFR0012 Revision 2.2 37 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide //Set Boot init callback user_config->bootInitCallback = tcp_client_ka_dpm_sample_init_callback; //Set Error callback user_config->errorCallback = tcp_client_ka_dpm_sample_error_callback; //Set session type(TCP Client) user_config->sessionConfig[session_idx].session_type = REG_TYPE_TCP_CLIENT; //Set local port user_config->sessionConfig[session_idx].session_myPort = TCP_CLIENT_KA_DPM_SAMPLE_DEF_CLIENT_PORT; //Set server IP address memcpy(user_config->sessionConfig[session_idx].session_serverIp, srv_info.ip_addr, strlen(srv_info.ip_addr)); //Set server port user_config->sessionConfig[session_idx].session_serverPort = srv_info.port; //Set Connection callback user_config->sessionConfig[session_idx].session_connectCallback = tcp_client_ka_dpm_sample_connect_callback; //Set Recv callback user_config->sessionConfig[session_idx].session_recvCallback = tcp_client_ka_dpm_sample_recv_callback; //Set connection retry count user_config->sessionConfig[session_idx].session_conn_retry_cnt = TCP_CLIENT_KA_DPM_SAMPLE_DEF_MAX_CONNECTION_RETRY; //Set connection timeout user_config->sessionConfig[session_idx].session_conn_wait_time = TCP_CLIENT_KA_DPM_SAMPLE_DEF_MAX_CONNECTION_TIMEOUT; //Set auto reconnection flag user_config->sessionConfig[session_idx].session_auto_reconn = NX_TRUE; //Set KeepAlive timeout user_config->sessionConfig[session_idx].session_ka_interval = TCP_CLIENT_KA_DPM_SAMPLE_DEF_KEEPALIVE_TIMEOUT; return ; } 2.7.2.2 Data Transmission The callback function is called when a TCP packet is received from the TCP server. In this example, the received data is printed out and an echo message is sent to the TCP server. void tcp_client_ka_dpm_sample_recv_callback(void *sock, UCHAR *rx_buf, UINT rx_len, ULONG rx_ip, ULONG rx_port) { //Display received packet PRINTF(" =====> Received Packet(%ld) \n", rx_len); //Echo message status = dpm_mng_send_to_session(SESSION1, rx_ip, rx_port, (char *)rx_buf, rx_len); User Manual CFR0012 Revision 2.2 38 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide //Display sent packet PRINTF(" <===== Sent Packet(%ld) \n", rx_len); dpm_mng_job_done(); //Done opertaion } 2.7.3 How it Works The DA16200 TCP Client with KeepAlive in the DPM sample application is a simple echo message. When the TCP server sends a message, then the DA16200 TCP client will echo that message to the TCP server. A periodic TCP KeepAlive message is sent to the TCP server every 55 seconds. Figure 22: Workflow of TCP Client with KeepAlive in DPM 2.8 UDP Socket The UDP socket sample application is an example of the simplest UDP echo application. The User Datagram Protocol (UDP) is one of the core members of the Internet protocol suite. UDP uses a simple connectionless communication model with a minimum of protocol mechanisms. UDP provides checksums for data integrity, and port numbers to address different functions at the source and destination of the datagram. It has no handshake dialogues, and thus exposes the user's program to any unreliability of the underlying network; there is no guarantee of delivery, ordering, or duplicate protection. DA16200 SDK provides NetX Duo's UDP protocol. NetX Duo is a high-performance realtime implementation of the UDP/IP standards designed exclusively for embedded ThreadX-based applications. This section describes how the UDP socket sample application is built and works. 2.8.1 How to Run 1. Run a socket application on the peer PC (see Section 2.1.2) and open a UDP socket with port number 10195 (default UDP test port). 2. In the IAR workbench, open the workspace for the TCP Client sample application as follows: ~/SDK/sample/Network/UDP_Socket/build/DA16xxx.eww 3. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB, and reboot. 4. Use the console command to set up the Wi-Fi station interface. 5. There is one way to set the port number for the Test DUT of the UDP Socket Sample: a. Edit the source code: ~/SDK/sample/Network/UDP_Socket /src/udp_socket.c #define UDP_SOCKET_SAMPLE_DEF_LOCAL_PORT "192.168.0.11" After a connection is made to a Wi-Fi AP, the sample application will connect to the Test DUT. User Manual CFR0012 Revision 2.2 39 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 2.8.2 How it Works The DA16200 UDP socket sample application is a simple echo server. When a UDP peer sends a message, then the DA16200 UDP socket sample application will echo that message to the UDP peer. Figure 23: Workflow of UDP Socket 2.8.3 Details The DA16200 SDK provides the NetX Duo's UDP protocol. This sample application describes how the UDP socket is created, deleted, and configured. 2.8.3.1 Initialization A UDP port is a logical end point in the UDP protocol. There are 65,535 valid ports in the UDP component of NetX Duo, ranging from 1 through 0xFFFF. To send or receive UDP data, the application must first create a UDP socket with function nx_udp_socket_create(), then bind the UDP socket to a desired port. Next, the application may send and receive data on that socket. The details are as follows: void udp_socket_sample_run() { NX_IP *ip_ptr = NULL; NX_PACKET_POOL *pool_ptr = NULL; NX_UDP_SOCKET *sock_ptr = NULL; // Get informations of current ip interface and packet pool get_thread_netx((void **)&pool_ptr, (void **)&ip_ptr, WLAN0_IFACE); // Create socket status = nx_udp_socket_create(ip_ptr, sock_ptr, UDP_CLIENT_SAMPLE_SOCKET_NAME, NX_IP_NORMAL, NX_FRAGMENT_OKAY, NX_IP_TIME_TO_LIVE, 5); // Bind udp socket status = nx_udp_socket_bind(sock_ptr, UDP_CLIENT_SAMPLE_DEF_CLIENT_PORT, NX_WAIT_FOREVER); ... } User Manual CFR0012 Revision 2.2 40 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 2.8.3.2 Data Transmission To receive a UDP packet, function nx_udp_socket_receive() is called. The socket receive function delivers the oldest packet on the socket's receive queue. If there are no packets in the receive queue, the call thread can be suspended (with an optional timeout) until a packet arrives. To send UDP data, function nx_udp_socket_send() is called. This service puts a UDP header in front of the packet and sends the packet on the Internet with the internal IP send routine. There is no thread suspension on sending UDP packets, because all UDP packet transmissions are processed immediately. void udp_socket_sample_run() { ... while (NX_TRUE) { /* * Receive a packet from the UDP socket. * If no packet is available, * wait for 100(TCP_SERVER_SAMPLE_DEF_TIMEOUT) timer ticks before giving up. */ status = nx_udp_socket_receive(sock_ptr, &recv_ptr, UDP_CLIENT_SAMPLE_DEF_TIMEOUT); if (status == NX_SUCCESS) { /* * Get the source IP address, protocol, port number * and the incoming interface from the incoming packet. */ status = nxd_udp_packet_info_extract(recv_ptr, &peer_ip_addr, NX_NULL, &peer_port, NX_NULL); // Get the length of the received packet. status = nx_packet_length_get(recv_ptr, &recv_bytes); // Copy data from a packet into the buffer. status = nx_packet_data_retrieve(recv_ptr, data_buf, &data_buflen); // Display received packet PRINTF(" =====> Received Packet(%ld) from %d.%d.%d.%d:%d\n", recv_bytes, (peer_ip_addr.nxd_ip_address.v4 >> 24) & 0x0ff, (peer_ip_addr.nxd_ip_address.v4 >> 16) & 0x0ff, (peer_ip_addr.nxd_ip_address.v4 >> 8) & 0x0ff, (peer_ip_addr.nxd_ip_address.v4 ) & 0x0ff, peer_port); // Allocate a packet from the packet pool status = nx_packet_allocate(pool_ptr, &send_ptr, NX_UDP_PACKET, NX_WAIT_FOREVER); // Copy data to the end of the packet. status = nx_packet_data_append(send_ptr, data_buf, data_buflen, pool_ptr, NX_WAIT_FOREVER); // Send a UDP packet through the socket. User Manual CFR0012 Revision 2.2 41 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide status = nxd_udp_socket_send(sock_ptr, send_ptr, &peer_ip_addr, peer_port); //Display sent packet PRINTF(" <===== Sent Packet(%ld) to %d.%d.%d.%d:%d \n", data_buflen, (peer_ip_addr.nxd_ip_address.v4 >> 24) & 0x0ff, (peer_ip_addr.nxd_ip_address.v4 >> 16) & 0x0ff, (peer_ip_addr.nxd_ip_address.v4 >> 8) & 0x0ff, (peer_ip_addr.nxd_ip_address.v4 ) & 0x0ff, peer_port); } } } 2.9 UDP Server in DPM The UDP server in the DPM sample application is an example of the simplest UDP echo application in DPM mode. The DA16200 SDK can work in DPM mode. The DPM manager feature of the DA16200 SDK is helpful for the user to develop and manage a UDP server socket application in Non-DPM and DPM modes. This section describes how the UDP server in the DPM sample application is built and works. 2.9.1 How to Run 1. Run a socket application on the peer PC (see Section 2.1.2) and open a UDP socket with port number 10194 (Default UDP test port). 2. In the IAR workbench, open the workspace for the UDP Server DPM sample application as follows: ~/SDK/sample/Network/UDP_Server_DPM/build/DA16xxx.eww 3. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB, and reboot. 4. Use the console command to set up the Wi-Fi station interface. 5. There is one way to set the port number for the Test DUT of the UDP Server DPM Sample: a. Edit the source code: ~/SDK/sample/Network/UDP_Socket /src/udp_server_dpm_sample.c #define UDP_SERVER_DPM_SAMPLE_DEF_SERVER_PORT UDP_SVR_TEST_PORT After a connection is made to a Wi-Fi AP, the sample application will connect to the Test DUT. 2.9.2 How it Works The DA16200 UDP Server in the DPM sample application is a simple echo server. When the peer's UDP application sends a message, the DA16200 UDP server will echo that message to the peer. User Manual CFR0012 Figure 24: Workflow of UDP Server in DPM Revision 2.2 42 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 2.9.3 Details 2.9.3.1 Registration The UDP server in the DPM sample application works in DPM mode. The basic code is similar to the UDP server sample application. The difference with the UDP server sample application is two things: An initial callback function is added, named `udp_server_dpm_sample_wakeup_callback` in the code. The callback function is called when the DPM state changes from sleep to wakeup An additional user configuration can be stored in RTM In this sample, the peer's UDP socket port number will be stored. void udp_server_dpm_sample_init_user_config(dpm_user_config_t *user_config) { const int session_idx = 0; //Set Boot init callback user_config->bootInitCallback = udp_server_dpm_sample_init_callback; //Set DPM wakkup init callback user_config->wakeupInitCallback = udp_server_dpm_sample_wakeup_callback; //Set Error callback user_config->errorCallback = udp_server_dpm_sample_error_callback; //Set session type(UDP Server) user_config->sessionConfig[session_idx].session_type = REG_TYPE_UDP_SERVER; //Set local port user_config->sessionConfig[session_idx].session_myPort = UDP_SERVER_DPM_SAMPLE_DEF_SERVER_PORT; //Set Connection callback user_config->sessionConfig[session_idx].session_connectCallback = udp_server_dpm_sample_connect_callback; //Set Recv callback user_config->sessionConfig[session_idx].session_recvCallback = udp_server_dpm_sample_recv_callback; //Set secure mode user_config->sessionConfig[session_idx].supportSecure = NX_FALSE; //Set user configuration user_config->ptrDataFromRetentionMemory = (UCHAR *)&srv_info; user_config->sizeOfRetentionMemory = sizeof(udp_server_dpm_sample_svr_info_t); return ; } 2.9.3.2 Data transmission The callback function is called when a UDP packet is received from the peer's UDP socket application. In this example, the received data is printed out and an echo message is sent to the peer's UDP socket application. void udp_server_dpm_sample_recv_callback(void *sock, UCHAR *rx_buf, UINT rx_len, ULONG rx_ip, ULONG rx_port) { //Display received packet PRINTF(" =====> Received Packet(%ld) \n", rx_len); User Manual CFR0012 Revision 2.2 43 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide //Echo message status = dpm_mng_send_to_session(SESSION1, rx_ip, rx_port, (char *)rx_buf, rx_len); //Display sent packet PRINTF(" <===== Sent Packet(%ld) \n", rx_len); dpm_mng_job_done(); //Done opertaion } 2.10 UDP Client in DPM The UDP client in the DPM sample application is an example of the simplest UDP echo application in DPM mode. The DA16200 SDK can work in DPM mode. The user application requires an additional operation to work in DPM mode. The DPM manager feature of the DA16200 SDK is helpful for the user to develop and manage a UDP client socket application in Non-DPM and DPM modes. This section describes how the UDP client in the DPM sample application is built and works. 2.10.1 How to Run 1. Run a socket application on the peer PC (See Section 2.1.2) and open a UDP socket with port number 10194 (Default UDP test port). 2. In the IAR workbench, open the workspace for the UDP Server DPM sample application as follows: ~/SDK/sample/Network/UDP_Client_DPM/build/DA16xxx.eww 3. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB, and reboot. 4. Use the console command to set up the Wi-Fi station interface. 5. There is one way to set the port number for the Test DUT of the UDP Client DPM Sample: a. Edit the source code: ~/SDK/sample/Network/UDP_Socket /src/udp_client_dpm_sample.c #define UDP_CLIENT_DPM_SAMPLE_DEF_SERVER_PORT UDP_CLI_TEST_PORT After a connection is made to a Wi-Fi AP, the sample application will connect to the Test DUT. 2.10.2 How it Works The DA16200 UDP Client in the DPM sample application is a simple echo message. When a peer's UDP application sends a message, then the DA16200 UDP client will echo that message to the peer. User Manual CFR0012 Figure 25: Workflow of UDP Client in DPM Revision 2.2 44 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 2.10.3 Details 2.10.3.1 Registration The UDP client in the DPM sample application works in DPM mode. The basic code is similar to the UDP client sample application. The difference with the UDP client sample application is two things: An initial callback function is added, named udp_client_dpm_sample_wakeup_callback in the code. The function is called when the DPM state changes from sleep to wakeup An additional user configuration can be stored in RTM In this example, the peer's UDP IP address and port number will be stored. void udp_client_dpm_sample_init_user_config(dpm_user_config_t *user_config) { const int session_idx = 0; //Set Boot init callback user_config->bootInitCallback = udp_client_dpm_sample_init_callback; //Set DPM wakeup init callback user_config->wakeupInitCallback = udp_client_dpm_sample_wakeup_callback; //Set Error callback user_config->errorCallback = udp_client_dpm_sample_error_callback; //Set session type(UDP Client) user_config->sessionConfig[session_idx].session_type = REG_TYPE_UDP_CLIENT; //Set local port user_config->sessionConfig[session_idx].session_myPort = UDP_CLIENT_DPM_SAMPLE_DEF_CLIENT_PORT; //Set server IP address memcpy(user_config->sessionConfig[session_idx].session_serverIp, srv_info.ip_addr, strlen(srv_info.ip_addr)); //Set server port user_config->sessionConfig[session_idx].session_serverPort = srv_info.port; //Set Connection callback user_config->sessionConfig[session_idx].session_connectCallback = udp_client_dpm_sample_connect_callback; //Set Recv callback user_config->sessionConfig[session_idx].session_recvCallback = udp_client_dpm_sample_recv_callback; //Set connection retry count user_config->sessionConfig[session_idx].session_conn_retry_cnt = UDP_CLIENT_DPM_SAMPLE_DEF_MAX_CONNECTION_RETRY; //Set connection timeout user_config->sessionConfig[session_idx].session_conn_wait_time = UDP_CLIENT_DPM_SAMPLE_DEF_MAX_CONNECTION_TIMEOUT; //Set auto reconnection flag user_config->sessionConfig[session_idx].session_auto_reconn = NX_TRUE; //Set user configuration user_config->ptrDataFromRetentionMemory = (UCHAR *)&srv_info; user_config->sizeOfRetentionMemory = sizeof(udp_client_dpm_sample_svr_info_t); User Manual CFR0012 Revision 2.2 45 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide return ; } 2.10.3.2 Data Transmission The callback function is called when a UDP packet is received from the peer's UDP socket application. In this example, the received data is printed out and an echo message is sent to the peer's UDP socket application. void udp_client_dpm_sample_recv_callback(void *sock, UCHAR *rx_buf, UINT rx_len, ULONG rx_ip, ULONG rx_port) { //Display received packet PRINTF(" =====> Received Packet(%ld) \n", rx_len); //Echo message status = dpm_mng_send_to_session(SESSION1, 0, 0, (char *)rx_buf, rx_len); //Display sent packet PRINTF(" <===== Sent Packet(%ld) \n", rx_len); dpm_mng_job_done(); //Done operation } User Manual CFR0012 Revision 2.2 46 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 3 Network Examples: Security 3.1 Test DUT The Test DUT runs a (D)TLS application for `Network Examples: Security'. The Test DUT is connected to an AP, either through a wired (LAN or WLAN) or a wireless connection. 3.1.1 Example of Test DUT (for MS Windows® OS) There are many (D)TLS counter applications available. In this section, we use a self-implemented (D)TLS counter application to demonstrate these sample applications. It is based on the cryptography APIs of the Bouncy Castle (https://www.bouncycastle.org/java.html). 3.1.1.1 TLS Server The TLS server application is for the DA16200 TLS client sample application. It runs with a default port number (10196) and waits for a TLS client to connect, as shown in Figure 26. There is one TLS client connection allowed, and there is no client certificate required during TLS handshake. If the TLS session is established succesfully, the TLS server application sends a message per five seconds periodically. Figure 26: Start of TLS Server Application 3.1.1.2 TLS Client The TLS client application is for the DA16200 TLS server sample application. It runs with default TLS server information. The IP address is 192.168.0.2 and the port number is 10197. The TLS client tries to connect to DA16200 TLS server sample application as shown in Figure 27. If a TLS session is established successfully, the TLS client application sends a message per 5 seconds periodically. Usage: tls_client.exe [TLS server IP address] [Port number] Figure 27: Start of TLS Client Application If the TLS client application cannot find a DA16200 TLS server, an exception occurs with a timeout message as shown in Figure 28. User Manual CFR0012 Revision 2.2 47 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide Figure 28: Timeout of TLS Client Application 3.1.1.3 DTLS Server The DTLS server application is for the DA16200 DTLS client sample application. It runs with a default port number (10199) and waits for the DTLS client to connect, as shown in Figure 29. A client certificate is not required during DTLS handshake. If a DTLS session is established successfully, the DTLS server application sends a message per five seconds periodically. Figure 29: Start of DTLS Server Application 3.1.1.4 DTLS Client The DTLS client application is for the DA16200 DTLS server sample application. It runs with default DTLS server information. The IP address is 192.168.0.2 and the port number is 10199. The DTLS client tries to connect to the DA16200 DTLS server sample application as shown in Figure 30. If a DTLS session is established successfully, the DTLS client application sends a message per five seconds periodically. Usage: dtls_client.exe [DTLS server IP address] [Port number] Figure 30: Start of DTLS Client Application 3.2 TLS Server The TLS server sample application is an example of the simplest TLS echo server application. Transport Layer Security (TLS) is a cryptographic protocol designed to provide communication security over a computer network. The DA16200 SDK provides an SSL library, called "mbedTLS", on the secure H/W engine to support the TLS protocol. "MbedTLS" is one of the popular SSL libraries. It is helpful to easily develop a network application with a TLS protocol. User Manual CFR0012 Revision 2.2 48 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide This section describes how the TLS server sample application is built and works. 3.2.1 How to Run 1. Open the workspace for the TLS Server sample application as follows: ~/SDK/sample/Network/TLS_Server/build/DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. 3. Use the console command to set up the Wi-Fi station interface. 4. After a connection is made to an AP, the sample application will create a TLS server socket with port number 10197 and wait for a client connection. 5. Run a TLS client application on the peer PC. 3.2.2 How it Works The DA16200 TLS Server sample is a simple echo server. When a TLS client sends a message, the DA16200 TLS server will echo that message to the TLS client. Figure 31: Workflow of TLS Server 3.2.3 Details The DA16200 SDK provides an "mbedTLS" library. It describes how the TLS server is implemented with an "mbedTLS" library and a socket library. 3.2.3.1 Initialization The DA16200 secure H/W engine has to be initialized with da16x_seucer_module_init() before the TLS context is initialized. Then, the TLS context is allocated and initialized in function tls_server_sample_init_ssl(). To set up a TLS session, function tls_server_sample_setup_ssl() is called as follows: UINT tls_server_sample_setup_ssl(tls_server_sample_conf_t *config) { const char *pers = "tls_server_sample"; /* * Prepare the DTLS configuration by setting the endpoint and trasport type, * and loading reasonable defaults for the security parameters. */ ret = mbedtls_ssl_config_defaults(config->ssl_conf, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); /* * Parse one DER-encoded or one or more concatenated PEM-encoded certificates * and add them to the chained list. User Manual CFR0012 Revision 2.2 49 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide */ ret = mbedtls_x509_crt_parse(config->cert_crt, tls_server_sample_cert, tls_server_sample_cert_len); // Parse a private key in PEM or DER format. ret = mbedtls_pk_parse_key(config->pkey_ctx, tls_server_sample_key, tls_server_sample_key_len, NULL, 0); if (mbedtls_pk_get_type(config->pkey_ctx) == MBEDTLS_PK_RSA) { // Initialize an RSA-alt context. ret = mbedtls_pk_setup_rsa_alt(config->pkey_alt_ctx, (void *)mbedtls_pk_rsa(*config->pkey_ctx), tls_server_sample_rsa_decrypt_func, tls_server_sample_rsa_sign_func, tls_server_sample_rsa_key_len_func); // Import certificate & private key ret = mbedtls_ssl_conf_own_cert(config->ssl_conf, config->cert_crt, config->pkey_alt_ctx); } else { // Import certificate & private key ret = mbedtls_ssl_conf_own_cert(config->ssl_conf, config->cert_crt, config->pkey_ctx); } ret = mbedtls_ctr_drbg_seed(config->ctr_drbg_ctx, mbedtls_entropy_func, config->entropy_ctx, (const unsigned char *)pers, strlen(pers)); /* * Set the random number generator. * DA16200 SDK supports generic callback function * for the random nubmer generator. */ mbedtls_ssl_conf_rng(config->ssl_conf, mbedtls_ctr_drbg_random, config->ctr_drbg_ctx); /* * Set the authentication mode. * It determines how strictly the certificates are checked. * It, MBEDTLS_SSL_VERIFY_NONE, doesn't care verification in this sample. */ mbedtls_ssl_conf_authmode(config->ssl_conf, MBEDTLS_SSL_VERIFY_NONE); // Set up an SSL context for use. ret = mbedtls_ssl_setup(config->ssl_ctx, config->ssl_conf); // Set callback function to know network traffic User Manual CFR0012 Revision 2.2 50 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide mbedtls_ssl_set_bio(config->ssl_ctx, (void *)config, tls_server_sample_send_func, tls_server_sample_recv_func, NULL); return NX_SUCCESS; } 3.2.3.2 TLS Handshake TLS is an encryption protocol designed to secure network communication. A TLS handshake is the process that starts a communication session that uses TLS encryption. To do a TLS handshake, function tls_server_sample_do_handshake() is called. That function in turn simply calls function mbedtls_ssl_handshake() of the "mbedTLS" library. If an error occurred during the TLS handshake, the API returns specific error code. If a TLS session is established successfully, the API returns 0. The details are as follows: UINT tls_server_sample_do_handshake(tls_server_sample_conf_t *config) { // Perform the handshake while ((ret = mbedtls_ssl_handshake(config->ssl_ctx)) != 0) { if ((ret != MBEDTLS_ERR_SSL_WANT_READ) && (ret != MBEDTLS_ERR_SSL_WANT_WRITE)) { status = NX_NOT_SUCCESSFUL; break; } } return status; } 3.2.3.3 Data Transmission Encryption scrambles data so that only authorized parties can understand the information. While a TLS session is established, all application data must be encrypted to transfer application data. "MbedTLS" provides specific APIs that are helpful to encrypt and decrypt data. To write application data, function mbedtls_ssl_write() of the "mbedTLS" library is called. In this sample, function tls_server_sample_send() is called to send data to the TLS client. UINT tls_server_sample_send(tls_server_sample_conf_t *config, NX_PACKET *packet_ptr, ULONG wait_option) { ... // Write send_len application data bytes. while ((ret = mbedtls_ssl_write(config->ssl_ctx, send_data, send_len)) <= 0) { if ((ret != MBEDTLS_ERR_SSL_WANT_READ) && (ret != MBEDTLS_ERR_SSL_WANT_WRITE)) { status = NX_NOT_SUCCESSFUL; break; } } ... } To read application data, function mbedtls_ssl_read() of the "mbedTLS" library is called. In this sample, function tls_server_sample_recv() is called. When called to read application data, the User Manual CFR0012 Revision 2.2 51 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide tls_server_sample_recv_func() callback function is called to get the actual network data. This callback function is set up during TLS setup by function mbedtls_ssl_set_bio(). This sample application calls function mbedtls_ssl_read() twice to check the received data and its length. Function mbedtls_ssl_get_bytes_avail() returns the number of application data bytes that remain to be read from the current record. UINT tls_server_sample_recv(tls_server_sample_conf_t *config, NX_PACKET **packet_ptr, ULONG wait_option) { ... /* * Read at most 'len' application data bytes. * It's to check there is the received data or not. */ ret = mbedtls_ssl_read(config->ssl_ctx, NULL, NULL); /* * Return the number of application data bytes remaining * to be read from the current record. */ recv_len = mbedtls_ssl_get_bytes_avail(config->ssl_ctx); // Allocate memory to get application data. recv_buf = malloc(recv_len); /* * Read at most 'len' application data bytes. * It's to check there is the received data or not. */ ret = mbedtls_ssl_read(config->ssl_ctx, recv_buf, recv_len); ... } 3.3 TLS Server in DPM The TLS server in the DPM sample application is an example of the simplest TLS echo server application. Transport Layer Security (TLS) is a set of cryptographic protocols designed to provide secured communication over a computer network. The DA16200 SDK can work in DPM mode. The user application requires an additional operation to work in DPM mode. The DA16200 SDK provides a DPM manager feature for the user network application. The DPM manager feature offers support for the user to develop and manage a TLS network application in Non-DPM and DPM modes. This section describes how the TLS server in the DPM sample application is built and works. 3.3.1 How to Run 1. Open the workspace for the TLS Server in the DPM sample application as follows: ~/SDK/sample/Network/TLS_Server_DPM/build/DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. 3. Use the console command to set up the Wi-Fi station interface. 4. After a connection is made to an AP, the example application will create a TLS server socket with port number 10197 and wait for a client connection. 5. Run a TLS client application on the peer PC. User Manual CFR0012 Revision 2.2 52 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 3.3.2 How it Works The DA16200 TLS Server in the DPM sample is a simple echo server. When a TLS client sends a message, then the DA16200 TLS server will echo that message to the TLS client. The DA16200 TLS server will take time to wait to establish a TLS session. Figure 32: Workflow of TLS Server in DPM 3.3.3 Details 3.3.3.1 Registration The TLS server in the DPM sample application works in DPM mode. The basic code is similar to the TLS server sample application. The difference with the TLS server sample application is two things: An initial callback function is added, named tls_server_dpm_sample_wakeup_callback in the code. The function is called when the DPM state changes from sleep to wakeup An additional user configuration can be stored in RTM In this sample, the TLS server information will be stored. void tls_server_dpm_sample_init_user_config(dpm_user_config_t *user_config) { const int session_idx = 0; //Set Boot init callback user_config->bootInitCallback = tls_server_dpm_sample_init_callback; //Set DPM wakkup init callback user_config->wakeupInitCallback = tls_server_dpm_sample_wakeup_callback; //Set Error callback user_config->errorCallback = tls_server_dpm_sample_error_callback; //Set session type(TCP Server) user_config->sessionConfig[session_idx].session_type = REG_TYPE_TCP_SERVER; //Set local port user_config->sessionConfig[session_idx].session_myPort = TLS_SERVER_DPM_SAMPLE_DEF_SERVER_PORT; //Set Connection callback user_config->sessionConfig[session_idx].session_connectCallback = tls_server_dpm_sample_connect_callback; //Set Recv callback user_config->sessionConfig[session_idx].session_recvCallback = tls_server_dpm_sample_recv_callback; //Set secure mode User Manual CFR0012 Revision 2.2 53 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide user_config->sessionConfig[session_idx].supportSecure = NX_TRUE; //Set secure setup callback user_config->sessionConfig[session_idx].session_setupSecureCallback = tls_server_dpm_sample_secure_callback; //Set user configuration user_config->ptrDataFromRetentionMemory = (UCHAR *)&srv_info; user_config->sizeOfRetentionMemory = sizeof(tls_server_dpm_sample_svr_info_t); return ; } 3.3.3.2 TLS Setup In order to establish a TLS session, TLS should be set up. DA16200 includes an "mbedTLS" library to provide the TLS protocol. Most APIs that are related to the TLS protocol are based on an "mbedTLS" library. TLS will be set up by session_setupSecureCallback function. The details are as follows. void tls_server_dpm_sample_secure_callback(void *config) { const char *pers = "tls_server_dpm_sample"; SECURE_INFO_T *secure_config = (SECURE_INFO_T *)config; ret = mbedtls_ssl_config_defaults(secure_config->ssl_conf, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); //Import test certificate ret = mbedtls_x509_crt_parse(secure_config->cert_crt, tls_server_dpm_sample_cert, tls_server_dpm_sample_cert_len); ret = mbedtls_pk_parse_key(secure_config->pkey_ctx, tls_server_dpm_sample_key, tls_server_dpm_sample_key_len, NULL, 0); if (mbedtls_pk_get_type(secure_config->pkey_ctx) == MBEDTLS_PK_RSA) { ret = mbedtls_pk_setup_rsa_alt(secure_config->pkey_alt_ctx, (void *)mbedtls_pk_rsa(*secure_config- >pkey_ctx), tls_server_dpm_sample_rsa_decrypt_func, tls_server_dpm_sample_rsa_sign_func, tls_server_dpm_sample_rsa_key_len_func); ret = mbedtls_ssl_conf_own_cert(secure_config->ssl_conf, secure_config->cert_crt, secure_config->pkey_alt_ctx); } else { ret = mbedtls_ssl_conf_own_cert(secure_config->ssl_conf, secure_config->cert_crt, secure_config->pkey_ctx); } ret = mbedtls_ctr_drbg_seed(secure_config->ctr_drbg_ctx, User Manual CFR0012 Revision 2.2 54 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide mbedtls_entropy_func, secure_config->entropy_ctx, (const unsigned char *)pers, strlen(pers)); mbedtls_ssl_conf_rng(secure_config->ssl_conf, mbedtls_ctr_drbg_random, secure_config->ctr_drbg_ctx); //Don't care verification in this sample. mbedtls_ssl_conf_authmode(secure_config->ssl_conf, MBEDTLS_SSL_VERIFY_NONE); //Use Heap memory for incoming/outgoing buffer of TLS ret = mbedtls_ssl_conf_content_heap(secure_config->ssl_conf, NX_TRUE); ret = mbedtls_ssl_setup(secure_config->ssl_ctx, secure_config->ssl_conf); dpm_mng_job_done(); //Done opertaion return ; } 3.3.3.3 Data Transmission The callback function is called when a TLS packet is received from a TLS client. In this sample, the received data is printed out and an echo message is sent to the TLS server. Data will be encrypted and decrypted in the callback function. void tls_server_dpm_sample_recv_callback(void *sock, UCHAR *rx_buf, UINT rx_len, ULONG rx_ip, ULONG rx_port) { //Display received packet PRINTF(" =====> Received Packet(%ld) \n", rx_len); //Echo message status = dpm_mng_send_to_session(SESSION1, rx_ip, rx_port, (char *)rx_buf, rx_len); //Display sent packet PRINTF(" <===== Sent Packet(%ld) \n", rx_len); dpm_mng_job_done(); //Done opertaion } 3.4 TLS Client The TLS client sample application is an example of the simplest TLS echo client application. Transport Layer Security (TLS) are cryptographic protocols designed to provide secured communication over a computer network. The DA16200 SDK provides a DPM manager feature for the user network application. The DA16200 SDK provides an SSL library called "mbedTLS" on a secure H/W engine to support the TLS protocol. "MbedTLS" is one of the popular SSL libraries and helpful to easily develop a network application with a TLS protocol. This section describes how the TLS client sample application is built and works. 3.4.1 How to Run 1. Run a TLS server application on the peer PC and open a TLS server socket with port number 10196. 2. Open the workspace for the TLS Client sample application as follows: ~/SDK/sample/Network/TLS_Client/build/DA16xxx.eww User Manual CFR0012 Revision 2.2 55 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 3. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB, and reboot. 4. Use the console command to set up the Wi-Fi station interface. 5. Set the TLS server IP address and the port number as you created the socket on the peer PC with the following console command and then reboot. These parameters can also be defined in the source code. [/DA16200] # nvram.setenv TLSC_SERVER_IP 192.168.0.11 [/DA16200] # nvram.setenv TLSC_SERVER_PORT 10196 [/DA16200] # reboot 6. After a connection is made to an AP, the example application will connect to the peer. 3.4.2 How it Works The DA16200 TLS Client sample is a simple echo message. When the TLS server sends a message, then the DA16200 TLS client will echo that message to the TLS server. Figure 33: Workflow of TLS Client 3.4.3 Details DA16200 SDK provides the "mbedTLS" library. It describes how TLS client is implemented with the "mbedTLS" library and socket library. 3.4.3.1 Registration The DA16200 secure H/W engine has to be initialized with function da16x_secure_module_init() before the TLS context is initialized. Then, the TLS context is allocated and initialized in function tls_client_sample_init_ssl(). To setup a TLS session, function tls_client_sample_setup_ssl() is called as follows: UINT tls_client_sample_setup_ssl(tls_client_sample_conf_t *config) { const char *pers = "tls_client_sample"; /* * Prepare the TLS configuration by setting the endpoint and trasport type, * and loading reasonable defaults for the security parameters. */ ret = mbedtls_ssl_config_defaults(config->ssl_conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); ret = mbedtls_ctr_drbg_seed(config->ctr_drbg_ctx, mbedtls_entropy_func, config->entropy_ctx, User Manual CFR0012 Revision 2.2 56 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide (const unsigned char *)pers, strlen(pers)); /* * Set the random number generator. * DA16200 SDK supports generic callback function * for the random nubmer generator. */ mbedtls_ssl_conf_rng(config->ssl_conf, mbedtls_ctr_drbg_random, config->ctr_drbg_ctx); /* * Set the authentication mode. * It determines how strictly the certificates are checked. */ mbedtls_ssl_conf_authmode(config->ssl_conf, MBEDTLS_SSL_VERIFY_NONE); // Set up an SSL context for use. ret = mbedtls_ssl_setup(config->ssl_ctx, config->ssl_conf); // Set callback function to know network traffic mbedtls_ssl_set_bio(config->ssl_ctx, (void *)config, tls_client_sample_send_func, tls_client_sample_recv_func, NULL); return NX_SUCCESS; } 3.4.3.2 TLS Handshake TLS is an encryption protocol designed to secure network communication. A TLS handshake is the process that starts a communication session that uses TLS encryption. To do a TLS handshake, function tls_client_sample_do_handshake() is called. It simply calls the function mbedtls_ssl_handshake() of the "mbedTLS" library. If an error occurred during the TLS handshake, the API returns a specific error code. If a TLS session is established successfully, the API returns 0. UINT tls_client_sample_do_handshake(tls_client_sample_conf_t *config, ULONG wait_option) { // Perform TLS handshake while ((ret = mbedtls_ssl_handshake(config->ssl_ctx)) != 0) { if ((ret != MBEDTLS_ERR_SSL_WANT_READ) && (ret != MBEDTLS_ERR_SSL_WANT_WRITE)) { return NX_NOT_SUCCESSFUL; } } return NX_SUCCESS; } 3.4.3.3 Data Transmission Encryption scrambles data so that only authorized parties can understand the information. While a TLS session is established, all data must be encrypted to transfer application data. "mbedTLS" provides specific APIs that are helpful to encrypt and decrypt data. To write application data, function User Manual CFR0012 Revision 2.2 57 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide mbedtls_ssl_write() of the "mbedTLS" library is called. In this sample, function tls_client_sample_send() is called to send data to TLS client. UINT tls_client_sample_send(tls_client_sample_conf_t *config, NX_PACKET *packet_ptr, ULONG wait_option) { ... // Write send_len application data bytes. while ((ret = mbedtls_ssl_write(config->ssl_ctx, send_data, send_len)) <= 0) { if ((ret != MBEDTLS_ERR_SSL_WANT_READ) && (ret != MBEDTLS_ERR_SSL_WANT_WRITE)) { status = NX_NOT_SUCCESSFUL; break; } } ... } To read application data, function mbedtls_ssl_read() of the "mbedTLS" library is called. In this sample, function tls_client_sample_recv() calls the "mbedTLS" library. When called to read application data, callback function tls_client_sample_recv_func() is called to get actual network data. This callback function is set up during TLS setup by function mbedtls_ssl_set_bio(). This sample application calls function mbedtls_ssl_read() twice to check received data and its length. Function mbedtls_ssl_get_bytes_avail() returns the number of application data bytes that remain to be read from the current record. UINT tls_client_sample_recv(tls_client_sample_conf_t *config, NX_PACKET **packet_ptr, ULONG wait_option) { ... /* * Read at most 'len' application data bytes. * It's to check there is the received data or not. */ ret = mbedtls_ssl_read(config->ssl_ctx, NULL, NULL); /* * Return the number of application data bytes remaining * to be read from the current record. */ recv_len = mbedtls_ssl_get_bytes_avail(config->ssl_ctx); // Allocate memory to get application data. recv_buf = malloc(recv_len); /* * Read at most 'len' application data bytes. * It's to check there is the received data or not. */ ret = mbedtls_ssl_read(config->ssl_ctx, recv_buf, recv_len); ... } 3.5 TLS Client in DPM The TLS client in the DPM sample application is an example of the simplest TLS echo client application in DPM mode. Transport Layer Security (TLS) is a set of cryptographic protocols designed to provide secured communication over a computer network. The DA16200 SDK can work User Manual CFR0012 Revision 2.2 58 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide in DPM mode. The user application requires an additional operation to work in DPM mode. The DA16200 SDK provides a DPM manager feature for the user network application. The DPM manager feature supports the user to develop and manage the TLS network application in Non-DPM and DPM modes. This section describes how the TLS client in the DPM sample application is built and works. 3.5.1 How to Run 1. Run a TLS server application on the peer PC and open a TLS server socket with port number 10196. 2. Open the workspace for a TCP Client in the DPM sample application as follows: ~/SDK/sampleNetwork/TLS_Client/build/DA16xxx.eww 3. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB, and reboot. 4. Use the console command to set up the Wi-Fi station interface. 5. Set the TLS server IP address and the port number as you created the socket on the peer PC with the following console command and then reboot. These parameters can also be defined in the source code. [/DA16200] # nvram.setenv TLSC_SERVER_IP 192.168.0.11 [/DA16200] # nvram.setenv TLSC_SERVER_PORT 10196 [/DA16200] # reboot After a connection is made to an AP, the example application will connect to the peer PC. 3.5.2 How it Works The DA16200 TLS Client in the DPM sample is a simple echo message. When a TLS server sends a message, then the DA16200 TLS client will echo that message to the TLS server. Figure 34: Workflow of TLS Client in DPM 3.5.3 Details 3.5.3.1 Registration The TLS client in the DPM sample application works in DPM mode. The basic code is similar to the TLS client sample application. The difference with the TLS client sample application is two things: An initial callback function is added, named `tls_client_dpm_sample_wakeup_callback` in the code. It will be called when DPM state changes from sleep to wakeup An additional user configuration that can be stored in RTM In this example, TLS server information will be stored. void tls_client_dpm_sample_init_user_config(dpm_user_config_t *user_config) { const int session_idx = 0; //Set Boot init callback User Manual CFR0012 Revision 2.2 59 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide user_config->bootInitCallback = tls_client_dpm_sample_init_callback; //Set DPM wakeup init callback user_config->wakeupInitCallback = tls_client_dpm_sample_wakeup_callback; //Set External wakeup callback user_config->externWakeupCallback = tls_client_dpm_sample_external_callback; //Set Error callback user_config->errorCallback = tls_client_dpm_sample_error_callback; //Set session type(TLS Client) user_config->sessionConfig[session_idx].session_type = REG_TYPE_TCP_CLIENT; //Set local port user_config->sessionConfig[session_idx].session_myPort = DM_TLS_CLIENT_SAMPLE_DEF_CLIENT_PORT; //Set server IP address memcpy(user_config->sessionConfig[session_idx].session_serverIp, srv_info.ip_addr, strlen(srv_info.ip_addr)); //Set server port user_config->sessionConfig[session_idx].session_serverPort = srv_info.port; //Set Connection callback user_config->sessionConfig[session_idx].session_connectCallback = tls_client_dpm_sample_connect_callback; //Set Recv callback user_config->sessionConfig[session_idx].session_recvCallback = tls_client_dpm_sample_recv_callback; //Set connection retry count user_config->sessionConfig[session_idx].session_conn_retry_cnt = DM_TLS_CLIENT_SAMPLE_DEF_MAX_CONNECTION_RETRY; //Set connection timeout user_config->sessionConfig[session_idx].session_conn_wait_time = DM_TLS_CLIENT_SAMPLE_DEF_MAX_CONNECTION_TIMEOUT; //Set auto reconnection flag user_config->sessionConfig[session_idx].session_auto_reconn = NX_TRUE; //Set secure mode user_config->sessionConfig[session_idx].supportSecure = NX_TRUE; //Set secure setup callback user_config->sessionConfig[session_idx].session_setupSecureCallback = tls_client_dpm_sample_secure_callback; //Set user configuration user_config->ptrDataFromRetentionMemory = (UCHAR *)&srv_info; user_config->sizeOfRetentionMemory = sizeof(tls_client_dpm_sample_svr_info_t); return ; } User Manual CFR0012 Revision 2.2 60 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 3.5.3.2 TLS Setup In order to establish a TLS session, TLS should be set up. DA16200 includes an "mbedTLS" library to provide the TLS protocol. Most APIs that are related to the TLS protocol are based on an "mbedTLS" library. TLS will be set up by session_setupSecureCallback function. The details are as shown below. Note that this sample application does not include certificates. void tls_client_dpm_sample_secure_callback(void *config) { const char *pers = "tls_client_sample"; SECURE_INFO_T *secure_config = (SECURE_INFO_T *)config; ret = mbedtls_ssl_config_defaults(secure_config->ssl_conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); ret = mbedtls_ctr_drbg_seed(secure_config->ctr_drbg_ctx, mbedtls_entropy_func, secure_config->entropy_ctx, (const unsigned char *)pers, strlen(pers)); mbedtls_ssl_conf_rng(secure_config->ssl_conf, mbedtls_ctr_drbg_random, secure_config->ctr_drbg_ctx); //Don't care verification in this sample. mbedtls_ssl_conf_authmode(secure_config->ssl_conf, MBEDTLS_SSL_VERIFY_NONE); ret = mbedtls_ssl_setup(secure_config->ssl_ctx, secure_config->ssl_conf); dpm_mng_job_done(); //Done opertaion return ; } 3.5.3.3 Data Transmission The callback function is called when the TLS packet is received from the TLS server. In this sample, the received data is printed out and an echo message is sent to the TLS server. Data will be encrypted and decrypted in the callback function. void tls_client_dpm_sample_recv_callback(void *sock, UCHAR *rx_buf, UINT rx_len, ULONG rx_ip, ULONG rx_port) { //Display received packet PRINTF(" =====> Received Packet(%ld) \n", rx_len); //Echo message status = dpm_mng_send_to_session(SES_1, rx_ip, rx_port, (char *)rx_buf, rx_len); //Display sent packet PRINTF(" <===== Sent Packet(%ld) \n", rx_len); dpm_mng_job_done(); //Done opertaion } User Manual CFR0012 Revision 2.2 61 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 3.6 DTLS Server The DTLS server sample application is an example of the simplest DTLS echo server application. Datagram Transport Layer Security (DTLS) is a cryptographic protocol that provides security for datagram-based applications by allowing them to communicate in a way that is designed to prevent eavesdropping, tampering, or message forgery. The DA16200 SDK provides an SSL library called "mbedTLS" on a secure H/W engine to support the DTLS protocol. "mbedTLS" is one of the popular SSL libraries. "mbedTLS" is helpful to easily develop a network application with a DTLS protocol. This section describes how the DTLS server sample application is built and works. 3.6.1 How to Run 1. Open the workspace for the DTLS Server sample application as follows: ~/SDK/sample/Network/DTLS_Server/build/DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. 3. Use the console command to set up the Wi-Fi station interface. 4. After a connection is made to an AP, the example application will create a DTLS server socket with port number 10199 and wait for a client connection. 5. Run a DTLS client application on the peer PC. 3.6.2 How it Works The DA16200 DTLS Server sample is a simple echo server. When DTLS client sends a message, then the DA16200 DTLS server will echo that message to the DTLS client. Figure 35: Workflow of DTLS Server 3.6.3 Details The DA16200 SDK provides the "mbedTLS" library. This sample application describes how the "mbedTLS" library is called and applied for the socket library. 3.6.3.1 Initialization The DA16200 secure H/W engine has to be initialized with da16x_seucer_module_init() before the DTLS context is initialized. Then, the DTLS context is allocated and initialized in function dtls_server_sample_init_ssl(). To set up a DTLS session, function dtls_server_sample_setup_ssl() is called as shown in the example code below. The DTLS session is established over a UDP protocol. In case a packet is lost, retransmission is required. So, the timer is registered to retransmit packet by function mbedtls_ssl_set_timer_cb(). UINT dtls_server_sample_setup_ssl(dtls_server_sample_conf_t *config) { const char *pers = "dtls_server_sample"; /* User Manual CFR0012 Revision 2.2 62 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide * Prepare the DTLS configuration by setting the endpoint and trasport type, * and loading reasonable defaults for the security parameters. */ ret = mbedtls_ssl_config_defaults(config->ssl_conf, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_PRESET_DEFAULT); /* * Parse one DER-encoded or one or more concatenated PEM-encoded certificates * and add them to the chained list. */ ret = mbedtls_x509_crt_parse(config->cert_crt, dtls_server_sample_cert, dtls_server_sample_cert_len); /* * Parse a private key in PEM or DER format. */ ret = mbedtls_pk_parse_key(config->pkey_ctx, dtls_server_sample_key, dtls_server_sample_key_len, NULL, 0); if (mbedtls_pk_get_type(config->pkey_ctx) == MBEDTLS_PK_RSA) { // Initialize an RSA-alt context. ret = mbedtls_pk_setup_rsa_alt(config->pkey_alt_ctx, (void *)mbedtls_pk_rsa(*config->pkey_ctx), dtls_server_sample_rsa_decrypt_func, dtls_server_sample_rsa_sign_func, dtls_server_sample_rsa_key_len_func); // Import certificate & private key ret = mbedtls_ssl_conf_own_cert(config->ssl_conf, config->cert_crt, config->pkey_alt_ctx); } else { // Import certificate & private key ret = mbedtls_ssl_conf_own_cert(config->ssl_conf, config->cert_crt, config->pkey_ctx); } ret = mbedtls_ctr_drbg_seed(config->ctr_drbg_ctx, mbedtls_entropy_func, config->entropy_ctx, (const unsigned char *)pers, strlen(pers)); /* * Set the random number generator. * DA16200 SDK supports generic callback function * for the random nubmer generator. */ mbedtls_ssl_conf_rng(config->ssl_conf, mbedtls_ctr_drbg_random, config->ctr_drbg_ctx); User Manual CFR0012 Revision 2.2 63 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide // Setup cookie context ret = mbedtls_ssl_cookie_setup(config->cookie_ctx, mbedtls_ctr_drbg_random, config->ctr_drbg_ctx); // Register callbacks for DTLS cookies. mbedtls_ssl_conf_dtls_cookies(config->ssl_conf, mbedtls_ssl_cookie_write, mbedtls_ssl_cookie_check, config->cookie_ctx); /* * Set the authentication mode. * It determines how strictly the certificates are checked. */ mbedtls_ssl_conf_authmode(config->ssl_conf, MBEDTLS_SSL_VERIFY_NONE); // Set the anti-replay protection for DTLS. mbedtls_ssl_conf_dtls_anti_replay(config->ssl_conf, MBEDTLS_SSL_ANTI_REPLAY_ENABLED); mbedtls_ssl_conf_read_timeout(config->ssl_conf, DTLS_SERVER_SAMPLE_DEF_TIMEOUT * 10); // Set retransmit timeout values for the DTLS handshake. mbedtls_ssl_conf_handshake_timeout(config->ssl_conf, DTLS_SERVER_SAMPLE_HANDSHAKE_MIN_TIMEOUT * 10, DTLS_SERVER_SAMPLE_HANDSHAKE_MAX_TIMEOUT * 10); // Set an SSL context for use. ret = mbedtls_ssl_setup(config->ssl_ctx, config->ssl_conf); // Set timer mbedtls_ssl_set_timer_cb(config->ssl_ctx, &config->timer, dtls_server_sample_timer_start, dtls_server_sample_timer_get_status); // Set callback function to know network traffic mbedtls_ssl_set_bio(config->ssl_ctx, (void *)config, dtls_server_sample_send_func, NULL, dtls_server_sample_recv_func); return NX_SUCCESS; } 3.6.3.2 DTLS Handshake DTLS is an encryption protocol designed to secure network communication. A DTLS handshake is the process that starts a communication session with DTLS encryption. To do a DTLS handshake, the application calls function dtls_server_sample_do_handshake(). The DTLS server must verify cookies for the DTLS client. The DTLS client's transport-level identification information must be set up (generally an IP Address). After a ClientHello message is received, the DTLS server must set up its IP address. Then, a DTLS handshake should be retried as follows: UINT dtls_server_sample_do_handshake(dtls_server_sample_conf_t *config) { unsigned char ip_buf[16] = {0x00,}; User Manual CFR0012 Revision 2.2 64 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide process_handshake: ret = dtls_server_sample_recv_func((void *)config, NULL, 0, DTLS_SERVER_SAMPLE_CONN_TIMEOUT); // Check client's IP address if ((config->peer_info.ip_addr.nxd_ip_address.v4 == 0) || (config->peer_info.port == 0)) { return NX_NOT_SUCCESSFUL; } memcpy(ip_buf, &config->peer_info.ip_addr.nxd_ip_address.v4, sizeof(ULONG)); // Set client's transport-level identification info. ret = mbedtls_ssl_set_client_transport_id(config->ssl_ctx, ip_buf, sizeof(ULONG)); while ((ret = mbedtls_ssl_handshake(config->ssl_ctx)) != 0) { if ( (ret != MBEDTLS_ERR_SSL_WANT_READ) && (ret != MBEDTLS_ERR_SSL_WANT_WRITE)) { if (ret != MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED) { PRINTF("Failed to process dtls handshake(0x%x)\n", -ret); } status = NX_NOT_SUCCESSFUL; break; } } // Retry DTLS handshake if client's IP address is set up and // server's state is HelloVerify. if (ret == MBEDTLS_ERR_SSL_HELLO_VERIFY_REQUIRED) { status = dtls_server_sample_shutdown_ssl(config); if (status == NX_SUCCESS) { goto process_handshake; } } return status; } 3.6.3.3 Data Transmission Encryption scrambles data so that only authorized parties can understand the information. While a DTLS session is established, all data must be encrypted for transfer. "mbedTLS" provides specific APIs that are helpful to encrypt and decrypt data. To write application data, function mbedtls_ssl_write() of the "mbedTLS" library is called. In this sample, function dtls_server_sample_send() is called to send data to the DTLS client. UINT dtls_server_sample_send(dtls_server_sample_conf_t *config, NX_PACKET *packet_ptr, ULONG wait_option) { ... // Write send_len application data bytes. while ((ret = mbedtls_ssl_write(config->ssl_ctx, data, len)) <= 0) User Manual CFR0012 Revision 2.2 65 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide { if ( (ret != MBEDTLS_ERR_SSL_WANT_READ) && (ret != MBEDTLS_ERR_SSL_WANT_WRITE)) { status = NX_NOT_SUCCESSFUL; break; } } ... } To read application data, function mbedtls_ssl_read() of the "mbedTLS" library is called. In this sample, function dtls_server_sample_recv() is called. When it is called to read application data, callback function dtls_server_sample_recv_func() is called to get actual network data. This callback function is set up during DTLS setup by function mbedtls_ssl_set_bio(). This sample application calls function mbedtls_ssl_read() twice to check the received data and its length. Function mbedtls_ssl_get_bytes_avail() returns the number of application data bytes that remain to be read from the current record. UINT dtls_server_sample_recv(dtls_server_sample_conf_t *config, NX_PACKET **packet_ptr, ULONG wait_option) { ... /* * Read at most 'len' application data bytes. * It's to check there is the received data or not. */ ret = mbedtls_ssl_read(config->ssl_ctx, NULL, NULL); /* * Return the number of application data bytes remaining * to be read from the current record. */ recv_len = mbedtls_ssl_get_bytes_avail(config->ssl_ctx); // Allocate memory to get application data. recv_buf = malloc(recv_len); /* * Read at most 'len' application data bytes. * It's to check there is the received data or not. */ ret = mbedtls_ssl_read(config->ssl_ctx, recv_buf, recv_len); ... } 3.7 DTLS Server in DPM The DTLS server in the DPM sample application is an example of the simplest DTLS echo server application. Datagram Transport Layer Security (DTLS) is a cryptographic protocol that provides security for datagram-based applications by allowing them to communicate in a way that is designed to prevent eavesdropping, tampering, or message forgery. The DA16200 SDK can work in DPM mode. The user application requires an additional operation to work in DPM mode. The DA16200 SDK provides a DPM manager feature for the user network application. The DPM manager feature supports the user to develop and manage a DTLS network application in Non-DPM and DPM modes. This section describes how the DTLS server in the DPM sample application is built and works. User Manual CFR0012 Revision 2.2 66 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 3.7.1 How to Run 1. Open the workspace for the DTLS Server in the DPM sample application as follows: ~/SDK/sample/Network/DTLS_Server_DPM/build/DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. 3. Use the console command to set up the Wi-Fi station interface. 4. After a connection is made to an AP, the example application will create a DTLS server socket with port number 10199 and wait for a client connection. 5. Run a DTLS client application on the peer PC. 3.7.2 How it Works The DA16200 DTLS Server in the DPM sample is a simple echo server. When a DTLS client sends a message, then the DA16200 DTLS server will echo that message to the DTLS client. Figure 36: Workflow of DTLS Server in DPM 3.7.3 Details 3.7.3.1 Registration The DTLS server in the DPM sample application works in DPM mode. The basic code is similar to the DTLS server sample application. The difference with the DTLS server sample application is two things: An initial callback function is added, named dtls_server_dpm_sample_wakeup_callback in the code. It will be called when the DPM state changes from sleep to wakeup An additional user configuration can be stored in RTM In this sample, DTLS server information will be stored. void dtls_server_dpm_sample_init_user_config(dpm_user_config_t *user_config) { const int session_idx = 0; // Set Boot init callback user_config->bootInitCallback = dtls_server_dpm_sample_init_callback; // Set DPM wakkup init callback user_config->wakeupInitCallback = dtls_server_dpm_sample_wakeup_callback; // Set Error callback user_config->errorCallback = dtls_server_dpm_sample_error_callback; // Set session type(UDP Server) user_config->sessionConfig[session_idx].session_type = REG_TYPE_UDP_SERVER; // Set local port user_config->sessionConfig[session_idx].session_myPort = User Manual CFR0012 Revision 2.2 67 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide DTLS_SERVER_DPM_SAMPLE_DEF_SERVER_PORT; // Set Connection callback user_config->sessionConfig[session_idx].session_connectCallback = dtls_server_dpm_sample_connect_callback; // Set Recv callback user_config->sessionConfig[session_idx].session_recvCallback = dtls_server_dpm_sample_recv_callback; // Set secure mode user_config->sessionConfig[session_idx].supportSecure = NX_TRUE; // Set secure setup callback user_config->sessionConfig[session_idx].session_setupSecureCallback = dtls_server_dpm_sample_secure_callback; //Set user configuration user_config->ptrDataFromRetentionMemory = (UCHAR *)&srv_info; user_config->sizeOfRetentionMemory =sizeof(dtls_server_dpm_sample_svr_info_t); } 3.7.3.2 DTLS Setup In order to establish a DTLS session, DTLS should be set up. The DA16200 includes an "mbedTLS" library to provide the DTLS protocol. Most APIs that are related to the DTLS protocol are based on an "mbedTLS" library. DTLS will be set up by function session_setupSecureCallback. The details are as follows. void dtls_server_dpm_sample_secure_callback(void *config) { const char *pers = "dtls_server_dpm_sample"; SECURE_INFO_T *secure_config = (SECURE_INFO_T *)config; ret = mbedtls_ssl_config_defaults(secure_config->ssl_conf, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_PRESET_DEFAULT); //import test certificate ret = mbedtls_x509_crt_parse(secure_config->cert_crt, dtls_server_dpm_sample_cert, dtls_server_dpm_sample_cert_len); ret = mbedtls_pk_parse_key(secure_config->pkey_ctx, dtls_server_dpm_sample_key, dtls_server_dpm_sample_key_len, NULL, 0); if (mbedtls_pk_get_type(secure_config->pkey_ctx) == MBEDTLS_PK_RSA) { ret = mbedtls_pk_setup_rsa_alt(secure_config->pkey_alt_ctx, (void *)mbedtls_pk_rsa(*secure_config->pkey_ctx), dtls_server_dpm_sample_rsa_decrypt_func, dtls_server_dpm_sample_rsa_sign_func, dtls_server_dpm_sample_rsa_key_len_func); ret = mbedtls_ssl_conf_own_cert(secure_config->ssl_conf, secure_config->cert_crt, secure_config->pkey_alt_ctx); User Manual CFR0012 Revision 2.2 68 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide } else { ret = mbedtls_ssl_conf_own_cert(secure_config->ssl_conf, secure_config->cert_crt, secure_config->pkey_ctx); } ret = mbedtls_ctr_drbg_seed(secure_config->ctr_drbg_ctx, mbedtls_entropy_func, secure_config->entropy_ctx, (const unsigned char *)pers, strlen(pers)); mbedtls_ssl_conf_rng(secure_config->ssl_conf, mbedtls_ctr_drbg_random, secure_config->ctr_drbg_ctx); ret = mbedtls_ssl_cookie_setup(secure_config->cookie_ctx, mbedtls_ctr_drbg_random, secure_config->ctr_drbg_ctx); mbedtls_ssl_conf_dtls_cookies(secure_config->ssl_conf, mbedtls_ssl_cookie_write, mbedtls_ssl_cookie_check, secure_config->cookie_ctx); // Don't care verification in this sample. mbedtls_ssl_conf_authmode(secure_config->ssl_conf, MBEDTLS_SSL_VERIFY_NONE); mbedtls_ssl_conf_max_frag_len(secure_config->ssl_conf, 0); mbedtls_ssl_conf_dtls_anti_replay(secure_config->ssl_conf, MBEDTLS_SSL_ANTI_REPLAY_ENABLED); mbedtls_ssl_conf_read_timeout(secure_config->ssl_conf, DTLS_SERVER_DPM_SAMPLE_RECEIVE_TIMEOUT * 10); mbedtls_ssl_conf_handshake_timeout(secure_config->ssl_conf, DTLS_SERVER_DPM_SAMPLE_HANDSHAKE_MIN_TIMEOUT * 10, DTLS_SERVER_DPM_SAMPLE_HANDSHAKE_MAX_TIMEOUT * 10); ret = mbedtls_ssl_setup(secure_config->ssl_ctx, secure_config->ssl_conf); dpm_mng_job_done(); // Done opertaion return ; } 3.7.3.3 Data Transmission The callback function will be called when a DTLS packet is received from the DTLS client. In this example, the received data is printed out and an echo message is sent to the DTLS server. Data will be encrypted and decrypted in the callback function. void dtls_server_dpm_sample_recv_callback(void *sock, UCHAR *rx_buf, UINT rx_len, ULONG rx_ip, ULONG rx_port) { //Display received packet PRINTF(" =====> Received Packet(%ld) \n", rx_len); //Echo message status = dpm_mng_send_to_session(SESSION1, rx_ip, rx_port, (char *)rx_buf, User Manual CFR0012 Revision 2.2 69 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide rx_len); //Display sent packet PRINTF(" <===== Sent Packet(%ld) \n", rx_len); dpm_mng_job_done(); //Done opertaion } 3.8 DTLS Client The DTLS client sample application is an example of the simplest DTLS echo client application. Datagram Transport Layer Security (DTLS) is a cryptographic protocol that provides security for datagram-based applications by allowing them to communicate in a way that is designed to prevent eavesdropping, tampering, or message forgery. The DA16200 SDK provides an SSL library called "mbedTLS" on a secure H/W engine to support the DTLS protocol. "mbedTLS" is one of the popular SSL libraries. "mbedTLS" is helpful to easily develop a network application with the DTLS protocol. This section describes how the DTLS client sample application is built and works. 3.8.1 How to Run 1. Run a DTLS server application on the peer PC and open a DTLS server socket with port number 10199. 2. Open the workspace for the DTLS Client sample application as follows: ~/SDK/sample/Network/DTLS_Client/build/DA16xxx.eww 3. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB, and reboot. 4. Use the console command to set up the Wi-Fi station interface. 5. Set the DTLS server IP address and the port number as you created the socket on the peer PC with the following console command and then reboot. These parameters can also be defined in the source code. [/DA16200] # nvram.setenv DTLSC_SERVER_IP 192.168.0.11 [/DA16200] # nvram.setenv DTLSC_SERVER_PORT 10199 [/DA16200] # reboot After a connection is made to an AP, the sample application will connect to the peer PC. 3.8.2 How it Works The DA16200 DTLS Client sample is a simple echo message. When the DTLS server sends a message, then the DA16200 DTLS client will echo that message to the DTLS server. User Manual CFR0012 Figure 37: Workflow of DTLS Client Revision 2.2 70 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 3.8.3 Details The DA16200 SDK provides an "mbedTLS" library. This sample application describes how an "mbedTLS" library is called and applied for the socket library. 3.8.3.1 Initialization The DA16200 secure H/W engine has to be initialized with da16x_seucer_module_init() before the DTLS context is initialized. Then, the DTLS context is allocated and initialized in function dtls_client_sample_init_ssl(). To set up a DTLS session, function dtls_client_sample_setup_ssl() is called as shown in the code example below. A DTLS session is established over the UDP protocol. If a packet is lost, then retransmission is required. So, the timer is registered to retransmit the packet by function mbedtls_ssl_set_timer_cb(). UINT dtls_client_sample_setup_ssl(dtls_client_sample_conf_t *config) { const char *pers = "dtls_client_sample"; /* * Prepare the DTLS configuration by setting the endpoint and trasport type, * and loading reasonable defaults for the security parameters. */ ret = mbedtls_ssl_config_defaults(config->ssl_conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_PRESET_DEFAULT); ret = mbedtls_ctr_drbg_seed(config->ctr_drbg_ctx, mbedtls_entropy_func, config->entropy_ctx, (const unsigned char *)pers, strlen(pers)); /* * Set the random number generator. * DA16200 SDK supports generic callback function * for the random nubmer generator. */ mbedtls_ssl_conf_rng(config->ssl_conf, mbedtls_ctr_drbg_random, config->ctr_drbg_ctx); /* * Set the authentication mode. * It determines how strictly the certificates are checked. */ mbedtls_ssl_conf_authmode(config->ssl_conf, MBEDTLS_SSL_VERIFY_NONE); // Set the anti-replay protection for DTLS. mbedtls_ssl_conf_dtls_anti_replay(config->ssl_conf, MBEDTLS_SSL_ANTI_REPLAY_ENABLED); mbedtls_ssl_conf_read_timeout(config->ssl_conf, DTLS_CLIENT_SAMPLE_DEF_TIMEOUT * 10); // Set retransmit timeout values for the DTLS handshake. mbedtls_ssl_conf_handshake_timeout(config->ssl_conf, DTLS_CLIENT_SAMPLE_HANDSHAKE_MIN_TIMEOUT * 10, DTLS_CLIENT_SAMPLE_HANDSHAKE_MAX_TIMEOUT * 10); // Set an SSL context for use. User Manual CFR0012 Revision 2.2 71 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide ret = mbedtls_ssl_setup(config->ssl_ctx, config->ssl_conf); // Set timer mbedtls_ssl_set_timer_cb(config->ssl_ctx, &config->timer, dtls_client_sample_timer_start, dtls_client_sample_timer_get_status); // Set callback function to know network traffic. mbedtls_ssl_set_bio(config->ssl_ctx, (void *)config, dtls_client_sample_send_func, NULL, dtls_client_sample_recv_func); return NX_SUCCESS; } 3.8.3.2 DTLS Handshake DTLS is an encryption protocol designed to secure network communication. A DTLS handshake is the process that starts a communication session that uses DTLS encryption. To do a DTLS handshake, function dtls_client_sample_do_handshake() is called. If an error occurs during a DTLS handshake, the API returns the specific error code. If a DTLS session is established successfully, the API returns 0. UINT dtls_client_sample_do_handshake(dtls_client_sample_conf_t *config) { while ((ret = mbedtls_ssl_handshake(config->ssl_ctx)) != 0) { if ((ret != MBEDTLS_ERR_SSL_WANT_READ) && (ret != MBEDTLS_ERR_SSL_WANT_WRITE)) { break; } } return status; } 3.8.3.3 Data Transmission Encryption scrambles data so that only authorized parties can understand the information. While a DTLS session is established, all data must be encrypted to transfer application data. "mbedTLS" provides specific APIs that are helpful to encrypt and decrypt data. To write application data, call function mbedtls_ssl_write() of the "mbedTLS" library. In this sample, function dtls_client_sample_send() is called to send data to the DTLS client. UINT dtls_server_sample_send(dtls_server_sample_conf_t *config, NX_PACKET *packet_ptr, ULONG wait_option) { ... // Write send_len application data bytes. while ((ret = mbedtls_ssl_write(config->ssl_ctx, data, len)) <= 0) { if ((ret != MBEDTLS_ERR_SSL_WANT_READ) && (ret != MBEDTLS_ERR_SSL_WANT_WRITE)) { status = NX_NOT_SUCCESSFUL; User Manual CFR0012 Revision 2.2 72 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide break; } } ... } To read application data, function mbedtls_ssl_read() of the "mbedTLS" library is called. In this sample, function dtls_client_sample_recv() is called. When called to read application data, callback function dtls_client_sample_recv_func() is called to get actual network data. This callback function is set up during DTLS setup by function mbedtls_ssl_set_bio(). This sample application calls function mbedtls_ssl_read() twice to check the received data and its length. Function mbedtls_ssl_get_bytes_avail() returns the number of application data bytes that remain to be read from the current record. UINT dtls_client_sample_recv(dtls_client_sample_conf_t *config, NX_PACKET **packet_ptr, ULONG wait_option) { ... // Read at most 'len' application data bytes. It's to check there is the received data or not. ret = mbedtls_ssl_read(config->ssl_ctx, NULL, NULL); // Return the number of application data bytes remaining to be read from the current record. recv_len = mbedtls_ssl_get_bytes_avail(config->ssl_ctx); // Allocate memory to get remaining data. recv_buf = malloc(recv_len); // Read at most 'len' application data bytes. It's actually to read application data. ret = mbedtls_ssl_read(config->ssl_ctx, recv_buf, recv_len); ... } 3.9 DTLS Client in DPM The DTLS client in the DPM sample application is an example of the simplest DTLS echo client application in DPM mode. Datagram Transport Layer Security (DTLS) is a cryptographic protocol that provides security for datagram-based applications by allowing them to communicate in a way that is designed to prevent eavesdropping, tampering, or message forgery. The DA16200 SDK can work in DPM mode. The user application requires an additional operation to work in DPM mode. The DA16200 SDK provides the DPM manager feature for the user network application. The DPM manager feature supports the user to develop and manage a DTLS network application in Non-DPM and DPM modes. This section describes how the DTLS client in the DPM sample application is built and works. 3.9.1 How to Run 1. Run a DTLS server application on the peer PC and open a DTLS server socket with port number 10199. 2. Open the workspace for the DTLS Client in the DPM sample application as follows: ~/SDK/sample/Network/DTLS_Client_DPM/build/DA16xxx.eww 3. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB, and reboot. 4. Use the console command to set up the Wi-Fi station interface. User Manual CFR0012 Revision 2.2 73 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 5. Set the DTLS server IP address and the port number as you created the socket on the peer PC with the following console command and then reboot. These parameters can also be defined in the source code. [/DA16200] # nvram.setenv DTLSC_SERVER_IP 192.168.0.11 [/DA16200] # nvram.setenv DTLSC_SERVER_PORT 10199 [/DA16200] # reboot After a connection is made to an AP, the sample application will connect to the peer PC. 3.9.2 How it Works The DA16200 DTLS Client in the DPM sample is a simple echo message. When the DTLS server sends a message, then the DA16200 DTLS client will echo that message to the DTLS server. Figure 38: Workflow of DTLS Client in DPM 3.9.3 Details 3.9.3.1 Registration The DTLS client in the DPM sample application works in DPM mode. The basic code is similar to the DTLS client sample application. The difference with the DTLS client sample application is two things: An initial callback function is added, named `dtls_client_dpm_sample_wakeup_callback` in the code. It will be called when the DPM state changes from sleep to wakeup An additional user configuration can be stored in RTM In this sample, DTLS server information will be stored. void dtls_client_dpm_sample_init_user_config(dpm_user_config_t *user_config) { const int session_idx = 0; //Set Boot init callback user_config->bootInitCallback = dtls_client_dpm_sample_init_callback; //Set DPM wakeup init callback user_config->wakeupInitCallback = dtls_client_dpm_sample_wakeup_callback; //Set Error callback user_config->errorCallback = dtls_client_dpm_sample_error_callback; //Set session type(UDP Client) user_config->sessionConfig[session_idx].session_type = REG_TYPE_UDP_CLIENT; //Set local port user_config->sessionConfig[session_idx].session_myPort = DTLS_CLIENT_DPM_SAMPLE_DEF_CLIENT_PORT; User Manual CFR0012 Revision 2.2 74 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide //Set server IP address memcpy(user_config->sessionConfig[session_idx].session_serverIp, srv_info.ip_addr, strlen(srv_info.ip_addr)); //Set server port user_config->sessionConfig[session_idx].session_serverPort = srv_info.port; //Set Connection callback user_config->sessionConfig[session_idx].session_connectCallback = dtls_client_dpm_sample_connect_callback; //Set Recv callback user_config->sessionConfig[session_idx].session_recvCallback = dtls_client_dpm_sample_recv_callback; //Set secure mode user_config->sessionConfig[session_idx].supportSecure = NX_TRUE; //Set secure setup callback user_config->sessionConfig[session_idx].session_setupSecureCallback = dtls_client_dpm_sample_secure_callback; //Set user configuration user_config->ptrDataFromRetentionMemory = (UCHAR *)&srv_info; user_config->sizeOfRetentionMemory = sizeof(dtls_client_dpm_sample_svr_info_t); return ; } 3.9.3.2 DTLS Setup In order to establish a DTLS session, DTLS should be set up. The DA16200 includes an "mbedTLS" library to provide the DTLS protocol. Most APIs that are related to the DTLS protocol are based on an "mbedTLS" library. DTLS will be set up by function session_setupSecureCallback. The details are as shown below. Note that this sample application does not include certificates. void dtls_client_dpm_sample_secure_callback(void *config) { const char *pers = "dtls_client_dpm_sample"; SECURE_INFO_T *secure_config = (SECURE_INFO_T *)config; ret = mbedtls_ssl_config_defaults(secure_config->ssl_conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_PRESET_DEFAULT); ret = mbedtls_ctr_drbg_seed(secure_config->ctr_drbg_ctx, mbedtls_entropy_func, secure_config->entropy_ctx, (const unsigned char *)pers, strlen(pers)); mbedtls_ssl_conf_rng(secure_config->ssl_conf, mbedtls_ctr_drbg_random, secure_config->ctr_drbg_ctx); //Don't care verification in this sample. mbedtls_ssl_conf_authmode(secure_config->ssl_conf, MBEDTLS_SSL_VERIFY_NONE); mbedtls_ssl_conf_max_frag_len(secure_config->ssl_conf, 0); User Manual CFR0012 Revision 2.2 75 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide mbedtls_ssl_conf_dtls_anti_replay(secure_config->ssl_conf, MBEDTLS_SSL_ANTI_REPLAY_ENABLED); mbedtls_ssl_conf_read_timeout(secure_config->ssl_conf, DTLS_CLIENT_DPM_SAMPLE_RECEIVE_TIMEOUT * 10); mbedtls_ssl_conf_handshake_timeout(secure_config->ssl_conf, DTLS_CLIENT_DPM_SAMPLE_HANDSHAKE_MIN_TIMEOUT * 10, DTLS_CLIENT_DPM_SAMPLE_HANDSHAKE_MAX_TIMEOUT * 10); ret = mbedtls_ssl_setup(secure_config->ssl_ctx, secure_config->ssl_conf); dpm_mng_job_done(); //Done opertaion return ; } 3.9.3.3 Data Transmission The callback function is called when a DTLS packet is received from the DTLS server. In this sample, the received data is printed out and an echo message is sent to the DTLS server. Data will be encrypted and decrypted in the callback function. void dtls_client_dpm_sample_recv_callback(void *sock, UCHAR *rx_buf, UINT rx_len, ULONG rx_ip, ULONG rx_port) { //Display received packet PRINTF(" =====> Received Packet(%ld) \n", rx_len); //Echo message status = dpm_mng_send_to_session(SESSION1, rx_ip, rx_port, (char *)rx_buf, rx_len); //Display sent packet PRINTF(" <===== Sent Packet(%ld) \n", rx_len); dpm_mng_job_done(); //Done opertaion } User Manual CFR0012 Revision 2.2 76 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 4 Network Examples: Protocols / Applications 4.1 CoAP Client 4.1.1 Test DUT The Test DUT runs a CoAP server application. In this section, a self-implemented CoAP server application is used to demonstrate the DA16200 CoAP client sample application. The sample application is based on Eclipse Californium (https://www.eclipse.org/californium/) and runs on a Windows OS as shown in Figure 39. Figure 39: Start of CoAP Server Application The CoAP server application is a simple CoAP server. It has two resources, called \res and \obs_res. The "res" resource allows GET, POST, PUT, DELETE, and PING methods. The "obs_res" resource allows OBSERVE request and sends an observe notification every ten seconds. 4.1.2 How to Run 1. Run a CoAP server application on the peer PC. 2. Open the workspace for the CoAP Client application as follows: ~/SDK/sample/Network/CoAP_Client/build/DA16xxx.eww 3. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. 4. Use the console command to set up the Wi-Fi station interface. After a connection is made to an AP, the example application will initialize a CoAP client to start the service. 4.1.3 CoAP Client Initialization This section explains how to initialize and construct a CoAP client. UINT coap_client_sample_init_config(coap_client_sample_config *config) { coap_client_t *coap_client_ptr = &config->coap_client; get_thread_netx((void **)&config->pool_ptr, (void **)&config->ip_ptr, WLAN0_IFACE); config->state = COAP_CLIENT_SAMPLE_STATE_SUSPEND; //Init coap client. status = coap_client_init(coap_client_ptr, COAP_CLIENT_SAMPLE_NAME, config->ip_ptr, config->pool_ptr); //Set auth mode to skip certificate validity check. coaps_client_set_authmode(coap_client_ptr, NX_FALSE); //Set request and observe ports. config->req_port = COAP_CLIENT_SAMPLE_REQUEST_PORT; User Manual CFR0012 Revision 2.2 77 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide config->obs_port = COAP_CLIENT_SAMPLE_OBSERVE_PORT; return status; } The coap_client_sample_init_config function guides how the CoAP client is initialized. The coap_client_init function initializes the CoAP Client instance. If a CoAP observe relation is already established in DPM wakeup, then it is recovered. The API's details are as follows: UINT coap_client_init(coap_client_t *client_ptr, CHAR *name_ptr, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr) Prototype Description Parameters Return values UINT coap_client_init(coap_client_t *client_ptr, CHAR *name_ptr, NX_IP *ip_ptr, NX_PACKET_POOL *pool_ptr) Initialize CoAP Client. client_ptr: CoAP Client instance pointer name_ptr: Name of CoAP Client ip_ptr: IP instance pointer poo_ptr: Pool to allocate packet from 0(NX_SUCCESS) on success UINT coaps_client_set_authmode(coap_client_t *client_ptr, UINT mode) Prototype Description Parameters Return values UINT coaps_client_set_authmode(coap_client_t *client_ptr, UINT mode) If true, DTLS Server's certificate validity will be checked during DTLS handshake. Default is false. client_ptr: CoAP Client instance pointer mode: DTLS's auth mode 0(NX_SUCCESS) on success 4.1.4 CoAP Client Deinitialization This section explains how to deinitialize the CoAP client. UINT coap_client_sample_deinit_config(coap_client_sample_config *config) { coap_client_t *coap_client_ptr = &config->coap_client; //Deinit coap client. status = coap_client_deinit(coap_client_ptr); //Release User's CoAP request information. status = coap_client_sample_clear_request(&config->request); return retval; } The coap_client_deinit function deinitalizes the CoAP client. The API's details are as follows. UINT coap_client_deinit(coap_client_t *client_ptr) Prototype UINT coap_client_deinit(coap_client_t *client_ptr) Description Deinitialize CoAP Client. Parameters client_ptr: CoAP Client instance pointer Return 0(NX_SUCCESS) on success values User Manual CFR0012 Revision 2.2 78 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 4.1.5 CoAP Client Request and Response The DA16200 provides a CoAP client request (GET/POST/PUT/DELETE/PING) and response. In this section, we describe how the DA16200 sends the CoAP request to the CoAP server and receives the CoAP response. 4.1.5.1 CoAP URI and Proxy-URI To transmit a CoAP request and response, a URI must be set up. DA16200 provides APIs, such as: UINT coap_client_set_uri(coap_client_t *client_ptr, unsigned char *uri, size_t urilen) Prototype Description Parameters Return values UINT coap_client_set_uri(coap_client_t *client_ptr, unsigned char *uri, size_t urilen) Setup URI. client_ptr: CoAP Client instance pointer uri: URI of CoAP request uri_len: Length of URI 0(NX_SUCCESS) on success UINT coap_client_set_proxy_uri(coap_client_t *client_ptr, unsigned char *uri, size_t urilen) Prototype Description Parameters Return values UINT coap_client_set_proxy_uri(coap_client_t *client_ptr, unsigned char *uri, size_t urilen) Setup Proxy-URI. If uri is NULL, previous Proxy-URI is removed client_ptr: CoAP Client instance pointer uri: Proxy-URI of CoAP request uri_len: Length of URI 0(NX_SUCCESS) on success 4.1.5.2 GET Method The DA16200 provides an API to send a GET request as shown in the example code. UINT coap_client_sample_request_get(coap_client_sample_config *config) { coap_client_t *coap_client_ptr = &config->coap_client; coap_client_sample_request *request_ptr = &config->request; coap_rw_packet_t resp_packet; //Set URI. status = coap_client_set_uri(coap_client_ptr, (unsigned char *)request_ptr->uri, request_ptr->urilen); //Set Proxy-URI. If null, previous proxy uri will be removed. status = coap_client_set_proxy_uri(coap_client_ptr, (unsigned char *)request_ptr->proxy_uri, request_ptr->proxy_urilen); //Send coap request status = coap_client_request_get_with_port(coap_client_ptr, config->req_port); //Receive coap response status = coap_client_recv_response(coap_client_ptr, &resp_packet); //Display output if response includes payload. if (resp_packet.payload.len) { coap_client_sample_hexdump("GET Request", resp_packet.payload.p, User Manual CFR0012 Revision 2.2 79 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide resp_packet.payload.len); } //Release coap response. coap_clear_rw_packet(&resp_packet); return status; } The CoAP GET request is generated and sent in function coap_client_request_get_with_port. A CoAP response is received in function coap_client_recv_response. The API's details are as follows: UINT coap_client_request_get_with_port(coap_client_t *client_ptr, UINT port) Prototype Description Parameters Return values UINT coap_client_request_get_with_port(coap_client_t *client_ptr, UINT port) CoAP Client sends GET request client_ptr: CoAP Client instance pointer port: UDP socket's local port number 0(NX_SUCCESS) on success The DA16200 CoAP client sample application provides a command to send a GET request to the CoAP server. Figure 40, Figure 41, and Figure 42 show the interaction of two DA16200 CoAP clients with the CoAP server for a get request. Figure 40: GET Method of CoAP Client #1 Figure 41: GET Method of CoAP Client #2 Figure 42: GET Method of CoAP Client #3 4.1.5.3 POST Method DA16200 provides an API to send a POST request as shown in the example code. UINT coap_client_sample_request_post(coap_client_sample_config *config) { coap_client_t *coap_client_ptr = &config->coap_client; coap_client_sample_request *request_ptr = &config->request; coap_rw_packet_t resp_packet; // Set URI. User Manual CFR0012 Revision 2.2 80 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide status = coap_client_set_uri(coap_client_ptr, (unsigned char *)request_ptr->uri, request_ptr->urilen); // Set Proxy-URI. If null, previous proxy uri will be removed. status = coap_client_set_proxy_uri(coap_client_ptr, (unsigned char *)request_ptr->proxy_uri, request_ptr->proxy_urilen); // Send coap request. status = coap_client_request_post_with_port(coap_client_ptr, config->req_port, request_ptr->data, request_ptr->datalen); // Receive coap response. status = coap_client_recv_response(coap_client_ptr, &resp_packet); // Display output if response includes payload. if (resp_packet.payload.len) { coap_client_sample_hexdump("POST Request", resp_packet.payload.p, resp_packet.payload.len); } // Release coap response. coap_clear_rw_packet(&resp_packet); return status; } A CoAP POST request is generated and sent in function coap_client_request_post_with_port. A CoAP response is received in function coap_client_recv_response. The API's details are as follows. UINT coap_client_request_post_with_port(coap_client_t *client_ptr, UINT port, unsigned char * payload, unsigned int payload_len) Prototype Description Parameters Return values UINT coap_client_request_post_with_port(coap_client_t *client_ptr, UINT port, unsigned char *payload, unsigned int payload_len) CoAP Client sends POST request client_ptr: CoAP Client instance pointer port: UDP socket's local port number payload: Payload pointer payload_len: Length of payload 0(NX_SUCCESS) on success The DA16200 CoAP client sample application has a command to send a POST request to a CoAP server. Figure 43, Figure 44, and Figure 45 show the interaction of two DA16200 CoAP clients with the CoAP server for a POST request. Figure 43: POST Method of CoAP Client #1 User Manual CFR0012 Revision 2.2 81 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide Figure 44: POST Method of CoAP Client #2 Figure 45: POST Method of CoAP Client #3 4.1.5.4 PUT Method DA16200 provides an API to send a PUT request as shown in the example code. UINT coap_client_sample_request_put(coap_client_sample_config *config) { coap_client_t *coap_client_ptr = &config->coap_client; coap_client_sample_request *request_ptr = &config->request; coap_rw_packet_t resp_packet; //Set URI. status = coap_client_set_uri(coap_client_ptr, (unsigned char *)request_ptr->uri, request_ptr->urilen); //Set Proxy-URI. If null, previous proxy uri will be removed. status = coap_client_set_proxy_uri(coap_client_ptr, (unsigned char *)request_ptr->proxy_uri, request_ptr->proxy_urilen); //Send coap request. status = coap_client_request_put_with_port(coap_client_ptr, config->req_port, request_ptr->data, request_ptr->datalen); //Receive coap response. status = coap_client_recv_response(coap_client_ptr, &resp_packet); //Display output if response includes payload. if (resp_packet.payload.len) { coap_client_sample_hexdump("PUT Request", resp_packet.payload.p, resp_packet.payload.len); } //Release coap response. coap_clear_rw_packet(&resp_packet); return status; } The CoAP PUT request is generated and sent in function coap_client_request_put_with_port. A CoAP response is received in function coap_client_recv_response. The API's details are as follows. UINT coap_client_request_put_with_port(coap_client_t *client_ptr, UINT port, unsigned char *payload, unsigned int payload_len) Prototype UINT coap_client_request_put_with_port(coap_client_t *client_ptr, UINT port, unsigned char *payload, unsigned int payload_len) User Manual CFR0012 Revision 2.2 82 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide Description Parameters Return values CoAP Client sends PUT request client_ptr: CoAP Client instance pointer port: UDP socket's local port number payload: Payload pointer payload_len: Length of payload 0(NX_SUCCESS) on success The DA16200 CoAP client sample application provides a command to send a PUT request to the CoAP server. Figure 46, Figure 47, and Figure 48 show the interaction of two DA16200 CoAP clients and the CoAP server for put requests. Figure 46: PUT Method of CoAP Client #1 Figure 47: PUT Method of CoAP Client #2 Figure 48: PUT Method of CoAP Client #3 4.1.5.5 DELETE Method DA16200 provides an API to send a DELETE request as shown in the example code. UINT coap_client_sample_request_delete(coap_client_sample_config *config) { coap_client_t *coap_client_ptr = &config->coap_client; coap_client_sample_request *request_ptr = &config->request; coap_rw_packet_t resp_packet; //Set URI. status = coap_client_set_uri(coap_client_ptr, (unsigned char *)request_ptr->uri, request_ptr->urilen); //Set Proxy-URI. If null, previous proxy uri will be removed. status = coap_client_set_proxy_uri(coap_client_ptr, (unsigned char *)request_ptr->proxy_uri, request_ptr->proxy_urilen); //Send coap request. status = coap_client_request_delete_with_port(coap_client_ptr, config>req_port); //Receive coap response. status = coap_client_recv_response(coap_client_ptr, &resp_packet); User Manual CFR0012 Revision 2.2 83 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide //Display output if response includes payload. if (resp_packet.payload.len) { coap_client_sample_hexdump("DELETE Request", resp_packet.payload.p, resp_packet.payload.len); } //Release coap response. coap_clear_rw_packet(&resp_packet); return status; } A CoAP DELETE request is generated and sent in function coap_client_request_delete_with_port. A CoAP response is received in function coap_client_recv_response. The API's details are as follows. UINT coap_client_request_delete_with_port(coap_client_t *client_ptr, UINT port) Prototype Description Parameters Return values UINT coap_client_request_delete_with_port(coap_client_t *client_ptr, UINT port) CoAP Client sends DELETE request to the URI client_ptr: CoAP Client instance pointer port: UDP socket's local port number 0(NX_SUCCESS) on success DA16200 CoAP client sample application provides a command to send a DELETE request to the CoAP server. Figure 49, Figure 50, and Figure 51 show the interaction of a DA16200 CoAP client and the CoAP server for a delete request. Figure 49: DELETE Method of CoAP Client #1 Figure 50: DELETE Method of CoAP Client #2 Figure 51: DELETE Method of CoAP Client #3 4.1.5.6 CoAP PING DA16200 provides an API to send a PING request as shown in the example code. UINT coap_client_sample_request_ping(coap_client_sample_config *config) { coap_client_t *coap_client_ptr = &config->coap_client; coap_client_sample_request *request_ptr = &config->request; //Set URI. User Manual CFR0012 Revision 2.2 84 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide status = coap_client_set_uri(coap_client_ptr, (unsigned char *)request_ptr->uri, request_ptr->urilen); //Set Proxy-URI. If null, previous proxy uri will be removed. status = coap_client_set_proxy_uri(coap_client_ptr, (unsigned char *)request_ptr->proxy_uri, request_ptr->proxy_urilen); //Progress ping request. status = coap_client_ping_with_port(coap_client_ptr, config->req_port); return status; } A CoAP PING request is processed in function coap_client_ping_with_port. The API's details are as follows. UINT coap_client_ping_with_port(coap_client_t *client_ptr, UINT port) Prototype Description Parameters Return values UINT coap_client_ping_with_port(coap_client_t *client_ptr, UINT port) CoAP Client sends PING request client_ptr: CoAP Client instance pointer port: UDP socket's local port number 0(NX_SUCCESS) on success The DA16200 CoAP client sample application has a command to send a PING method to the CoAP server. Figure 52 and Figure 53 shows the interaction of the DA16200 CoAP client and the CoAP server for a PING request. Figure 52: PING Method of CoAP Client #1 Figure 53: PING Method of CoAP Client #2 4.1.5.7 CoAP Response DA16200 constructs a CoAP response in coap_rw_packet_t structure. In this section, details are given of how a CoAP response is constructed. ~/SDK/src/coap/coap_common.h typedef struct { /// Version number uint8_t version; /// Message type uint8_t type; /// Token length uint8_t token_len; /// Status code uint8_t code; /// Message-ID uint8_t msg_id[2]; } coap_header_t; User Manual CFR0012 Revision 2.2 85 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide typedef struct { /// Option number uint8_t num; /// Option value coap_rw_buffer_t buf; } coap_rw_option_t; typedef struct { /// Header of the packet coap_header_t header; /// Token value, size as specified by header.token_len coap_rw_buffer_t token; /// Number of options uint8_t numopts; /// Options of the packet coap_rw_option_t opts[MAXOPT]; /// Payload carried by the packet coap_rw_buffer_t payload; } coap_rw_packet_t; The coap_rw_packet_t structure includes the CoAP response information. After CoAP response is received, DA16200 parses and constructs it. The coap_rw_packet_t structure can be released as API: void coap_clear_rw_packet(coap_rw_packet_t *packet) Prototype Description Parameters Return values void coap_clear_rw_packet(coap_rw_packet_t *packet) Release coap_rw_packet structure packet: data pointer to release 0(NX_SUCCESS) on success To receive a CoAP response, DA16200 provides an API that is mentioned below. The API must be called after a CoAP requests to send a response. UINT coap_client_recv_response(coap_client_t *client_ptr, coap_rw_packet_t *resp_ptr) Prototype Description Parameters Return values UINT coap_client_recv_response(coap_client_t *client_ptr, coap_rw_packet_t *resp_ptr) Receive CoAP response for specific CoAP request client_ptr: CoAP Client instance pointer resp_ptr: CoAP response 0(NX_SUCCESS) on success 4.1.6 CoAP Observe DA16200 provides a CoAP observe functionality. After registration at a CoAP server, DA16200 (CoAP client) is ready to receive an observe notification. This section describes how CoAP observe is registered and deregistered at a CoAP server. 4.1.6.1 Registration DA16200 provides an API to register a CoAP observe as shown in the example code. UINT coap_client_sample_register_observe(coap_client_sample_config *config) { Coap_client_t *coap_client_ptr = &config->coap_client; coap_client_sample_request *request_ptr = &config->request; //set URI. User Manual CFR0012 Revision 2.2 86 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide status = coap_client_set_uri(coap_client_ptr, (unsigned char *)request_ptr->uri, request_ptr->urilen); //set Proxy-URI. If null, previous proxy uri will be removed. status = coap_client_set_proxy_uri(coap_client_ptr, (unsigned char *)request_ptr->proxy_uri, request_ptr->proxy_urilen); //Register coap observe. status = coap_client_set_observe_notify_with_port( coap_client_ptr, config->obs_port, coap_client_sample_observe_notify, coap_client_sample_observe_close_notify); return status; } A DA16200 CoAP observe allows only one connection. After successful registration, a DA16200 CoAP client allows to receive an observe notification. When the observe notification is received, the callback function (observe_notify) is called. If there is no observe notification during the max-age, the close callback function (observe_close_notify) is called. The API's details are as follows. UINT coap_client_set_observe_notify_with_port(coap_client_t *client_ptr, UINT port, UINT (*observe_notify)(VOID *client_ptr, coap_rw_packet_t *resp_ptr), void (*observe_close_notify)(void)) Prototype Description Parameters Return values UINT coap_client_set_observe_notify_with_port(coap_client_t *client_ptr, UINT port, UINT (*observe_notify)(VOID *client_ptr, coap_rw_packet_t *resp_ptr), void (*observe_close_notify)(void)) Register CoAP observe. The callback function, observe_notify, will be called when CoAP observe notification is received client_ptr: CoAP Client instance pointer port: UDP socket's local port number observe_notify: Callback function for CoAP observe notification observe_close_notify: Callback function for CoAP observe closing 0(NX_SUCCESS) on success The DA16200 CoAP client sample application has a command for CoAP observe. Figure 54, Figure 55, and Figure 56 show the interaction of a DA16200 CoAP client and the CoAP server for CoAP observe. The CoAP server sends an observe notification every 5 seconds before deregistration. Figure 54: CoAP Observe of CoAP Client #1 User Manual CFR0012 Revision 2.2 87 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide Figure 55: CoAP Observe of CoAP Client #2 Figure 56: CoAP Observe of CoAP Client #3 4.1.6.2 Deregistration DA16200 provides an API to deregister a CoAP observe as shown in the example code. UINT coap_client_sample_unregister_observe(coap_client_sample_config *config) { coap_client_t *coap_client_ptr = &config->coap_client; //Deregister observe. coap_client_clear_observe(coap_client_ptr); return status; } The API's details are as follows: VOID coap_client_clear_observe(coap_client_t *coap_client) Prototype VOID coap_client_clear_observe(coap_client_t *coap_client) Description Deregister CoAP observe relation Parameters client_ptr: CoAP Client instance pointer 4.2 DNS Query 4.2.1 How to Run 1. Open the workspace for the DNS Query sample application as follows: ~/SDK/sample/Network/DNS_Query/build/DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. 3. Use the console to set up the Wi-Fi station interface. 4. After a connection is made to an AP, the example application starts a DNS query operation with a test URL. 5. The example application runs two types of DNS query operations: single-IPv4 address and multiple-IPv4 address. >>> Single IPv4 address DNS query test ... - Name : www.daum.net - Addresses : 203.133.167.16 >>> Multiple IPv4 address DNS query test ... User Manual CFR0012 Revision 2.2 88 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide - Name : www.daum.net - Addresses : 203.133.167.81 203.133.167.16 4.2.2 Application Initialization This section shows how to get the IPv4 address from a domain name URL. Two types of API functions are supported to get the IP address: Get single IPv4 address: char * dns_A_query(char *domain_name) Get multiple IPv4 addresses: unsigned int dns_ALL_Query(unsigned char *domain_name, unsigned char *record_buffer, unsigned int buffer_size, unsigned int *record_count) This example creates a user thread, which entry function is dns_query_sample(). void dns_query_sample(ULONG arg) { char *test_url = TX_NULL; /* Check test url */ test_url = read_nvram_string("TEST_DOMAIN_URL"); if (test_url == TX_NULL) { test_url = TEST_URL; } PRINTF("\n\n"); /* 1. Single IP address */ dns_A_query_sample(test_url); /* 2. Multiple IP address */ dns_multiple_query_sample(test_url); } 4.2.3 Get Single IPv4 Address This example shows the use of the API function "char * dns_A_query(char *domain_name)" to get the IPv4 address string with a domain name URL. void dns_A_query_sample(char *test_url_str) { char *ipaddr_str = NX_NULL; PRINTF(">>> Single IPv4 address DNS query test ...\n"); /* Allocate buffer from heap area */ ipaddr_str = malloc(MAX_IP_LEN); if (ipaddr_str == NULL) { PRINTF("\nFailed to allocate buffer from heap area ...\n"); return; } memset(ipaddr_str, 0, MAX_IP_LEN); /* DNS query with test url string */ ipaddr_str = dns_A_Query(test_url_str); User Manual CFR0012 Revision 2.2 89 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide /* Fail checking ... */ if (ipaddr_str == NX_NULL) { PRINTF("\nFailed to dns-query with %s\n", test_url_str); } else { PRINTF("- Name : %s\n", test_url_str); PRINTF("- Addresses :\t%s\n", ipaddr_str); } } 4.2.4 Get Multiple IPv4 Addresses This example shows the use of the API function "UINT dns_ALL_Query(UCHAR *domain_name, UCHAR *record_buffer, UINT record_buffer_size, UINT *record_count)" to get a string of multiple IPv4 addresses from a domain name URL. /* 2. Multiple IP address */ void dns_multiple_query_sample(char *test_url_str) { ULONG multi_ipaddr[MAX_IP_LIST_CNT] = { 0, }; ULONG ipv4_address; int ipaddr_cnt = 0; int i; UINT status; PRINTF("\n\n"); PRINTF(">>> Multiple IPv4 address DNS query test ...\n"); /* DNS query with test url string */ status = dns_ALL_Query((UCHAR *)test_url_str, (UCHAR *)&multi_ipaddr[0], (MAX_IP_LIST_CNT * sizeof(ULONG)), (UINT *)&ipaddr_cnt); /* Fail checking ... */ if (status != TX_SUCCESS) { PRINTF("\nFailed to dns-query with %s\n", test_url_str); } else { PRINTF("- Name : %s\n", test_url_str); PRINTF("- Addresses : "); for (i = 0; i < ipaddr_cnt; i++) { ipv4_address = multi_ipaddr[i]; PRINTF("\t%d.%d.%d.%d\n", (ipv4_address >> 24) & 0xff, (ipv4_address >> 16) & 0xff, (ipv4_address >> 8) & 0xff, (ipv4_address ) & 0xff); } } } 4.3 SNTP and Get Current Time Wi-Fi devices may need to synchronize the device clock on the internet with the use of TLS or communication with the server. DA16200 provides SNTP for this operation and users can use this function to get the current time. User Manual CFR0012 Revision 2.2 90 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 4.3.1 How to Run 1. Open the workspace for the SNTP and current time sample application as follows: ~/SDK/sample/ETC/Current_Time/build/DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. 3. Use the console to set up the Wi-Fi station interface. 4. After a connection is made to an AP, the example application will start an SNTP client with test values. ~/SDK/sample/ETC/Current_Time/src/cur_time_sample.c #define TEST_SNTP_SERVER "time.windows.com" #define TEST_SNTP_RENEW_PERIOD 600 #define #define #define TEST_TIME_ZONE (9 * 3600) // seconds ONE_SECONDS 100 CUR_TIME_LOOP_DELAY 10 // seconds NOTE If the SNTP client was started with predefined values, this configuration will be ignored. The legacy AP must be connected to the internet. 5. After a connection is made to the SNTP server, DA16200 will show the connection result on the debug console. Connection COMPLETE to 88:36:6c:4e:a1:28 -- DHCP Client WLAN0: SEL -- DHCP Client WLAN0: REQ -- DHCP Client WLAN0: BOUND Assigned addr : 192.168.0.9 netmask : 255.255.255.0 gateway : 192.168.0.1 DNS addr : 168.126.63.1 DHCP Server IP : 192.168.0.1 Lease Time : 02h 00m 00s Renewal Time : 01h 00m 00s >>> SNTP Server: time.windows.com (52.168.138.145) >>> SNTP Time sync : 2018.12.03 - 15:06:28 DA16200 will periodically get the current time (test period: 10 seconds). - Current Time : 2018.12.03 15:06:37 (GMT +9:00) - Current Time : 2018.12.03 15:06:47 (GMT +9:00) ... ... 4.3.2 Operation 1. The user application needs to set SNTP client information. ~/SDK/sample/ETC/Current_Time/src/cur_time_sample.c void cur_time_sample(ULONG arg) { unsigned int status; __time64_t now; struct tm *ts; char time_buf[80]; User Manual CFR0012 Revision 2.2 91 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide /* Config SNTP client */ status = set_n_start_SNTP(); if (status != TX_SUCCESS) { PRINTF("[%s] Faile to start SNTP client ...\n", __func__); return; } 2. If the SNTP client was already started with predefined values, then this configuration will be skipped. Set the SNTP server address, time update period and time zone and finally enable the function. ~/SDK/sample/ETC/Current_Time/src/cur_time_sample.c static UCHAR set_n_start_SNTP(void) { unsigned int status = TX_SUCCESS; /* Check current SNTP running status */ status = getSNTPuse(); if (status == TX_TRUE) { /* Already SNTP module running ... */ return TX_SUCCESS; } /* Config and save SNTP server domain */ status = (unsigned int)setSNTPsrv(TEST_SNTP_SERVER, 0); if (status != TX_SUCCESS) { PRINTF("Failed to write nvram operation (SNTP server domain)...\n"); status = TX_START_ERROR; goto _exit; } /* Config and save SNTP periodic renew time: seconds */ status = (unsigned int)setSNTPperiod(TEST_SNTP_RENEW_PERIOD); if (status != TX_SUCCESS) { PRINTF("Failed to write nvram operation (SNTP renew period)...\n"); status = TX_START_ERROR; goto _exit; } /* Config and save SNTP time zone */ status = (unsigned int)setTimezone(TEST_TIME_ZONE); if (status != TX_SUCCESS) { PRINTF("Failed to write nvram operation (SNTP renew period)...\n"); status = TX_START_ERROR; goto _exit; } da16x_SetTzoff(TEST_TIME_ZONE); /* Config and save SNTP client mode : enable */ status = setSNTPuse(SNTP_ENABLE); if (status != TX_SUCCESS) { PRINTF("Failed to write nvram operation (SNTP mode)...\n"); status = TX_START_ERROR; goto _exit; } } 3. After a connection is made to the SNTP server, DA16200 will periodically get the current time. User Manual CFR0012 Revision 2.2 92 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide ~/SDK/sample/ETC/Current_Time/src/cur_time_sample.c void cur_time_sample(ULONG arg) { ... while (1) { /* delay */ tx_thread_sleep(CUR_TIME_LOOP_DELAY * ONE_SECONDS); /* get current time */ da16x_time64(NULL, &now); ts = (struct tm *)da16x_localtime64(&now); /* make time string */ Da16x_strftime(time_buf, sizeof(time_buf), "%Y.%m.%d %H:%M:%S", ts); /* display current time string */ PRINTF("- Current Time : %s (GMT %+02ld:%02ld)\n", time_buf, da16x_Tzoff() / 3600, da16x_Tzoff() % 3600); } 4.4 SNTP and Get Current Time in DPM Function This example application applies to the DPM function. Most code is the same as the non-DPM SNTP example. 4.4.1 How to Run 1. Open the workspace for the SNTP and the current time in the DPM sample application as follows: ~/SDK/sample/ETC/Current_Time_DPM/build/DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. 3. Use the console to set up the Wi-Fi station interface. 4. After a connection is made to an AP, the example application will start an SNTP client with test values. ~/SDK/sample/ETC/Current_Time_DPM/src/cur_time_dpm_sample.c #define TEST_SNTP_SERVER "time.windows.com" #define TEST_SNTP_RENEW_PERIOD 600 #define TEST_TIME_ZONE (9 * 3600) // seconds #define #define ONE_SECONDS 100 CUR_TIME_LOOP_DELAY 10 // seconds NOTE If the SNTP client was started with pre-defined values, this configuration will be ignored. The legacy AP must be connected to the internet 5. After a connection is made to the SNTP server, DA16200 will show the connection result on the debug console and go to DPM sleep mode. Connection COMPLETE to 88:36:6c:4e:a1:28 -- DHCP Client WLAN0: SEL -- DHCP Client WLAN0: REQ -- DHCP Client WLAN0: BOUND Assigned addr : 192.168.0.9 netmask : 255.255.255.0 User Manual CFR0012 Revision 2.2 93 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide gateway : 192.168.0.1 DNS addr : 168.126.63.1 DHCP Server IP : 192.168.0.1 Lease Time : 02h 00m 00s Renewal Time : 01h 00m 00s >>> SNTP Server: time.windows.com (52.168.138.145) >>> SNTP Time sync : 2018.12.03 - 15:06:28 >>> Start DPM Power-Down !!! DA16200 will periodically get the current time (test period is 10 seconds). WC_RTM(0x12) >>> TIM : FAST - Current Time : 2018.12.03 15:06:38 (GMT +9:00) >>> Start DPM Power-Down !!! rwnx_send_set_ps_mode PS TIME (us) 115902 WC_RTM(0x12) >>> TIM : FAST - Current Time : 2018.12.03 15:06:48 (GMT +9:00) >>> Start DPM Power-Down !!! rwnx_send_set_ps_mode PS TIME (us) 115936 4.4.2 Operation The SNTP configuration interface is the same as the non-DPM SNTP example. If DA16200 woke up from DPM Sleep mode, use the RTM API to get the current SNTP status, or save the SNTP status into the RTM. ~/SDK/sample/ETC/Current_Time_DPM/src/cur_time_dpm_sample.c static UCHAR set_n_start_SNTP(void) { unsigned int status = TX_SUCCESS; /* Check current SNTP running status */ if (dpm_mode_is_wakeup() == DPM_WAKEUP) { status = get_sntp_use_from_rtm(); } else { status = getSNTPuse(); } if (status == TX_TRUE) { long time_zone; /* Already SNTP module running, set again time-zone ... */ time_zone = get_timezone_from_rtm(); da16x_SetTzoff(time_zone); return TX_SUCCESS; } if (dpm_mode_is_wakeup() == NORMAL_BOOT) { /* Config and save SNTP server domain */ status = (unsigned int)setSNTPsrv(TEST_SNTP_SERVER, 0); if (status != TX_SUCCESS) { PRINTF("Failed to write nvram operation (SNTP server domain)\n"); status = TX_START_ERROR; goto _exit; } User Manual CFR0012 Revision 2.2 94 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide /* Config and save SNTP periodic renew time : seconds */ status = (unsigned int)setSNTPperiod(TEST_SNTP_RENEW_PERIOD); if (status != TX_SUCCESS) { PRINTF("Failed to write nvram operation (SNTP renew period)...\n"); status = TX_START_ERROR; goto _exit; } /* Config and save SNTP time zone */ status = (unsigned int)setTimezone(TEST_TIME_ZONE); if (status != TX_SUCCESS) { PRINTF("Failed to write nvram operation (SNTP renew period)...\n"); status = TX_START_ERROR; goto _exit; } set_timezone_to_rtm(TEST_TIME_ZONE); da16x_SetTzoff(TEST_TIME_ZONE); /* Config and save SNTP client mode : enable */ status = setSNTPuse(SNTP_ENABLE); if (status != TX_SUCCESS) { PRINTF("Failed to write nvram operation (SNTP mode)...\n"); status = TX_START_ERROR; goto _exit; } /* Save config and start SNTP client */ set_sntp_use_to_rtm(status); } _exit : return status; } When connected to the SNTP server, DA16200 will start an RTC timer to periodically get the current time. ~/SDK/sample/ETC/Current_Time_DPM/src/cur_time_dpm_sample.c void cur_time_dpm_sample(ULONG arg) { ... /* Regist periodic RTC Timer: Get current time */ if (dpm_mode_is_wakeup() == NORMAL_BOOT) { /* Time delay for stable running SNTP client */ tx_thread_sleep(10); dpm_timer_create(CUR_TIME_LOOP_DELAY, SAMPLE_CUR_TIME_DPM, TEST_TIMER_ID, 1, // 0:One-shot, 1:Periodical display_cur_time); } /* Set flag to go to DPM sleep 3 */ dpm_app_sleep_ready_set(SAMPLE_CUR_TIME_DPM); } The SNTP configuration interface is the same as for the non-DPM SNTP example. ~/SDK/sample/ETC/Current_Time_DPM/src/cur_time_dpm_sample.c static void display_cur_time(void) User Manual CFR0012 Revision 2.2 95 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide { dpm_app_wakeup_done(SAMPLE_CUR_TIME_DPM); __time64_t now; struct tm *ts; char time_buf[80]; /* get current time */ da16x_time64(NULL, &now); ts = (struct tm *)da16x_localtime64(&now); /* make time string */ Da16x_strftime(time_buf, sizeof(time_buf), "%Y.%m.%d %H:%M:%S", ts); /* display current time string */ PRINTF("- Current Time : %s (GMT %+02ld:%02ld)\n", time_buf, da16x_Tzoff() / 3600, da16x_Tzoff() % 3600); /* Set flag to go to DPM sleep 3 */ dpm_app_sleep_ready_set(SAMPLE_CUR_TIME_DPM); } 4.5 HTTP Client The DA16200 SDK has a ported product called Express Logic's NetXDuo HTTP v5.10. With this product, an application programmer can develop an HTTP client application that uses NetXDuo HTTP APIs. 4.5.1 How to Run 1. Open the workspace for the HTTP_Client sample application as follows: ~/SDK/sample/Network/HTTP_Client/build/DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. 3. Use the console to set up the Wi-Fi station interface and connect to the AP that is connected to the Internet. 4. Complete the setup and (re)start the sample. 4.5.2 Operation The sample code is an example of the Get and Post methods. When the sample starts, a -get request is made to the URL address. If ENABLE_METHOD_POST_TEST is defined, request with post (the sample's URL address is just an example). To connect to the HTTPS server, simply enter "https://" instead of "http://" in the URL address. To set valid time information in the certificate before the HTTPs request, the system's current time must be set (SNTP service must be enabled). 1. The HTTP Client sample code also includes sample code to parse the input URL. If the URL is parsed with HTTPs, the encryption mode option is automatically set. UINT http_client_get_sample(unsigned char *uri) { status = parse_uri(uri, uri_len, &http_request); if (status) { DBG_PRINT("[%s]Failed to parse uri(0x%02x)\n", __func__, status); return status; User Manual CFR0012 Revision 2.2 96 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide } 2. Create an HTTP Client instance on the specified IP instance. // Create http client status = nx_http_client_create(&http_client, HTTP_CLIENT_THREAD_NAME, ip_ptr, pool_ptr, HTTP_CLIENT_WINDOW_SZ); if (status) { DBG_PRINT("[%s]Not able to create http client(0x%02x).\n", __func__, status); return status; } 3. Set the port number and insert the header field. // Set http client options nx_http_client_set_connect_port(&http_client, http_request.port); // Set hostname for http 1.1 nx_http_client_set_host_domain(&http_client, http_request.hostname, strlen((char *)http_request.hostname)); 4. Set the buffer size that https uses for encryption and decryption. The buffer size can be up to 17 Kbyte. If not set, the default is 4 Kbyte. If only HTTP is used, then the buffer size does not need to be set. if (http_request.insecure == NX_TRUE) { // Set secure mode nx_http_client_set_secure_connection(&http_client, NX_TRUE); // Use heap memory for tls contents buffer nx_http_client_set_content_heap(&http_client, NX_TRUE); // Set contents buffer's size nx_http_client_set_content_buflen(&http_client, HTTP_CLIENT_IN_CONTENT_BUF_SZ, HTTP_CLIENT_IN_CONTENT_BUF_SZ); } 5. Start an HTTP GET or POST request. If http_request.data is NULL, then the request is a Get method. If http_request.data is valid, then the request is a Post method. If this routine returns NX_SUCCESS, the application can then make multiple calls to nx_http_client_get_packet to retrieve data packets that correspond to the requested resource content. status = nxd_http_client_get_start(&http_client, &http_request.ip_addr, http_request.path, post_data_len ? http_request.data : NX_NULL, post_data_len, strlen((char *)http_request.username) ? http_request.username : NX_NULL, http_request.password : NX_NULL, strlen((char *)http_request.password) ? wait_option); if (status != NX_SUCCESS) { User Manual CFR0012 Revision 2.2 97 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide DBG_PRINT("[%s]Not able to get data from http server(0x%02x)\n", __func__, status); } else { ... 6. Get the next resource data packet. This step retrieves the next content packet of the resource requested by the previous nx_http_client_get_start call. Successive calls to this routine should be made until the return status NX_HTTP_GET_DONE is received. Function nx_packet_data_retrieve copies data from the supplied packet into the supplied buffer. The actual number of bytes copied is returned in the destination that is pointed to by the bytes copied. do { nx_packet_release(recv_packet); if (recv_buf) { free(recv_buf); recv_buf = NULL; } recv_bytes = 0; status = nx_http_client_get_packet(&http_client, &recv_packet, wait_option); if (status == NX_SUCCESS) { status = nx_packet_length_get(recv_packet, &recv_bytes); if (status) { PRINTF("[%s]Failed to get rx packet's length(0x%02x)\n", __func__, status); break; } recv_buf = calloc(recv_bytes + 1, 1); if (recv_buf == NULL) { PRINTF("[%s]Memory is not enough\n", __func__); break; } status = nx_packet_data_retrieve(recv_packet, recv_buf, &recv_bytes); if (status != NX_SUCCESS) { PRINTF("[%s] Not able to get data(0x%02x)\n", __func__, status); break; } nx_packet_release(recv_packet); recv_packet = NX_NULL; free(recv_buf); recv_buf = NULL; User Manual CFR0012 Revision 2.2 98 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 4.6 HTTP Client in DPM Function The DA16200 SDK has a ported product called Express Logic's NetXDuo HTTP v5.10. With this product, an application programmer can develop an HTTP client application that uses NetXDuo HTTP APIs. 4.6.1 How to Run 1. Open the workspace for the HTTP_Client sample application as follows: ~/SDK/sample/Network/HTTP_Client/build/DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. 3. Use the console to set up the Wi-Fi station interface and connect to the AP that is connected to the Internet. 4. Complete the setup and (re)start the sample. 4.6.2 Operation The sample code is an example of the Get and Post method. When the sample starts, a -get request is made to the URL address. If ENABLE_METHOD_POST_TEST is defined, request with -post. (the sample's URL address is just an example). To connect to the HTTPs server, simply enter "https://" instead of "http://" in the URL address. To set valid time information in the certificate before the HTTPs request, the system's current time must be set (SNTP service must be enabled). 1. If an application that uses the HTTP protocol is registered in DPM, a setting must be made not to enter DPM_SLEEP while HTTP transmission (request/response) is in progress. Set DPM_SLEEP to enabled after all transfers are complete. UINT port_number = 0; PRINTF("\n\n>>> Start HTTP-Client sample\n\n\n"); dpm_app_register(HTTP_CLIENT_THREAD_NAME, port_number); dpm_app_sleep_ready_clear(HTTP_CLIENT_THREAD_NAME); http_client_get_sample(uri); dpm_app_sleep_ready_set(HTTP_CLIENT_THREAD_NAME); 2. The HTTP Client sample code also includes sample code to parse the input URL. If the URL is parsed with HTTPs, the encryption mode option is automatically set. UINT http_client_get_sample(unsigned char *uri) { status = parse_uri(uri, uri_len, &http_request); if (status) { DBG_PRINT("[%s]Failed to parse uri(0x%02x)\n", __func__, status); return status; } 3. Create an HTTP Client instance on the specified IP instance. // Create http client status = nx_http_client_create(&http_client, HTTP_CLIENT_THREAD_NAME, ip_ptr, pool_ptr, User Manual CFR0012 Revision 2.2 99 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide HTTP_CLIENT_WINDOW_SZ); if (status) { DBG_PRINT("[%s]Not able to create http client(0x%02x).\n", __func__, status); return status; } 4. Set the port number and insert the header field. // Set http client options nx_http_client_set_connect_port(&http_client, http_request.port); // Set hostname for http 1.1 nx_http_client_set_host_domain(&http_client, http_request.hostname, strlen((char *)http_request.hostname)); 5. Set the buffer size that HTTPs uses for encryption and decryption. The buffer size can be up to 17 Kbyte. If not set, the default is 4 Kbyte. If only HTTP is used, then the buffer size does not need to be set. if (http_request.insecure == NX_TRUE) { // Set secure mode nx_http_client_set_secure_connection(&http_client, NX_TRUE); // Use heap memory for tls contents buffer nx_http_client_set_content_heap(&http_client, NX_TRUE); // Set contents buffer's size nx_http_client_set_content_buflen(&http_client, HTTP_CLIENT_IN_CONTENT_BUF_SZ, HTTP_CLIENT_IN_CONTENT_BUF_SZ); } 6. Start an HTTP GET or POST request. If http_request.data is NULL, then the request is a Get method. If http_request.data is valid, then the request is a Post method. If this routine returns NX_SUCCESS, the application can then make multiple calls to nx_http_client_get_packet to retrieve data packets that correspond to the requested resource content. status = nxd_http_client_get_start(&http_client, &http_request.ip_addr, http_request.path, post_data_len ? http_request.data : NX_NULL, post_data_len, strlen((char *)http_request.username) ? http_request.username : NX_NULL, strlen((char *)http_request.password) ? http_request.password : NX_NULL, wait_option); if (status != NX_SUCCESS) { DBG_PRINT("[%s]Not able to get data from http server(0x%02x)\n", __func__, status); } else { ... 7. Get the next resource data packet. User Manual CFR0012 Revision 2.2 100 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide This step retrieves the next content packet of the resource requested by the previous nx_http_client_get_start call. Successive calls to this routine should be made until the return status NX_HTTP_GET_DONE is received. Function nx_packet_data_retrieve copies data from the supplied packet into the supplied buffer. The actual number of bytes copied is returned in the destination that is pointed to by the bytes copied. do { nx_packet_release(recv_packet); if (recv_buf) { free(recv_buf); recv_buf = NULL; } recv_bytes = 0; status = nx_http_client_get_packet(&http_client, &recv_packet, wait_option); if (status == NX_SUCCESS) { status = nx_packet_length_get(recv_packet, &recv_bytes); if (status) { PRINTF("[%s]Failed to get rx packet's length(0x%02x)\n", __func__, status); break; } recv_buf = calloc(recv_bytes + 1, 1); if (recv_buf == NULL) { PRINTF("[%s]Memory is not enough\n", __func__); break; } status = nx_packet_data_retrieve(recv_packet, recv_buf, &recv_bytes); if (status != NX_SUCCESS) { PRINTF("[%s] Not able to get data(0x%02x)\n", __func__, status); break; } nx_packet_release(recv_packet); recv_packet = NX_NULL; free(recv_buf); recv_buf = NULL; } 4.7 HTTP Server The DA16200 SDK has a ported product called Express Logic's NetXDuo HTTP v5.10. With this product, an application programmer can develop an HTTP server application that uses NetXDuo HTTP APIs. User Manual CFR0012 Revision 2.2 101 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 4.7.1 How to Run 1. Open the workspace for the HTTP_Server sample application as follows: ~/SDK/sample/Network/HTTP_Server/build/DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. 3. Use the console to set up the Wi-Fi station interface and connect to the AP. 4. Complete the setup and (re)start the sample. 4.7.2 Operation The sample code is an example of the Get and Post methods. 1. The HTTP Server sample code supports both HTTP and HTTPS (Default is HTTP). To operate with HTTPs, define ENABLE_HTTPS_SERVER as shown below. Also, update the certificate embedded in the code (*root_ca, *own_cert, *private_key) as needed. /// HTTPS server #define ENABLE_HTTPS_SERVER 2. Check if the network is initialized and check the status of the IP instance. static UINT http_server_sample(HTTP_SERVER_CONF *config) { UINT status = NX_SUCCESS; NX_PACKET_POOL *svr_pkt_pool = NX_NULL; NX_IP *nx_ip_ptr = NX_NULL; /* Check the network initialization */ status = check_net_init(config->iface); if (status == NX_SUCCESS) { ULONG actual_status; get_thread_netx((void **)&svr_pkt_pool, (void **)&nx_ip_ptr, config->iface); do { status = nx_ip_status_check(nx_ip_ptr, NX_IP_INITIALIZE_DONE, &actual_status, 100); if (status != NX_SUCCESS) { tx_thread_sleep(1); } } while (status != NX_SUCCESS); } else { PRINTF("Failed to create HTTP Server(0x%02x)\n", status); return status; } 3. This step creates an HTTP Server instance, which runs in the context of its own ThreadX thread. The optional authentication_check and request_notify application callback routines give the application software control over the basic operations of the HTTP Server. //create http server status = nx_http_server_create(&config->http_server, config->server_name, nx_ip_ptr, config->stack, User Manual CFR0012 Revision 2.2 102 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide HTTP_SERVER_STACK_SIZE, svr_pkt_pool, &config->http_server_params, NX_NULL, http_server_request_notify); if (status != NX_SUCCESS) { PRINTF("Failed to create HTTP Server(0x%02x)\n", status); APP_FREE(config->stack); config->stack = NULL; return status; } 4. Start the create HTTP Server instance. // start http server status = nx_http_server_start(&config->http_server); if (status != NX_SUCCESS) { PRINTF("Failed to start HTTP server(0x%02x)\n", status); status = nx_http_server_delete(&config->http_server); if (status != NX_SUCCESS) { PRINTF("Failed to delete HTTP server(0x%02x)\n", status); } APP_FREE(config->stack); config->stack = NULL; return status; } 5. When a request is received from the HTTP Client, the notify callback function registered at nx_http_server_create is called. When the POST method is used, payload data sent by the client can be extracted. When the GET method is used, the server needs to send data to the client. static UINT http_server_request_notify(NX_HTTP_SERVER *server_ptr, UINT logical_connection, UINT request_type, CHAR *resource, NX_PACKET *packet_ptr) { UINT status = NX_SUCCESS; char *recv_buf = NULL; ULONG recv_bytes = 0; if (request_type == NX_HTTP_SERVER_POST_REQUEST) { PRINTF("HTTP Server : POST\n"); ... status = nx_packet_length_get(packet_ptr, &recv_bytes); ... status = nx_packet_data_retrieve(packet_ptr, recv_buf, &recv_bytes); ... 6. Register callback functions that build payload data to be sent to HTTP Client in response to a GET method. static VOID http_server_init_info(HTTP_SERVER_CONF *config, UINT secure_mode) User Manual CFR0012 Revision 2.2 103 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide { ... //Functions for building response data config->http_server_params.nx_http_server_web_open = ws_open; config->http_server_params.nx_http_server_web_close = ws_close; config->http_server_params.nx_http_server_web_get_size = ws_get_size; config->http_server_params.nx_http_server_web_get_payload = ws_get_payload; return ; } The DA16200 does not have a file system. Therefore, the HTTP Server uses free memory to implement a virtual file system. Users can display web pages on HTTP clients when the HTTP Server sends text written in HTML as payload data. Memory can be allocated dynamically or statically at the discretion of the user. UINT (*nx_http_server_web_open)(CHAR *dir_name) Parameter *dir_name: Receive URI requested by HTTP Client. Description Build(=open) the data(=file) to be transmitted as payload. UINT (*nx_http_server_web_get_size)(CHAR *dir_name, ULONG *size) Parameter *dir_name: Receive URI requested by HTTP Client. *size : The total size of the built data. Description The total size of the built data is passed through *size. UINT (*nx_http_server_web_get_payload)(VOID *buffer_ptr, ULONG request_size, ULONG *actual_size) Parameter *buffer_ptr: Receive URI requested by HTTP Client. mss : Determined by the maximum seg_size (mss) of a TCP socket. *actual_size: Must pass a value less than or equal to mss. if (mss < remaining_size) *actual_size = mss; else *actual_size = remaining_size; Description The data(=file) built in nx_http_server_web_open() is loaded on payload and transmitted. If the data size is larger than the mss, it is called several times. 7. If the HTTP Server works successfully, test the Get method as follows. Use the web browser of the test PC that is connected to the same network. http://[Server IP]/index.html Figure 57: The Result of the DA16200 HTTP Server 8. Then test the Post method. The POSTMAN tool is recommended for the test (https://www.getpostman.com/apps). User Manual CFR0012 Revision 2.2 104 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide Figure 58: The DA16200 HTTP Server Test with POSTMAN Tool 9. In the DA16200 console, you can see the data sent by POSTMAN (HTTP Client) printed as a hex_dump. Depending on your application data format, you can develop code to parse and handle your HTTP data. HTTP Server : PUT -- DHCP Client WLAN0: RENEWING -- DHCP Client WLAN0: BOUND Assigned addr : 192.168.31.4 Lease Time : 00h 30m 00s Renewal Time : 00h 15m 00s HTTP Server : POST >>> HTTP Response - (len=274): [00000000] 50 4f 53 54 20 2f 69 6e 64 65 78 2e 68 74 6d 6c [00000010] 20 48 54 54 50 2f 31 2e 31 0d 0a 43 6f 6e 74 65 [00000020] 6e 74 2d 54 79 70 65 3a 20 74 65 78 74 2f 70 6c [00000030] 61 69 6e 0d 0a 55 73 65 72 2d 41 67 65 6e 74 3a [00000040] 20 50 6f 73 74 6d 61 6e 52 75 6e 74 69 6d 65 2f [00000050] 37 2e 32 34 2e 31 0d 0a 41 63 63 65 70 74 3a 20 [00000060] 2a 2f 2a 0d 0a 50 6f 73 74 6d 61 6e 2d 54 6f 6b [00000070] 65 6e 3a 20 34 30 36 39 63 61 32 65 2d 32 32 65 [00000080] 35 2d 34 66 36 39 2d 38 37 34 64 2d 31 62 65 34 [00000090] 62 31 37 36 35 39 39 33 0d 0a 48 6f 73 74 3a 20 [000000a0] 31 39 32 2e 31 36 38 2e 33 31 2e 34 0d 0a 41 63 [000000b0] 63 65 70 74 2d 45 6e 63 6f 64 69 6e 67 3a 20 67 [000000c0] 7a 69 70 2c 20 64 65 66 6c 61 74 65 2c 20 62 72 [000000d0] 0d 0a 43 6f 6e 6e 65 63 74 69 6f 6e 3a 20 6b 65 [000000e0] 65 70 2d 61 6c 69 76 65 0d 0a 43 6f 6e 74 65 6e [000000f0] 74 2d 4c 65 6e 67 74 68 3a 20 31 38 0d 0a 0d 0a [00000100] 70 70 70 70 70 70 70 70 70 70 70 70 70 70 70 70 [00000110] 70 70 POST /index.html HTTP/1.1..Conte nt-Type: text/pl ain..User-Agent: PostmanRuntime/ 7.24.1..Accept: */*..Postman-Tok en: 4069ca2e-22e 5-4f69-874d-1be4 b1765993..Host: 192.168.31.4..Ac cept-Encoding: g zip, deflate, br ..Connection: ke ep-alive..Conten t-Length: 18.... pppppppppppppppp pp 4.8 OTA FW update The DA16200 firmware image set consists of Bootloader (secondary bootloader), SLIB and RTOS. The boot loader cannot be updated via OTA, only SLIB and RTOS. With this product, an application programmer can develop an OTA FW update application that uses OTA APIs. In addition, users can update certificates (TLS Certificate Key #0 and TLS Certificate Key #1). And it supports firmware update of MCU connected by UART1. User Manual CFR0012 Revision 2.2 105 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 4.8.1 How to Run 1. Open the workspace for the OTA_Update sample application as follows: .\sample\Network\ OTA_Update\build\DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. 3. Use the console to set up the Wi-Fi station interface and connect to the AP that is connected to the Internet. 4. Complete the setup and (re)start the sample. 4.8.2 Operation The sample code includes three examples of updating the DA16200's firmware (SLIB and RTOS), certificates (TLS Certificate Key #0 and TLS Certificate Key #1), and MCU firmware. Each example is divided into definitions as follows. By default, only the DA16200 firmware update definition is enabled and the certificate and MCU FW update are disabled. #define SAMPLE_UPDATE_DA16_FW #undef SAMPLE_UPDATE_MCU_FW #undef SAMPLE_UPDATE_CERT_KEY The definition of SAMPLE_OTA_HTTPS_TLS_CONFIG is for setting TLS options when using the HTTPS protocol. Usually this definition is disabled by default as no option setting is required unless required by the HTTPS server. #undef SAMPLE_OTA_HTTPS_TLS_CONFIG typedef struct OTA_UPDATE_CONFIG contains arguments to be passed to the OTA update API. Declare and use a global variable of OTA_UPDATE_CONFIG type. static OTA_UPDATE_CONFIG ota_update_conf = { 0, }; static OTA_UPDATE_CONFIG *g_ota_update_conf = (OTA_UPDATE_CONFIG *) &ota_update_conf; 4.8.2.1 DA16200 Firmware Update This is an example of DA16200 firmware update. 1. Both SLIB and RTOS must be downloaded at once. So, set both uri_slib and uri_rtos to suit user environment. g_ota_update_conf->uri_slib = ota_server_uri_slib; g_ota_update_conf->uri_rtos = ota_server_uri_rtos; 2. If the download is completed successfully, the user can set it to automatically activate RENEW. g_ota_update_conf->auto_renew = 1; 3. By registering a callback function in download_complete_notify, the user can be notified if the download succeeds or fails. SLIB and RTOS are notified separately. Users can check whose notification is by update_type. g_ota_update_conf->download_complete_notify = user_sample_da16_fw_download_notify; 4. Users can be notified of the RENEW status by registering a callback function. Unlike download notification, it is notified only once. If the notification status is successful, the DA16200 will automatically reboot after 2-3 seconds. g_ota_update_conf->renew_notify = user_sample_da16_fw_renew_notify; 5. Finally, call the OTA update start API. When ota_update_start_download() is called, an OTA update task is created internally and the creation status of the task is immediately returned. The process is not blocked. status = ota_update_start_download(g_ota_update_conf); 6. If the firmware has been successfully updated, the DA16200 will reboot. User Manual CFR0012 Revision 2.2 106 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 4.8.2.2 Certificates Update This is an example of a certificate update. 1. Set uri_other to suit the user environment. g_ota_update_conf->uri_other = ota_server_uri_cert; 2. Be sure to set other_type to OTA_TYPE_CERT_KEY. g_ota_update_conf->other_type = OTA_TYPE_CERT_KEY; 3. Set the address of SFLASH to be saved when downloading. If not set, the default is SFLASH_USER_AREA_0_START. g_ota_update_conf->download_sflash_addr = SFLASH_USER_AREA_0_START; 4. Register a callback to be notified of the download status. g_ota_update_conf->download_complete_notify = user_sample_cert_key_download_notify; 5. Finally, call the OTA update start API. When ota_update_start_download() is called, an OTA update task is created internally and the creation status of the task is immediately returned. The process is not blocked. status = ota_update_start_download(g_ota_update_conf); 6. If the download is successful, copy them to the TLS Certificate Key #0 and TLS Certificate Key #1 areas. status = ota_update_copy_flash(SFLASH_ROOT_CA_ADDR1, g_ota_update_conf>download_sflash_addr, 4096); 4.8.2.3 MCU Firmware Update This is an example of an MCU firmware update. 1. Set uri_other to suit the user environment. g_ota_update_conf->uri_other = ota_server_uri_mcu; 2. Be sure to set other_type to OTA_TYPE_MCU_FW. g_ota_update_conf->other_type = OTA_TYPE_MCU_FW; 3. Set the address of SFLASH to be saved when downloading. If not set, the default is SFLASH_USER_AREA_0_START. g_ota_update_conf->download_sflash_addr = SFLASH_USER_AREA_0_START; 4. Register a callback to be notified of the download status. g_ota_update_conf->download_complete_notify = user_sample_mcu_fw_download_notify; 5. Finally, call the OTA update start API. When ota_update_start_download() is called, an OTA update task is created internally and the creation status of the task is immediately returned. The process is not blocked. status = ota_update_start_download(g_ota_update_conf); 6. If the download is successful, initialize UART to transmit the firmware to the MCU. ota_update_uart1_init(); 7. Start UART protocol for communication with MCU. status = ota_update_uart_trans_mcu_fw(); User Manual CFR0012 Revision 2.2 107 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 5 Additional Examples 5.1 ThreadX API Sample 5.1.1 How to Run 1. Open the workspace for the ThreadX API sample application as follows: ~/SDK/sample/ETC/ThreadX/build/DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. After boot, the ThreadX APIs test will start automatically. Figure 59: ThreadX APIs Test 5.1.2 Sample Overview Each ThreadX product distribution contains sample apps that run on all supported microprocessors. This sample code is designed to illustrate how ThreadX APIs are used in an embedded multi-thread environment. The demonstration consists of initialization, running nine threads, a one-byte pool, one queue, one semaphore, one mutex, and one event flags group. NOTE See also ThreadX_User_Guide.pdf [3] 5.1.3 Thread Creation and Resource Initialization The threadx_sample runs after the basic ThreadX initialization is complete. It is responsible for initializing the system resources, including threads, queues, semaphores, mutexes, event flags, and memory pools. This function creates the demonstration objects in the following order: queue_0 / semaphore_0 event_flags_0 / mutex_0 / thread_0 / thread_1 / thread_2 / thread_3 / thread_4 / thread_5 / thread_6 / thread_7 / thread_8 The demonstration does not create any other additional ThreadX objects. However, an actual application may create system objects during runtime inside of executing threads. User Manual Revision 2.2 10-Mar-2021 CFR0012 108 of 214 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 5.1.4 Initial Execution All threads are created with the TX_AUTO_START option. This makes the threads initially ready for execution. After tx_application_define completes, control is transferred to the thread scheduler and from there to each thread. The order in which the threads execute is determined by their priority and the order in which they were created. In the demonstration, thread_0 executes first because it has the highest priority (it was created with a priority of 1). After thread_0 suspends, thread_5 is executed, followed by the execution of thread_3, thread_4, thread_6, thread_7, thread_1, and finally thread_2. NOTE Even though thread_3 and thread_4 have the same priority (both created with a priority of 26), thread_3 executes first. This is because thread_3 was created and became ready before thread_4. Threads of equal priority execute in a First In First Out (FIFO) fashion. void threadx_sample(ULONG arg) { ... ... /* Create the message queue shared by threads 1 and 2. */ status = tx_queue_create(&queue_0, "queue 0", TX_1_ULONG, message_queue, QUEUE_SIZE*sizeof(ULONG)); // queue pointer // queue name // message size // queue pointer // queue size /* --- For Semaphore usage ------------------------------------ */ /* Create the semaphore used by threads 3 and 4. */ status = tx_semaphore_create(&semaphore_0, // semaphore pointer "semaphore 0", // semaphore name 1); // initial count /* --- For Event group usage ------------------------------------ */ /* Create the event flags group * used by threads 1 and 5. */ status = tx_event_flags_create(&event_flags_0, // event group pointer "event flags 0"); // event name /* --- For Mutex lock usage ------------------------------------ */ /* Create the mutex used * by thread 6 and 7 without priority inheritance. */ status = tx_mutex_create(&mutex_0, // mutex pointer "mutex 0", // mutex name TX_NO_INHERIT); // inherit flag /* --- For thread create usage -------------------------------- */ /* Create the main thread. */ status = tx_thread_create(&thread_0, // thread pointer "thread 0", // thread name tx_0, // entry pointer 0, // argument thread_0_stack, // thread stack THREAD_STACK_SIZE, // stack size THREAD_0_PRI, // thread priority THREAD_0_PRI, // preempt threshold User Manual CFR0012 Revision 2.2 109 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide TX_NO_TIME_SLICE, TX_AUTO_START); // time slice // auto start flag /* Create threads 1 and 2. * These threads pass information through a ThreadX message queue. * It is also interesting to note * that these threads have a time slice. */ status = tx_thread_create(&thread_1, "thread 1", tx_1, 1, thread_1_stack, THREAD_STACK_SIZE, THREAD_1_PRI, THREAD_1_PRI, 4, TX_AUTO_START); status = tx_thread_create(&thread_2, "thread 2", tx_2, 2, thread_2_stack, THREAD_STACK_SIZE, THREAD_2_PRI, THREAD_2_PRI, 4, TX_AUTO_START); /* Create threads 3 and 4. * These threads compete for a ThreadX counting semaphore. * An interesting thing here is that both threads share * the same instruction area. */ status = tx_thread_create(&thread_3, "thread 3", tx_3_4, 3, thread_3_stack, THREAD_STACK_SIZE, THREAD_3_PRI, THREAD_3_PRI, TX_NO_TIME_SLICE, TX_AUTO_START); status = tx_thread_create(&thread_4, "thread 4", tx_3_4, 4, thread_4_stack, THREAD_STACK_SIZE, THREAD_4_PRI, THREAD_4_PRI, TX_NO_TIME_SLICE, TX_AUTO_START); /* Create thread 5. * This thread simply pends on an event flag, * which will be set by thread_0. */ status = tx_thread_create(&thread_5, "thread 5", tx_5, 5, thread_5_stack, THREAD_STACK_SIZE, THREAD_5_PRI, THREAD_5_PRI, TX_NO_TIME_SLICE, TX_AUTO_START); /* Create threads 6 and 7. * These threads compete for a ThreadX mutex. */ status = tx_thread_create(&thread_6, "thread 6", tx_6_7, 6, thread_6_stack, THREAD_STACK_SIZE, THREAD_6_PRI, THREAD_6_PRI, TX_NO_TIME_SLICE, TX_AUTO_START); status = tx_thread_create(&thread_7, "thread 7", tx_6_7, 7, thread_7_stack, THREAD_STACK_SIZE, THREAD_7_PRI, THREAD_7_PRI, TX_NO_TIME_SLICE, TX_AUTO_START); /* --- For Byte-pool usage ------------------------------------ */ /* Create byte-pool test thread. */ status = tx_thread_create(&thread_8, "thread 8", tx_8, 0, thread_8_stack, THREAD_STACK_SIZE, THREAD_8_PRI, THREAD_8_PRI, TX_NO_TIME_SLICE, TX_AUTO_START); } User Manual CFR0012 Revision 2.2 110 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 5.1.5 Threads Operation in Detail Thread #0 Function tx_0 marks the entry point of the thread. Thread_0 is the first thread to run in the sample. Its processing is simple: it sets an event flag to wake up thread_5 and sleeps for 100 timer ticks, then repeats the sequence. Thread_0 is the highest priority thread among test threads. When its requested sleep expires, it will preempt any other executing thread in the sample. static void tx_0(ULONG arg) { ... ... /* This thread simply sits in while-forever-sleep loop. */ while (1) { /* Set event flag 0 to wakeup thread 5. */ status = tx_event_flags_set(&event_flags_0, 0x1, TX_OR); /* Check status. */ if (status == TX_SUCCESS) { PRINTF("[tx_%d] Event SET : ", arg); } else { PRINTF("[tx_%d] Failed to set event flags (0x%x)\n", arg, status); break; } tx_thread_sleep(100); } } // 100 ticks = 1 second Thread #1 Function tx_1 marks the entry point of the thread Thread_1. The thread is the second-to-last in the demonstration in execution order. Its processing consists of sending a message to thread_2 (through queue_0) and repeat the sequence. Notice that thread_1 suspends whenever queue_0 becomes full. static void tx_1(ULONG arg) { ... ... /* This thread simply sends messages to a queue shared by thread 2. */ while (1) { /* Send message to queue 0. */ tx_msg_buf = get_random_value_ulong(); status = tx_queue_send(&queue_0, &tx_msg_buf, TX_WAIT_FOREVER); /* Check completion status. */ if (status == TX_SUCCESS) { PRINTF("[tx_%d] Message TX (%x) -> ", arg, tx_msg_buf); } else { PRINTF("[tx_%d] Failed to send a message through message queue (0x%x)\n", arg, status); break; } tx_thread_sleep(200); } } // 200 ticks = 2 seconds User Manual CFR0012 Revision 2.2 111 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide Thread #2 Function tx_2 marks the entry point of the thread. Thread_2 is the last thread to be run in the demonstration. Its processing consists of getting a message from thread_1 (through queue_0) and then repeat the sequence. Notice that thread_2 suspends whenever queue_0 becomes empty. Although thread_1 and thread_2 share the lowest priority in the demonstration (priority 27), they are also the only threads that are ready for execution most of the time. They are also the only threads created with time-slicing. Each thread can execute for a maximum of 4 timer ticks before the other thread is executed. static void tx_2(ULONG arg) { ... ... /* This thread retrieves messages placed on the queue by thread 1. */ while (1) { /* Retrieve a message from the queue. */ status = tx_queue_receive(&queue_0, &rx_msg_buf, TX_WAIT_FOREVER); /* Check completion status and make sure the message is * what we expected. */ if (status != TX_SUCCESS) { PRINTF("[tx_%d] Failed to receive a message through message queue (0x%x)\n", arg, status); break; } if (tx_msg_buf == rx_msg_buf) { PRINTF("[tx_%d] Message RX (%x)\n", arg, rx_msg_buf); } else { PRINTF("[tx_%d] Wrong message through message queue (0x%x:0x%x)\n", arg, tx_msg_buf, rx_msg_buf); break; } } } Thread #3 and #4 Function tx_3_4 marks the entry point of both thread_3 and thread_4. Both threads have a priority of 26, which makes them the third and fourth threads in the demonstration system to execute. Each thread is processed in the same manner: get semaphore_0, sleep for 2 timer ticks, release semaphore_0, and then repeat the sequence. Notice that each thread suspends whenever semaphore_0 is unavailable. Also, both threads use the same function for their main processing. This presents no problems because they both have their unique stack, and C is naturally reentrant. Each thread determines which one it is by examination of the thread input parameter, which is set up when they are created. It is also reasonable to obtain the current thread point during thread execution and compare it with the control block's address to determine thread identity. static void tx_3_4(ULONG arg) { ... ... /* * This function is executed from thread 3 and thread 4. * As the loop below shows, User Manual CFR0012 Revision 2.2 112 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide * this function competes for ownership of semaphore_0. */ while (1) { /* Get the semaphore with suspension. */ status = tx_semaphore_get(&semaphore_0, TX_WAIT_FOREVER); /* Check status. */ if (status == TX_SUCCESS) { PRINTF("[tx_%d] Semaphore GET\n", arg); } else { PRINTF("[tx_%d] Failed to get semaphoer (0x%x)\n", arg, status); break; } /* Sleep for 2 ticks to hold the semaphore. */ tx_thread_sleep(2); // 20 msec /* Release the semaphore. */ status = tx_semaphore_put(&semaphore_0); /* Check status. */ if (status == TX_SUCCESS) { PRINTF("[tx_%d] Semaphore PUT\n", arg); } else { PRINTF("[tx_%d] Failed to put semaphoer (0x%x)\n", arg, status); break; } tx_thread_sleep(300); } } // 300 ticks = 3 seconds Thread #5 Function tx_5 marks the entry point of the thread. Thread_5 is the second thread in the demonstration system to execute. Its processing consists of getting an event flag from thread_0 (through event_flags_0), and then repeat the sequence. Notice that thread_5 suspends whenever the event flag in event_flags_0 is not available. static void tx_5(ULONG arg) { ... ... /* This thread simply waits for an event in a forever loop. */ while (1) { /* Wait for event flag 0. */ status = tx_event_flags_get(&event_flags_0, // group pointer 0x1, // requested flags TX_OR_CLEAR, // get option &actual_flags, // actual flags TX_WAIT_FOREVER); // wait option /* Check status. */ if (status == TX_SUCCESS) { PRINTF("[tx_%d] Event GET\n", arg); } else { PRINTF("[tx_%d] Failed to get event (0x%x)\n", User Manual CFR0012 Revision 2.2 113 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide arg, status); break; } actual_flags); } } if (actual_flags != 0x1) { PRINTF("[tx_%d] Wrong event get (0x%x)\n", arg, break; } Thread #6 and #7 Function tx_6_7 marks the entry point of both thread_6 and thread_7. Both threads have a priority of 8, which makes them the fifth and sixth threads in the demonstration system to execute. Each thread is processed in the same manner: get mutex_0 twice, sleep for 5 timer ticks, release mutex_0 twice, and then repeat the sequence. Notice that each thread suspends whenever mutex_0 is unavailable. Also, both threads use the same function for their main processing. This presents no problems because they both have their own unique stack, and C is naturally reentrant. Each thread determines which one it is by examination of the thread input parameter, which is set up when they are created. static void tx_6_7(ULONG arg) { ... ... /* * This function is executed from thread 6 and thread 7. * As the loop below shows, * these function compete for ownership of mutex_0. */ while (1) { /* Get the mutex with suspension. */ PRINTF("[tx_%d] #1 Mutex get TRY\n", arg); status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER); /* Check status. */ if (status == TX_SUCCESS) { PRINTF("[tx_%d] #1 Mutex get OK\n", arg); } else { PRINTF("[tx_%d] #1 Mutex get FAIL (0x%x)\n", arg, status); break; } /* Get the mutex again with suspension. * This shows that an owning thread may retrieve the mutex * it owns multiple times. */ PRINTF("[tx_%d] #2 Mutex get TRY\n", arg); status = tx_mutex_get(&mutex_0, TX_WAIT_FOREVER); /* Check status. */ if (status == TX_SUCCESS) { PRINTF("[tx_%d] #2 Mutex get OK\n", arg); } else { PRINTF("[tx_%d] #2 Mutex get FAIL (0x%x)\n", arg, status); break; } /* Sleep for 5 ticks to hold the mutex. */ User Manual CFR0012 Revision 2.2 114 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide twice. */ } } tx_thread_sleep(5); // 50 msec /* Release the mutex. */ PRINTF("[tx_%d] #1 Mutex put TRY\n", arg); status = tx_mutex_put(&mutex_0); /* Check status. */ if (status == TX_SUCCESS) { PRINTF("[tx_%d] #1 Mutex put OK\n", arg); } else { PRINTF("[tx_%d] #1 Mutex put FAIL (0x%x)\n", arg, status); break; } /* Release the mutex again. * This will actually release ownership since it was obtained PRINTF("[tx_%d] #2 mutex put TRY\n", arg); status = tx_mutex_put(&mutex_0); /* Check status. */ if (status == TX_SUCCESS) { PRINTF("[tx_%d] #2 Mutex put OK\n", arg); } else { PRINTF("[tx_%d] #2 Mutex put FAIL (0x%x)\n", arg, status); break; } tx_thread_sleep(400); // 400 ticks = 4 seconds Thread #8 Function tx_8 marks the entry point of the thread. Thread_8 is the standalone thread in the demonstration system to execute. The process of Thread_8 is: create byte pool, allocate byte pool, release byte pool, and then repeat the sequence. Thread_8 shows the usage of byte-pool processing. static void tx_8(ULONG arg) { ... ... /* --- For byte pool usage ---------------------------------- */ /* Create a byte memory pool */ tx_byte_pool_create(&byte_pool_0, // byte pool pointer "byte pool 0", // byte pool name byte_pool_buffer, // byte pool start pointer BYTE_POOL_SIZE); // byte pool size /* Allocate the test buffer for temporary buffer */ status = tx_byte_allocate(&byte_pool_0, // Pool pointer (void **)&first_ptr, // allocated pointer 128, // requested size TX_NO_WAIT); // wait option if (status != TX_SUCCESS) { PRINTF("[%s] #1 Failed to allocate from byte pool (0x%x)\n", __func__, status); goto finish; } else { PRINTF("Success to allocate 128 Bytes from byte_pool_0 ...\n"); } User Manual CFR0012 Revision 2.2 115 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide status = tx_byte_allocate(&byte_pool_0, (void **)&second_ptr, 64, TX_NO_WAIT); if (status != TX_SUCCESS) { PRINTF("#2 Failed to allocate from byte pool (0x%x)\n", status); goto finish; } else { PRINTF("Success to allocate 64 Bytes from byte_pool_0 ...\n"); } status = tx_byte_allocate(&byte_pool_0, (void **)&third_ptr, 1024, TX_NO_WAIT); if (status != TX_SUCCESS) { PRINTF("#3 Failed to allocate from byte pool (0x%x)\n",status); goto finish; } else { PRINTF("Success to allocate 1024 Bytes from byte_pool_0 ...\n"); } finish : if (first_ptr != TX_NULL); tx_byte_release(first_ptr); if (second_ptr != TX_NULL); tx_byte_release(second_ptr); if (third_ptr != TX_NULL); tx_byte_release(third_ptr); tx_byte_pool_delete(&byte_pool_0); } 5.2 RTC Timer with DPM Function This sample code describes how to use the RTC Timer to operate in DPM Sleep mode 1, 2, and 3. 5.2.1 How to Run 1. Open the workspace for the RTC timer sample application as follows: ~/SDK/sample/Peripheral/RTC_Timer_DPM/build/DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. 3. Use the console to set up the Wi-Fi station interface and enable DPM mode. 4. After boot, the RTC timer sample application starts automatically. Notice that the user can select DPM Sleep mode in the sample code. /* Defines for sample */ #undef SAMPLE_FOR_DPM_SLEEP_1 #define SAMPLE_FOR_DPM_SLEEP_2 #undef SAMPLE_FOR_DPM_SLEEP_3 // Sleep Mode 1 // Sleep Mode 2 // Sleep Mode 3 5.2.2 Application Initialization The User Application may retrieve user configuration data from NVRAM or retention memory (RTM) after boot is completed and this can be accomplished according to the DPM mode status. The User Application can use retention memory if DPM mode is enabled. ThreadX timer primitive is used rather than RTC timer in normal mode. /* This sample function always run on DPM mode ... */ rtm_len = dpm_user_mem_get(SAMPLE_RTC_TIMER, (UCHAR **)&rtc_sample_info); if (rtm_len == 0) { status = dpm_user_mem_alloc(SAMPLE_RTC_TIMER, (VOID **)&rtc_sample_info, sizeof(rtc_sample_info_t), 100); User Manual CFR0012 Revision 2.2 116 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide if (status != TX_SUCCESS) { PRINTF("[%s] Failed to allocate RTM area !!!\n", __func__); dpm_app_unregister(SAMPLE_RTC_TIMER); return; } /* Initialize allocated retention-memory buffer */ memset(rtc_sample_info, 0x00, sizeof(rtc_sample_info_t)); } else if (rtm_len != sizeof(rtc_sample_info_t)) { PRINTF("[%s] Invalid RTM alloc size (%d)\n", __func__, rtm_len); dpm_app_unregister(SAMPLE_RTC_TIMER); return; } 5.2.3 Timer Creation: DPM Sleep mode 1 DPM Sleep mode 1 means power-off except for RTC resources and the retention memory area, if needed. But in this case, maintaining the retention memory area cannot be guaranteed. A DUT with DPM Sleep mode 1 can be woken up by just an external wakeup resource and run the same as Power-on-Reset. To go to DPM Sleep mode 1, just run API dpm_sleep_start_mode_1(). void rtc_timer_sample(ULONG arg) { /* FALSE : Not maintain RTM area for DPM operation */ dpm_sleep_start_mode_1(TRUE); } 5.2.4 Timer Creation: DPM Sleep mode 2 DPM Sleep mode 2 means power-off with RTC alive and retention memory area if needed. A DUT with DPM Sleep mode 2 can be woken up by an external wakeup source and RTC timer resources. When a DUT wakes up from both wakeup sources (external or RTC), it runs the same as a normal POR with saved retention memory area if configured before Sleep mode 2. To go to DPM Sleep mode 2, just run API dpm_sleep_start_mode_2(). void rtc_timer_sample(ULONG arg) { unsigned long long wakeup_time; /* Just work in case of RTC timer wakeup */ if ( dpm_mode_is_wakeup() == DPM_WAKEUP && dpm_get_wakeup_source() != WAKEUP_COUNTER_WITH_RETENTION) { dpm_app_sleep_ready_set(SAMPLE_RTC_TIMER); return; } /* TRUE : Maintain RTM area for DPM operation */ wakeup_time = MICROSEC_FOR_ONE_SEC * RTC_TIMER_WAKEUP_ONCE; dpm_sleep_start_mode_2(wakeup_time, TRUE); } User Manual CFR0012 Revision 2.2 117 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 5.2.5 Timer Creation: DPM Sleep mode 3 DPM Sleep mode 3 means power-off with RTC resources and retention memory area alive, plus pTIM running. This sleep mode is what we normally call "DPM Sleep" (aka "connected sleep". The other two sleep modes are "unconnected sleep"). For more detailed information on DPM Sleep mode 3, please see the DA16200 EVK User Guide [2]. This sample code shows how to create a one-shot RTC timer and a periodic RTC timer. void rtc_timer_sample(ULONG arg) { ULONG status; if (dpm_mode_is_wakeup() == NORMAL_BOOT) { /* * Create a timer only once during normal boot. */ dpm_app_sleep_ready_clear(SAMPLE_RTC_TIMER); /* One-Shot timer */ status = dpm_timer_create(SAMPLE_RTC_TIMER, "timer1", rtc_timer_dpm_once_cb, RTC_TIMER_WAKEUP_ONCE, 0); if (status == SAMPLE_DPM_TIMER_ERR) { PRINTF(">>> Start test DPM sleep mode 3 : Fail to create One-Shot timer\n"); tx_thread_sleep(2); // Delay to display above message on console ... } /* Periodic timer */ status = dpm_timer_create(SAMPLE_RTC_TIMER, "timer2", rtc_timer_dpm_periodic_cb, RTC_TIMER_WAKEUP_PERIOD, RTC_TIMER_WAKEUP_PERIOD); if (status == SAMPLE_DPM_TIMER_ERR) { PRINTF(">>> Start test DPM sleep mode 3 : Fail to create Periodic timer\n"); tx_thread_sleep(2); // Delay to display above message on console ... } dpm_app_sleep_ready_set(SAMPLE_RTC_TIMER); } else { /* Notice initialize done to DPM module */ dpm_app_wakeup_done(SAMPLE_RTC_TIMER); } while (1) { /* Nothing to do... */ tx_thread_sleep(100); } User Manual CFR0012 Revision 2.2 118 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 5.2.6 Timer Creation: DPM Sleep mode 3 DPM Sleep mode 3 means power-off with RTC resources and retention memory area alive, plus pTIM running. This sleep mode is what we normally call "DPM Sleep" (aka "connected sleep". The other two sleep modes are "unconnected sleep"). For more detailed information on DPM Sleep mode 3, please see the DA16200 EVK User Guide [2]. This sample code shows how to create a one-shot RTC timer and a periodic RTC timer, and how to use retention memory. case 3 : { // DPM Sleep Mode 3 /* Notice initialize done to DPM module */ dpm_app_wakeup_done(SAMPLE_RTC_TIMER); /* Create RTC timer for DPM wakeup */ if (dpm_mode_is_wakeup() == NORMAL_BOOT) { /* One-Shot RTC timer */ oneshot_timer_id = dpm_timer_create( RTC_TIMER_WAKEUP_ONE_SHOT, SAMPLE_RTC_TIMER, oneshot_timer_id, ONESHOT_TIMER, rtc_timer_dpm_oneshot_cb); rtc_sample_info->oneshot_timer_id = oneshot_timer_id; PRINTF(">>> Start test DPM sleep mode 3 : One-Shot timer\n"); /* Periodic RTC timer */ periodic_timer_id = dpm_timer_create( RTC_TIMER_WAKEUP_PERIOD, SAMPLE_RTC_TIMER, periodic_timer_id, PERIODIC_TIMER, rtc_timer_dpm_periodic_cb); rtc_sample_info->periodic_timer_id = periodic_timer_id; PRINTF(">>> Start test DPM sleep mode 3 : periodic_count=%d\n", rtc_sample_info->periodic_count); dpm_app_sleep_ready_set(SAMPLE_RTC_TIMER); } else if (dpm_mode_is_wakeup() == DPM_WAKEUP) { // User code when waked up from DPM sleep mode 3... } 5.3 Get SCAN Result Sample 5.3.1 How to Run 1. Open the workspace for the SCAN result sample application as follows: ~/SDK/sample/ETC/Get_Scan_Result/build/DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. 3. After the boot is completed, the get_scan_result sample will start automatically. User Manual CFR0012 Revision 2.2 119 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide Figure 60: get_scan_result Sample Test 5.3.2 Sample Overview This sample shows how to use the void get_scan_result((void *)user_buf) API, to get the SCAN result on STA mode and Soft-AP mode. 5.3.3 Application Initialization The get_scan_result_sample function executes after the basic ThreadX initialization is completed. This sample just calls the user API "void get_scan_result()". void get_scan_result_sample(ULONG arg) { char *user_buf = NULL; scan_result_t *scan_result; int i; /* Allocate buffer to get scan result */ user_buf = malloc(SCAN_RSP_BUF_SIZE); /* Get scan result */ get_scan_result((void *) user_buf); ... ... } 5.3.4 Get SCAN Result After the API "get_scan_result()" has run, the user/developer can use the received data. This sample code shows how to display the scan list in the console. /* Display result on console */ scan_result = (scan_result_t *)user_buf; PRINTF("\n>>> Scanned AP List (Total : %d) \n", scan_result->ssid_cnt); for (i = 0; i < scan_result->ssid_cnt; i++) { User Manual CFR0012 Revision 2.2 120 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide PRINTF(" %02d) SSID: %s, RSSI: %d, Security: %d\n", i + 1, scan_result->scanned_ap_info[i].ssid, scan_result->scanned_ap_info[i].rssi, scan_result->scanned_ap_info[i].auth_mode) ; } /* Buffer free */ free(user_buf); } The SCAN results are stored in the following data structure format: typedef struct scanned_ap_info { int auth_mode; int rssi; char ssid[128]; } scanned_ap_info_t; typedef struct scan_result_to_app { int ssid_cnt; scanned_ap_info_t scanned_ap_info[MAX_SCAN_AP_CNT]; } scan_result_t; 5.4 SoftAP Provisioning Sample 5.4.1 How to Run 1. Open the workspace for the SoftAP Provisioning sample application as follows: ~/SDK/sample/ETC/SoftAp_Provisioning/build/DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. 3. After boot is completed, the softap_provisioning_sample will start automatically. 4. Check SoftAP mode and if not SoftAP mode, then do factory reset by factory button. 5.4.2 Application Initialize Create TCP Server Task for TCP connection TCPServerThreadPtr = (TX_THREAD*)app_common_malloc(sizeof(TX_THREAD)); TCPServerThreadStack = (char*)app_common_malloc(stackSize); tx_thread_create( TCPServerThreadPtr, "ProvTCPServer", app_provision_TCP_server_thread, _mode, TCPServerThreadStack, stackSize, OAL_PRI_APP(4), OAL_PRI_APP(4), TX_NO_TIME_SLICE, TX_AUTO_START); Create TLS Server Task for TLS connection TLSServerThreadPtr = (TX_THREAD*)app_common_malloc(sizeof(TX_THREAD)); TLSServerThreadStack = (char*)app_common_malloc(stackSize); User Manual CFR0012 Revision 2.2 121 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide tlsinfo = (TLSInfo *)app_common_malloc(sizeof(TLSInfo)); tlsinfo->mode = _mode; tlsinfo->config = &app_prov_tls_svr_config; tx_thread_create( TLSServerThreadPtr, "ProvTLSServer", app_provision_TLS_server_thread, (ULONG)tlsinfo, TLSServerThreadStack, stackSize, OAL_PRI_APP(4), OAL_PRI_APP(4), TX_NO_TIME_SLICE, TX_AUTO_START); Create TCP/TLS Client Task for request action and response PROVClientThreadPtr = (TX_THREAD*)app_common_malloc(sizeof(TX_THREAD)); PROVClinetThreadStack = (char*)app_common_malloc(stackSize); tx_thread_create( PROVClientThreadPtr, "ProvClient", app_provision_switch_client_thread, (ULONG)tlsinfo, PROVClinetThreadStack, stackSize, OAL_PRI_APP(5), OAL_PRI_APP(5), TX_NO_TIME_SLICE, TX_AUTO_START); 5.4.3 Data Communication with the Mobile App The TCP Data receive in while () loop of app_provision_TCP_server_thread (). The TLS Data receive in while () of app_prov_run_tls_svr (). Each received data was parsed by json and pass to app_provision_switch_client_thread (). In Client thread run command action and send the action result to the Mobile App. Receive Data Json Parser: app_provisioning_json_parser() json_recv_data = cJSON_Parse(_recData); child_object = cJSON_GetObjectItem(json_recv_data, "msgType"); if (child_object != NULL) { APRINTF("MSG Type [%d] \n",child_object->valueint); if (child_object->valueint == SET_AP_SSID_PW) { APRINTF_I("[SET SSID , PW]\n"); cJSON *child_ssid = cJSON_GetObjectItem(json_recv_data, "ssid"); cJSON *child_pw = cJSON_GetObjectItem(json_recv_data, "pw"); cJSON *child_url = cJSON_GetObjectItem(json_recv_data, "url"); memset(new_SSID, 0, MAX_AP_SSID_SIZE); memset(new_pw, 0, MAX_AP_PASSWORD_SIZE); memset(server_URL, 0, MAX_CUSTOMER_SERVER_SIZE); new_pw_size = 0; new_SSID_size = 0; server_URL_size = 0; User Manual CFR0012 Revision 2.2 122 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide if (child_ssid != NULL) { new_SSID_size = strlen(child_ssid->valuestring); strcpy(new_SSID,child_ssid->valuestring); } if (child_pw != NULL) { new_pw_size = strlen(child_pw->valuestring); strcpy(new_pw,child_pw->valuestring); } if (child_url != NULL) { server_URL_size = strlen(child_url->valuestring); strcpy(server_URL,child_url->valuestring); } retStatus = SET_AP_SSID_PW; } else { } } else if (child_object->valueint == CONNECTED) { retStatus = CONNECTED; } else if (child_object->valueint == REQ_RESCAN) { retStatus = REQ_RESCAN; } else if (child_object->valueint == REQ_REBOOT) { cJSON *child_finish = cJSON_GetObjectItem(json_recv_data, "finishCMD"); retStatus = REQ_REBOOT; } else if (child_object->valueint == REQ_SOCKET_TYPE) { cJSON *socketType = cJSON_GetObjectItem(json_recv_data, "SOCKET_TYPE"); socket_app = socketType->valueint; retStatus = REQ_SOCKET_TYPE; } retStatus = CMD_ERROR; cJSON_Delete(json_recv_data); TCP Socket Data Send to Mobile App: app_provision_send_tcp_data() nx_packet_allocate(provision_TCP_mem_pool, &tcp_tx_pkt, NX_TCP_PACKET, TX_WAIT_FOREVER); nx_packet_data_append(tcp_tx_pkt, _data, _dataSize, provision_TCP_mem_pool, TX_WAIT_FOREVER); status = nx_tcp_socket_send(provision_TCP_socket, tcp_tx_pkt, TX_WAIT_FOREVER); if (status) { APRINTF("[%s:%d]failed to send packet(0x%02x)\n", __func__, __LINE__, status); } User Manual CFR0012 Revision 2.2 123 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide nx_packet_release(tcp_tx_pkt); tcp_tx_pkt = NX_NULL; TLS Socket Data Send to Mobile App: app_provision_send_tls_data() while ((status = mbedtls_ssl_write(config->ssl_ctx,(const unsigned char *) data, dataSize)) <= 0) { if ((status != MBEDTLS_ERR_SSL_WANT_READ) && (status != DTLS_ERR_SSL_WANT_WRITE)) { APRINTF_E("[%s:%d] failed to write ssl packet(0x%x)\n", __func__, __LINE__, -status); } } 5.4.4 SoftAP Provisioning Scenario 1. System Mode change to SoftAP by Factory_reset button. Soft-AP is Ready (ec:9f:0d:9f:f9:39) >>> Start Provisioning Through Mobile App. Sample <<< ======================================================= [Start Provisioning with TCP/TLS] .. Soft AP Mode ======================================================= [app_provision_TCP_server_thread] Create TCP... Finding HomeAP List ... 2. Mobile App connect to the fixed SoftAP SSID (Dialog_DA16200) with the fixed PW (1234567890) [ListenSoc] Make Listen Wait Accept... AP-STA-CONNECTED 68:5a:cf:72:ba:dc Established TLS/TCP session(10.0.0.2:44466) success nx_packet_length_get 27 3. Check connection verify and send AP list to Mobile App. MSG Type [0] [CONNECTED] Recv MSG .. [0] success nx_packet_length_get 121 4. Mobile App select what it wanted and send selected AP information. MSG Type [1] [SET SSID , PW] [SSID] -> AP-101-301 size = 10 [PW] -> 0123456789 size = 10 [SERVER URL] -> https://www.dialog-semiconductor.com size = 36 Recv MSG .. [1] app_send_tls_json_data 5. System Reboot to Station mode and connect to selected AP. [CMD APP] STA_mode_reset.... factory_reset ... Connection COMPLETE to e8:54:84:06:5d:08 -- DHCP Client WLAN0: SEL(3) Success to connect Wi-Fi ... -- DHCP Client WLAN0: REQ(4) -- DHCP Client WLAN0: BOUND(5) User Manual CFR0012 Revision 2.2 124 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide Assigned addr netmask gateway DNS addr : 221.140.118.17 : 255.255.255.192 : 221.140.118.1 : 210.220.163.82 DHCP Server IP : 172.23.237.228 Lease Time : 01h 00m 00s Renewal Time : 00h 30m 00s User Manual CFR0012 Revision 2.2 125 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 6 Crypto Examples 6.1 Crypto Algorithms AES The AES algorithms sample application demonstrates common use cases of AES ciphers such as CBC, CFB, and ECB, and so on. The DA16200 SDK includes an "mbedTLS" library. The API of AES algorithms is the same as what the "mbedTLS" library provides. This section describes how the AES algorithm sample application is built and works. 6.1.1 How to Run 1. Open the workspace for the Crypto Algorithms of the AES application as follows: .\sample\Crypto\Crypto_AES\build\DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. The example application runs five types of crypto algorithms: AES-CBC-128, 192, and 256 AES-CFB128-128, 192, and 256 AES-ECB-128, 192, and 256 AES-ECB-128, 192, and 256 AES-CTR-128 AES-CCM * AES-CBC-128 (dec): passed * AES-CBC-128 (enc): passed * AES-CBC-192 (dec): passed * AES-CBC-192 (enc): passed * AES-CBC-256 (dec): passed * AES-CBC-256 (enc): passed * AES-CFB128-128 (dec): passed * AES-CFB128-128 (enc): passed * AES-CFB128-192 (dec): passed * AES-CFB128-192 (enc): passed * AES-CFB128-256 (dec): passed * AES-CFB128-256 (enc): passed * AES-ECB-128 (dec): passed * AES-ECB-128 (enc): passed * AES-ECB-192 (dec): passed * AES-ECB-192 (enc): passed * AES-ECB-256 (dec): passed * AES-ECB-256 (enc): passed * AES-CTR-128 (dec): passed * AES-CTR-128 (enc): passed * CCM-AES (enc): passed * CCM-AES (dec): passed * AES-GCM-128 (enc): passed * AES-GCM-192 (enc): passed * AES-GCM-256 (enc): passed * AES-GCM-128 (dec): passed * AES-GCM-192 (dec): passed * AES-GCM-256 (dec): passed * AES-OFB-128 (dec): passed * AES-OFB-128 (enc): passed * AES-OFB-192 (dec): passed * AES-OFB-192 (enc): passed * AES-OFB-256 (dec): passed * AES-OFB-256 (enc): passed User Manual CFR0012 Revision 2.2 126 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 6.1.2 Application Initialization DA16200 SDK provides an "mbedTLS" library. This library helps with an easy implementation of the user application. The example below describes how the user uses the AES algorithms of the "mbedTLS" library to encrypt and decrypt data. void crypto_sample_aes(ULONG arg) { #if defined(MBEDTLS_CIPHER_MODE_CBC) crypto_sample_aes_cbc(); #endif /* MBEDTLS_CIPHER_MODE_CBC */ #if defined(MBEDTLS_CIPHER_MODE_CFB) crypto_sample_aes_cfb(); #endif /* MBEDTLS_CIPHER_MODE_CFB */ crypto_sample_aes_ecb(); #if defined(MBEDTLS_CIPHER_MODE_CTR) crypto_sample_aes_ctr(); #endif /* MBEDTLS_CIPHER_MODE_CTR */ crypto_sample_aes_ccm(); crypto_sample_aes_gcm(); #if defined(MBEDTLS_CIPHER_MODE_OFB) crypto_sample_aes_ofb(); #endif /* MBEDTLS_CIPHER_MODE_OFB */ return ; } 6.1.3 Crypto Algorithm for AES-CBC-128, 192, and 256 DA16200 supports crypto algorithm for AES-CBC-128, 192, and 256. In order to explain how AESCBC works, see the test vector in http://csrc.nist.gov/archive/aes/rijndael/rijndael-vals.zip. int crypto_sample_aes_cbc() { mbedtls_aes_context *ctx = NULL; // Initialize the AES context. mbedtls_aes_init(ctx); for (i = 0; i < 6; i++) { u = i >> 1; v = i & 1; PRINTF("* AES-CBC-%3d (%s): ", 128 + u * 64, (v == MBEDTLS_AES_DECRYPT) ? "dec" : "enc"); if (v == MBEDTLS_AES_DECRYPT) { // Set the decryption key. mbedtls_aes_setkey_dec(ctx, key, 128 + u * 64); // Performs an AES-CBC decryption operation on full blocks. for (j = 0; j < CRYPTO_SAMPLE_AES_LOOP_COUNT ; j++) { mbedtls_aes_crypt_cbc(ctx, v, 16, iv, buf, buf); } } else { // Set the encryption key. User Manual CFR0012 Revision 2.2 127 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide mbedtls_aes_setkey_enc(ctx, key, 128 + u * 64); // Performs an AES-CBC encryption operation on full blocks. for (j = 0 ; j < CRYPTO_SAMPLE_AES_LOOP_COUNT ; j++) { unsigned char tmp[16] = {0x00,}; mbedtls_aes_crypt_cbc(ctx, v, 16, iv, buf, buf); memcpy(tmp, prv, 16); memcpy(prv, buf, 16); memcpy(buf, tmp, 16); } } } // Clear the AES context. mbedtls_aes_free(ctx); } The mbedtls_aes_context is the AES context-type definition to use the AES algorithm. It is initialized by function mbedtls_aes_init. Function mbedtls_aes_crypt_cbc does an AES-CBC encryption or decryption operation on full blocks. And it does the operation defined in the mode parameter (encrypt/decrypt), on the input data buffer defined in the input parameter. To do encryption or decryption, function mbedtls_aes_setkey_enc or mbedtls_aes_setkey_dec should be called before. After the operation is finished, function mbedtls_aes_free should be called to clear the AES context. 6.1.4 Crypto Algorithm for AES-CFB128-128, 192, and 256 DA16200 supports a crypto algorithm for AES-CFB128-128, 192, and 256. In order to explain how AES-CFB128 works, see the test vector in http://csrc.nist.gov/publications/nistpubs/800-38a/sp80038a.pdf. int crypto_sample_aes_cfb() { mbedtls_aes_context *ctx = NULL; // Initialize the AES context. mbedtls_aes_init(ctx); for (i = 0; i < 6; i++) { u = i >> 1; v = i & 1; PRINTF("* AES-CFB128-%3d (%s): ", 128 + u * 64, (v == MBEDTLS_AES_DECRYPT) ? "dec" : "enc"); // Set the key. mbedtls_aes_setkey_enc(ctx, key, 128 + u * 64); if (v == MBEDTLS_AES_DECRYPT) { // Perform an AES-CFB128 decryption operation. mbedtls_aes_crypt_cfb128(ctx, v, 64, &offset, iv, buf, buf); } else { // Perform an AES-CFB128 encryption operation. mbedtls_aes_crypt_cfb128(ctx, v, 64, &offset, iv, buf, buf); } } // Clear the AES context. mbedtls_aes_free(ctx); } User Manual CFR0012 Revision 2.2 128 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide The mbedtls_aes_context is the AES context-type definition to use AES algorithm. It is initialized by function mbedtls_aes_init. Function mbedtls_aes_crypt_cfb128 does AES-CFB128 encryption or decryption. And it does the operation defined in the mode parameter (encrypt or decrypt) on the input data buffer defined in the input parameter. For CFB, the user should set up the context with function mbedtls_aes_setkey_enc, regardless of whether you do encryption or decryption operations, that is, regardless of the mode parameter. This is because CFB mode uses the same key schedule for encryption and decryption. After the operation is finished, function mbedtls_aes_free should be called to clear the AES context. 6.1.5 Crypto Algorithm for AES-ECB-128, 192, and 256 DA16200 supports crypto algorithm for AES-ECB-128, 192, and 256. In order to explain how AESECB works, see the test vector in http://csrc.nist.gov/archive/aes/rijndael/rijndael-vals.zip. int crypto_sample_aes_ecb() { mbedtls_aes_context *ctx = NULL; // Initialize the AES context. mbedtls_aes_init(ctx); for (i = 0; i < 6; i++) { u = i >> 1; v = i & 1; PRINTF("* AES-ECB-%3d (%s): ", 128 + u * 64, (v == MBEDTLS_AES_DECRYPT) ? "dec" : "enc"); if (v == MBEDTLS_AES_DECRYPT) { // Set the decryption key. mbedtls_aes_setkey_dec(ctx, key, 128 + u * 64); // Perform an AES single-block decryption operation. for (j = 0 ; j < CRYPTO_SAMPLE_AES_LOOP_COUNT ; j++) { mbedtls_aes_crypt_ecb(ctx, v, buf, buf); } } else { // Set the encryption key. mbedtls_aes_setkey_enc(ctx, key, 128 + u * 64); // Perform an AES single-block encryption operation. for (j = 0 ; j < CRYPTO_SAMPLE_AES_LOOP_COUNT ; j++) { mbedtls_aes_crypt_ecb(ctx, v, buf, buf); } } } // Clear the AES context. mbedtls_aes_free(ctx); } The mbedtls_aes_context is the AES context-type definition to use the AES algorithm. It is initialized by function mbedtls_aes_init. Function mbedtls_aes_crypt_ecb does an AES single-block encryption or decryption operation. And it does the operation defined in the mode parameter (encrypt or decrypt) on the input data buffer defined in the input parameter. Function mbedtls_aes_init and either function mbedtls_aes_setkey_enc function or function mbedtls_aes_setkey_dec should be called before the first call to this API with the same context. After the operation is finished, function mbedtls_aes_free should be called to clear the AES context. User Manual CFR0012 Revision 2.2 129 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 6.1.6 Crypto Algorithm for AES-CTR-128 DA16200 supports the crypto algorithm for AES-CTR-128. To explain how AES-CTR works, see the Test Vectors section in http://www.faqs.org/rfcs/rfc3686.html. int crypto_sample_aes_ctr() { mbedtls_aes_context *ctx = NULL; // Initialize the AES context. mbedtls_aes_init(ctx); for (i = 0; i < 2; i++) { v = i & 1; PRINTF("* AES-CTR-128 (%s): ", (v == MBEDTLS_AES_DECRYPT) ? "dec" : "enc"); // Set the key. mbedtls_aes_setkey_enc(ctx, key, 128); if (v == MBEDTLS_AES_DECRYPT) { // Perform an AES-CTR decryption operation. mbedtls_aes_crypt_ctr(ctx, len, &offset, nonce_counter, stream_block, buf, buf); } else { // Perform an AES-CTR encryption operation. mbedtls_aes_crypt_ctr(ctx, len, &offset, nonce_counter, stream_block, buf, buf); } } // Clear the AES context. mbedtls_aes_free(ctx); } The mbedtls_aes_context is the AES context-type definition to use AES algorithm. It is initialized by function mbedtls_aes_init. Function mbedtls_aes_crypto_ctr does an AES-CTR encryption or decryption operation. And it does the operation defined in the mode parameter (encrypt/decrypt) on the input data buffer, defined in the input parameter. Due to the nature of CTR, you should use the same key schedule for both encryption and decryption operations. Therefore, use the context initialized with function mbedtls_aes_setkey_enc for both MBEDTLS_AES_ENCRYPT and MBEDTLS_AES_DECRYPT. After the operation is finished, call function mbedtls_aes_free to clear the AES context. 6.1.7 Crypto Algorithm for AES-CCM-128, 192, and 256 DA16200 supports a crypto algorithm for AES-CCM-128, 192, and 256. To explain how AES-CCM works, see the test vector in SP800-38C Appendix C #1. int crypto_sample_aes_ccm() { mbedtls_ccm_context *ctx = NULL; // Initialize the CCM context mbedtls_ccm_init(ctx); /* Initialize the CCM context set in the ctx parameter * and sets the encryption key. */ ret = mbedtls_ccm_setkey(ctx, MBEDTLS_CIPHER_ID_AES, crypto_sample_ccm_key, 8 * sizeof(crypto_sample_ccm_key)); User Manual CFR0012 Revision 2.2 130 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide PRINTF("* CCM-AES (enc): "); // Encrypt a buffer using CCM. ret = mbedtls_ccm_encrypt_and_tag(ctx, crypto_sample_ccm_msg_len, crypto_sample_ccm_iv, crypto_sample_ccm_iv_len, crypto_sample_ccm_ad, crypto_sample_ccm_add_len, crypto_sample_ccm_msg, out, out + crypto_sample_ccm_msg_len, crypto_sample_ccm_tag_len); PRINTF("* CCM-AES (dec): "); // Perform a CCM* authenticated decryption of a buffer. ret = mbedtls_ccm_auth_decrypt(ctx, crypto_sample_ccm_msg_len, crypto_sample_ccm_iv, crypto_sample_ccm_iv_len, crypto_sample_ccm_ad, crypto_sample_ccm_add_len, crypto_sample_ccm_res, out, crypto_sample_ccm_res + crypto_sample_ccm_msg_len, crypto_sample_ccm_tag_len); // Clear the CCM context. mbedtls_ccm_free(ctx); } The mbedtls_ccm_context is the CCM context-type definition for the CCM authenticated encryption mode for block ciphers. It is initialized by function mbedtls_ccm_init. Function mbedtls_ccm_setkey initializes the CCM context set in the ctx parameter and sets the encryption key. Function mbedtls_ccm_encrypt_and_tag encrypts a buffer with CCM. And function mbedtls_ccm_auth_decrypt does CCM-authenticated decryption of a buffer. After the operation is finished, call function mbed_ccm_free to release and clear the specified CCM context and underlying cipher subcontext. 6.1.8 Crypto Algorithm for AES-GCM-128, 192, and 256 DA16200 supports a crypto algorithm for AES-GCM-128, 192, and 256. To explain how AES-GCM works, see the test vector in the GCM test vectors of CSRC (http://csrc.nist.gov/groups/STM/cavp/documents/mac/gcmtestvectors.zip). int crypto_sample_aes_gcm() { //The GCM context structure. mbedtls_gcm_context *ctx = NULL; mbedtls_cipher_id_t cipher = MBEDTLS_CIPHER_ID_AES; // Initialize the specified GCM context. mbedtls_gcm_init(ctx); // AES-GCM Encryption Test for (j = 0; j < 3; j++) { PRINTF("* AES-GCM-%3d (%s): ", key_len, "enc"); // Associate a GCM context with a cipher algorithm and a key. mbedtls_gcm_setkey(ctx, cipher, crypto_sample_gcm_key, key_len); // Perform GCM encryption of a buffer. ret = mbedtls_gcm_crypt_and_tag(ctx, MBEDTLS_GCM_ENCRYPT, sizeof(crypto_sample_gcm_pt), crypto_sample_gcm_iv, sizeof(crypto_sample_gcm_iv), crypto_sample_gcm_additional, sizeof(crypto_sample_gcm_additional), User Manual CFR0012 Revision 2.2 131 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide crypto_sample_gcm_pt, buf, 16, tag_buf); // Clear a GCM context and the underlying cipher sub-context. mbedtls_gcm_free(ctx); } //AES-GCM Decryption Test for (j = 0; j < 3; j++) { PRINTF("* AES-GCM-%3d (%s): ", key_len, "dec"); // Associate a GCM context with a cipher algorithm and a key. mbedtls_gcm_setkey(ctx, cipher, crypto_sample_gcm_key, key_len); // Perform GCM decryption of a buffer. ret = mbedtls_gcm_crypt_and_tag(ctx, MBEDTLS_GCM_DECRYPT, sizeof(crypto_sample_gcm_pt), crypto_sample_gcm_iv, sizeof(crypto_sample_gcm_iv), crypto_sample_gcm_additional, sizeof(crypto_sample_gcm_additional), crypto_sample_gcm_ct[j], buf, 16, tag_buf); // Clear a GCM context and the underlying cipher sub-context. mbedtls_gcm_free(ctx); } } The mbedtls_gcm_context is the GCM context-type definition. It is initialized by function mbedtls_gcm_init. Function mbedtls_gcm_setkey associates a GCM context with a cipher algorithm (AES) and a key. Function mbedtls_gcm_crypt_and_tag does GCM encryption or decryption of a buffer by the second parameter. After the operation is finished, function mbed_gcm_free should be called to clear a GCM context and underlying cipher sub-context. 6.1.9 Crypto Algorithm for AES-OFB-128, 192, and 256 DA16200 supports crypto algorithm for AES-OFB-128, 192, and 256. To explain how AES-OFB works, see the test vector in the OFB test vectors of CSRC (https://csrc.nist.gov/publications/detail/sp/800-38a/final). int crypto_sample_aes_ofb() { mbedtls_aes_context *ctx = NULL; // Initialize the AES context. mbedtls_aes_init(ctx); // Test OFB mode for (i = 0; i < 6; i++) { PRINTF("* AES-OFB-%3d (%s): ", keybits, (v== MBEDTLS_AES_DECRYPT) ? "dec" : "enc"); memcpy(iv, crypto_sample_aes_ofb_iv, 16); memcpy(key, crypto_sample_aes_ofb_key[u], keybits / 8); // Set the encryption key. ret = mbedtls_aes_setkey_enc(ctx, key, keybits); if (v == MBEDTLS_AES_DECRYPT) { memcpy(buf, crypto_sample_aes_ofb_ct[u], 64); expected_out = crypto_sample_aes_ofb_pt; User Manual CFR0012 Revision 2.2 132 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide } else { memcpy(buf, crypto_sample_aes_ofb_pt, 64); expected_out = crypto_sample_aes_ofb_ct[u]; } // Perform an AES-OFB (Output Feedback Mode) encryption or decryption operation. ret = mbedtls_aes_crypt_ofb(ctx, 64, &offset, iv, stream_block, buf, buf); } // Clear the AES context. mbedtls_aes_free(ctx); } The mbedtls_aes_context is the AES context-type definition to use the AES algorithm. It is initialized by function mbedtls_aes_init. Function mbedtls_aes_crypt_ofb does an AES-OFB (Output Feedback Mode) encryption or decryption operation. For OFB, the user should set up the context with the function mbedtls_aes_setkey_enc, regardless of whether the user does an encryption or decryption operation. This is because OFB mode uses the same key schedule for encryption and decryption. The OFB operation is identical for encryption or decryption, therefore no operation mode needs to be specified. After the operation is finished, call function mbedtls_aes_free to clear the AES context. 6.2 Crypto Algorithms DES The DES algorithm sample application demonstrates common use cases of DES and Triple-DES ciphers. The DA16200 SDK includes an "mbedTLS" library. The API of the DES algorithm is the same as what the "mbedTLS" library provides. This section describes how the DES algorithm sample application is built and works. 6.2.1 How to Run 1. Open the workspace for the Crypto Algorithms of the DES application as follows: .\sample\Crypto\Crypto_DES\build\DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. The example application runs two types of crypto algorithms: DES-CBC-56 DES3-CBC-112 and 168 * DES -CBC- 56 (dec): passed * DES -CBC- 56 (enc): passed * DES3-CBC-112 (dec): passed * DES3-CBC-112 (enc): passed * DES3-CBC-168 (dec): passed * DES3-CBC-168 (enc): passed 6.2.2 Application Initialization DA16200 SDK provides an "mbedTLS" library. This library helps with an easy implementation of the user application. The example below shows how a user uses DES algorithms of the "mbedTLS" library to encrypt and decrypt data. void crypto_sample_des(ULONG arg) { #if defined(MBEDTLS_CIPHER_MODE_CBC) crypto_sample_des_cbc(); #endif /* MBEDTLS_CIPHER_MODE_CBC */ return ; } User Manual Revision 2.2 10-Mar-2021 CFR0012 133 of 214 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 6.2.3 Crypto Algorithm for DES-CBC-56, DES3-CBC-112, and 168 DA16200 supports crypto algorithm for DES-CBC-56, DES3-CBC-112, and 168. To explain how DES-CBC and DES3-CBC works, see the test vector in http://csrc.nist.gov/groups/STM/cavp/documents/des/tripledes-vectors.zip. int crypto_sample_des_cbc() { mbedtls_des_context *ctx = NULL; mbedtls_des3_context *ctx3 = NULL; // Initialize the DES context. mbedtls_des_init(ctx); // Initialize the Triple-DES context. mbedtls_des3_init(ctx3); for(i = 0; i < 6; i++) { u = i >> 1; v = i & 1; PRINTF("* DES%c-CBC-%3d (%s): ", ( u == 0 ) ? ' ' : '3', 56 + u * 56, ( v == MBEDTLS_DES_DECRYPT ) ? "dec" : "enc" ); switch (i) { case 0: // DES key schedule (56-bit, decryption). mbedtls_des_setkey_dec(ctx, crypto_sample_des3_keys); break; case 1: // DES key schedule (56-bit, encryption). mbedtls_des_setkey_enc(ctx, crypto_sample_des3_keys); break; case 2: // Triple-DES key schedule (112-bit, decryption). mbedtls_des3_set2key_dec(ctx3, crypto_sample_des3_keys); break; case 3: // Triple-DES key schedule (112-bit, encryption). mbedtls_des3_set2key_enc(ctx3, crypto_sample_des3_keys); break; case 4: // Triple-DES key schedule (168-bit, decryption). mbedtls_des3_set3key_dec(ctx3, crypto_sample_des3_keys); break; case 5: // Triple-DES key schedule (168-bit, encryption). mbedtls_des3_set3key_enc(ctx3, crypto_sample_des3_keys); break; } if (v == MBEDTLS_DES_DECRYPT) { for (j = 0 ; j < CRYPTO_SAMPLE_DES_LOOP_COUNT ; j++) { if(u == 0) { // DES-CBC buffer decryption. mbedtls_des_crypt_cbc(ctx, v, 8, iv, buf, buf); } else { // 3DES-CBC buffer decryption. mbedtls_des3_crypt_cbc(ctx3, v, 8, iv, buf, buf); User Manual CFR0012 Revision 2.2 134 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide } } } else { for (j = 0; j < CRYPTO_SAMPLE_DES_LOOP_COUNT; j++) { if (u == 0) { // DES-CBC buffer encryption. mbedtls_des_crypt_cbc(ctx, v, 8, iv, buf, buf); } else { // 3DES-CBC buffer encryption. mbedtls_des3_crypt_cbc(ctx3, v, 8, iv, buf, buf); } } } } // Clear the DES context. mbedtls_des_free(ctx); // Clear the Triple-DES context. mbedtls_des3_free(ctx3); } The mbedtls_des_context is the DES context structure. It is initialized by function mbedtls_des_init. Function mbedtls_des_crypt_cbc does DES-CBC buffer encryption and decryption. Before that, the key should be set up by function mbedtls_des_setkey_enc. After the operation is finished, call function mbed_des_free to clear the DES context. The mbedtls_des3_context is the Triple-DES context structure. It is initialized by function mbedtls_des3_init. There are two key-sizes supported: 112 bits and 168 bits. Based on the key-size, the key is set up via function mbedtls_des3_set2key_enc(or mbedtls_des3_set2key_dec) or mbedtls_des3_set3key_enc(or mbedtls_des3_set3key_dec). After that, the function mbedtls_des3_crypt_cbc does Triple-DES CBC encryption and decryption. After the operation is finished, call function mbedtls_des3_free to clear the DES3 context. 6.3 Crypto Algorithms HASH & HMAC The HASH and HMAC algorithms sample application demonstrates common use cases of HASH and HMAC algorithms such as SHA-1, SHA-256, and SHA-512, and so on. The DA16200 SDK includes an "mbedTLS" library. The API of the HASH and HMAC algorithms is the same as that of the "mbedTLS" library. This section describes how the HASH and HMAC algorithms sample application is built and works. 6.3.1 How to Run 1. Open the workspace for the Crypto Algorithms for the HASH and HMAC application as follows: .\sample\Crypto\Crypto_HASH\build\DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. 3. In the SDK, enable the Crypto Algorithms for the Hash and HMAC application as follows: The example application runs six types of hash algorithms and HMAC algorithms: SHA1, SHA-224, SHA-256, SHA-384, SHA-512, and MD5 HMAC * SHA-1: passed * SHA-224: passed * SHA-256: passed * SHA-384: passed * SHA-512: passed * MD5: passed * Message-digest Information User Manual CFR0012 Revision 2.2 135 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide >>> MD5: passed >>> RIPEMD160: passed >>> SHA1: passed >>> SHA224: passed >>> SHA256: passed >>> SHA384: passed >>> SHA512: passed * Hash with text string >>> MD5: passed >>> RIPEMD160: passed * Hash with multiple text string >>> MD5: passed >>> RIPEMD160: passed * HMAC with hex data >>> MD5: passed >>> RIPEMD160: passed >>> SHA1: passed >>> SHA224: passed >>> SHA256: passed >>> SHA384: passed >>> SHA512: passed * HMAC with multiple hex data >>> MD5: passed >>> RIPEMD160: passed >>> SHA1: passed >>> SHA224: passed >>> SHA256: passed >>> SHA384: passed >>> SHA512: passed * Hash with hex data >>> SHA1: passed >>> SHA224: passed >>> SHA256: passed >>> SHA384: passed >>> SHA512: passed * Hash with multiple hex data >>> SHA1: passed >>> SHA224: passed >>> SHA256: passed >>> SHA384: passed 6.3.2 Application Initialization The DA16200 SDK provides an "mbedTLS" library. This library helps with an easy implementation of the user application. This example describes how the user can use hash and HMAC algorithms of the "mbedTLS" library. void crypto_sample_hash(ULONG arg) { crypto_sample_hash_sha1(); crypto_sample_hash_sha224(); crypto_sample_hash_sha256(); crypto_sample_hash_sha384(); crypto_sample_hash_sha512(); User Manual CFR0012 Revision 2.2 136 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide crypto_sample_hash_md5(); crypto_sample_hash_md_wrapper(); return ; } 6.3.3 Crypto Algorithm for SHA-1 Hash DA16200 supports a crypto algorithm for the SHA-1 hash. To explain how the SHA-1 hash works, see the test vector in FIPS-180-1. int crypto_sample_hash_sha1() { mbedtls_sha1_context *ctx = NULL; PRINTF("* SHA-1: "); // Initialize a SHA-1 context. mbedtls_sha1_init(ctx); // Start a SHA-1 checksum calculation. mbedtls_sha1_starts_ret(ctx); // Feed an input buffer into an ongoing SHA-1 checksum calculation. mbedtls_sha1_update_ret(ctx, crypto_sample_hash_sha1_buf, crypto_sample_hash_sha1_buflen); // Finishes the SHA-1 operation, and writes the result to the output buffer. mbedtls_sha1_finish(ctx, sha1sum); // Clear a SHA-1 context. mbedtls_sha1_free(ctx); } The mbedtls_sha1_context is the SHA-1 context structure. Function mbedtls_sha1_init is called to initialize the context. To calculate SHA-1 Hash, three functions should be called. The details are below. 1. int mbedtls_sha1_starts_ret(mbedtls_sha1_context *ctx) Prototype int mbedtls_sha1_starts_ret(mbedtls_sha1_context *ctx) Description This function starts a SHA-1 checksum calculation. Parameters ctx: The SHA-1 context to initialize. This must be initialized. Return values 0 on success. A negative error code on failure. 2. int mbedtls_sha1_update_ret(mbedtls_sha1_context *ctx, const unsigned char *input, size_t ilen) Prototype int mbedtls_sha1_update_ret(mbedtls_sha1_context *ctx, const unsigned char *input, size_t ilen) Description This function feeds an input buffer into an ongoing SHA-1 checksum calculation. Parameters ctx: The SHA-1 context. This must be initialized and have a hash operation started. input: The buffer holding the input data. This must be a readable buffer of length ilen Bytes. User Manual CFR0012 Revision 2.2 137 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide ilen: The length of the input data input in Bytes. Return values 0 on success. A negative error code on failure. 3. int mbedtls_sha1_finish_ret(mbedtls_sha1_context *ctx, unsigned char output[20]) Prototype int mbedtls_sha1_finish_ret(mbedtls_sha1_context *ctx, unsigned char output[20]) Description This function finishes the SHA-1 operation and writes the result to the output buffer. Parameters ctx: The SHA-1 context to use. This must be initialized and have a hash operation started. output: The SHA-1 checksum result. This must be a writable buffer of length 20 Bytes. Return values 0 on success. A negative error code on failure. 6.3.4 Crypto Algorithm for SHA-224 Hash DA16200 supports a crypto algorithm for the SHA-224 hash. To explain how SHA-224 hash works, see the test vector in FIPS-180-2. int crypto_sample_hash_sha224() { mbedtls_sha256_context *ctx = NULL; PRINTF("* SHA-224: "); // Initialize the SHA-224 context. mbedtls_sha256_init(ctx); // Start a SHA-224 checksum calculation. mbedtls_sha256_starts_ret(ctx, 1); // Feeds an input buffer into an ongoing SHA-224 checksum calculation. mbedtls_sha256_update_ret(ctx, crypto_sample_hash_sha224_buf, crypto_sample_hash_sha224_buflen); // Finishes the SHA-224 operation, and writes the result to the output buffer. mbedtls_sha256_finish_ret(ctx, sha224sum); //Clear s SHA-224 context. mbedtls_sha256_free(ctx); } The mbedtls_sha256_context is the SHA-256 context structure. The "mbedTLS" library supports SHA-224 and SHA-256 using the context. This sample describes SHA-224. Call function mbedtls_sha256_init to initialize the context. To calculate SHA-224 Hash, three functions should be called. The details are below: 1. int mbedtls_sha256_starts_ret(mbedtls_sha256_context *ctx, int is224) Prototype int mbedtls_sha256_starts_ret(mbedtls_sha256_context *ctx, int is224) Description This function starts a SHA-224 or SHA-256 checksum calculation. Parameters ctx: The context to use. This must be initialized. is224: This determines which function to use. This must be either 0 for SHA-256, or 1 for SHA-224. Return values 0 on success. A negative error code on failure. User Manual CFR0012 Revision 2.2 138 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 2. int mbedtls_sha256_update_ret(mbedtls_sha256_context *ctx, const unsigned char *input, size_t ilen) Prototype int mbedtls_sha256_update_ret(mbedtls_sha256_context *ctx, const unsigned char *input, size_t ilen) Description This function feeds an input buffer into an ongoing SHA-256 checksum calculation. Parameters ctx: The SHA-256 context. This must be initialized and have a hash operation started. input: The buffer holding the input data. This must be a readable buffer of length ilen Bytes. ilen: The length of the input data input in Bytes. Return values 0 on success. A negative error code on failure. 3. int mbedtls_sha256_finish_ret(mbedtls_sha256_context *ctx, unsigned char output[32]) Prototype int mbedtls_sha256_finish_ret(mbedtls_sha256_context *ctx, unsigned char output[32]) Description This function finishes the SHA-256 operation and writes the result to the output buffer. Parameters ctx: The SHA-256 context to use. This must be initialized and have a hash operation started. output: The SHA-224 or SHA-256 checksum result. This must be a writable buffer of length 32 Bytes. Return values 0 on success. A negative error code on failure. 6.3.5 Crypto Algorithm for SHA-256 Hash DA16200 supports a crypto algorithm for the SHA-256 hash. To explain how the SHA-256 hash works, see the test vector in FIPS-180-2. int crypto_sample_hash_sha256() { mbedtls_sha256_context *ctx = NULL; PRINTF("* SHA-256: "); // Initialize the SHA-256 context. mbedtls_sha256_init(ctx); // Start a SHA-256 checksum calculation. mbedtls_sha256_starts_ret(ctx, 0); // Feeds an input buffer into an ongoing SHA-256 checksum calculation. mbedtls_sha256_update_ret(ctx, crypto_sample_hash_sha256_buf, crypto_sample_hash_sha256_buflen); // Finishes the SHA-256 operation, and writes the result to the output buffer. mbedtls_sha256_finish_ret(ctx, sha256sum); //Clear s SHA-256 context. mbedtls_sha256_free(ctx); } This example is the same as the Crypto Algorithm for the SHA-224 code (see Section 6.3.4). When starting the SHA-256 checksum calculation, the second parameter should be set to 0 for SHA-256. User Manual CFR0012 Revision 2.2 139 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 6.3.6 Crypto Algorithm for SHA-384 Hash DA16200 supports a crypto algorithm for the SHA-384 hash. To explain how the SHA-384 hash works, see the test vector in FIPS-180-2. int crypto_sample_hash_sha384() { mbedtls_sha512_context *ctx = NULL; PRINTF("* SHA-384: "); // Initialize a SHA-384 context. mbedtls_sha512_init(ctx); // Start a SHA-384 checksum calculation. mbedtls_sha512_starts_ret(ctx, 1); // Feed an input buffer into an ongoing SHA-384 checksum calculation. mbedtls_sha512_update(ctx, crypto_sample_hash_sha384_buf, crypto_sample_hash_sha384_buflen); // Finishes the SHA-384 operation, and writes the result to the output buffer. mbedtls_sha512_finish(ctx, sha384sum); // Clear a SHA-384 context. mbedtls_sha512_free(ctx); } The mbedtls_sha512_context is the SHA-512 context structure. "mbedTLS" library supports SHA384 and SHA-512 using the context. This example describes SHA-384. Function mbedtls_sha512_init is called to initialize the context. To calculate SHA-384 Hash, three functions should be called. The details are below: 1. int mbedtls_sha512_starts_ret(mbedtls_sha512_context *ctx, int is384) Prototype int mbedtls_sha512_starts_ret(mbedtls_sha512_context *ctx, int is384) Description This function starts a SHA-384 or SHA-512 checksum calculation. Parameters ctx: The context to use. This must be initialized. is384: This determines which function to use. This must be either 0 for SHA-512, or 1 for SHA-384. Return values 0 on success. A negative error code on failure. 2. int mbedtls_sha512_update_ret(mbedtls_sha512_context *ctx, const unsigned char *input, size_t ilen) Prototype int mbedtls_sha512_update_ret(mbedtls_sha512_context *ctx, const unsigned char *input, size_t ilen) Description This function feeds an input buffer into an ongoing SHA-512 checksum calculation. Parameters ctx: The SHA-512 context. This must be initialized and have a hash operation started. input: The buffer holding the input data. This must be a readable buffer of length ilen Bytes. ilen: The length of the input data input in Bytes. Return values 0 on success. A negative error code on failure. 3. int mbedtls_sha512_finish_ret(mbedtls_sha512_context *ctx, unsigned char output[64]) User Manual CFR0012 Revision 2.2 140 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide Prototype int mbedtls_sha512_finish_ret(mbedtls_sha512_context *ctx, unsigned char output[64]) Description This function finishes the SHA-512 operation and writes the result to the output buffer. Parameters ctx: The SHA-512 context to use. This must be initialized and start a hash operation. output: The SHA-384 or SHA-512 checksum result. This must be a writable buffer of length 64 Bytes. Return values 0 on success. A negative error code on failure. 6.3.7 Crypto Algorithm for SHA-512 Hash DA16200 supports a crypto algorithm for the SHA-512 hash. To explain how the SHA-512 hash works, see the test vector in FIPS-180-2. int crypto_sample_hash_sha512() { mbedtls_sha512_context *ctx = NULL; PRINTF("* SHA-512: "); // Initialize a SHA-512 context. mbedtls_sha512_init(ctx); // Start a SHA-512 checksum calculation. mbedtls_sha512_starts_ret(ctx, 0); // Feed an input buffer into an ongoing SHA-512 checksum calculation. mbedtls_sha512_update_ret(ctx, crypto_sample_hash_sha512_buf, crypto_sample_hash_sha512_buflen); // Finishes the SHA-512 operation, and writes the result to the output buffer. mbedtls_sha512_finish(ctx, sha512sum); // Clear a SHA-512 context. mbedtls_sha512_free(ctx); } This sample is the same with Crypto Algorithm for the SHA-384 code (see Section 6.3.6). When the SHA-512 checksum calculation is started, the second parameter should be set to 0 for SHA-512. 6.3.8 Crypto Algorithm for MD5 Hash DA16200 supports a crypto algorithm for MD5 hash. To explain how MD5 hash works, see test vector in RFC1321. int crypto_sample_hash_md5() { PRINTF("* MD5: "); // Output = MD5(input buffer) mbedtls_md5_ret(crypto_sample_hash_md5_buf,crypto_sample_hash_md5_buflen, md5sum); return ret; } User Manual CFR0012 Revision 2.2 141 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide In this example, the MD5 hash function will be calculated by function mbedtls_md5_ret. The detail is below: int mbedtls_md5_ret(const unsigned char *input, size_t ilen, unsigned char output[16]) Prototype int mbedtls_md5_ret(const unsigned char *input, size_t ilen, unsigned char output[16]) Description Output = MD5(input buffer) Parameters Input: buffer holding the data Ilen: length of the input data Output: MD5 checksum result Return values 0 if successful 6.3.9 Crypto Algorithm for Hash and HMAC with the Generic Message-Digest Wrapper The "mbedTLS" library provides the generic message-digest wrapper to calculate HASH and HMAC functions. The example below shows how HASH and HMAC will be calculated with the generic message-digest wrapper functions. First, the user needs to check which message-digest could be supported by the "mbedTLS" library. The sample code below shows how to get and check message-digest information. int crypto_sample_hash_md_wrapper_info(char *md_name, mbedtls_md_type_t md_type, int md_size) { const mbedtls_md_info_t *md_info = NULL; const int *md_type_ptr = NULL; // Get the message-digest information associated with the given digest type. md_info = mbedtls_md_info_from_type(md_type); // Get the message-digest information associated with the given digest name. if (md_info != mbedtls_md_info_from_string(md_name)) { goto cleanup; } // Extract the message-digest type from the message-digest information structure. if (mbedtls_md_get_type(md_info) != (mbedtls_md_type_t)md_type) { goto cleanup; } // Extract the message-digest size from the message-digest information structure. if (mbedtls_md_get_size(md_info) != (unsigned char)md_size) { goto cleanup; } // Extract the message-digest name from the message-digest information structure. if (strcmp(mbedtls_md_get_name(md_info), md_name) != 0) { goto cleanup; } // Find the list of digests supported by the generic digest module. for (md_type_ptr = mbedtls_md_list() ; *md_type_ptr != 0 ; md_type_ptr++) { if(*md_type_ptr == md_type) { User Manual CFR0012 Revision 2.2 142 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide found = 1; break; } } return ret; } The API details are as follows: const mbedtls_md_info_t* mbedtls_md_info_from_type(mbedtls_md_type_t md_type) Prototype const mbedtls_md_info_t* mbedtls_md_info_from_type(mbedtls_md_type_t md_type) Description This function returns the message-digest information associated with the given digest type. Parameters md_type: The type of digest to search for. Return values The message-digest information associated with md_type. NULL if the associated message-digest information is not found. const mbedtls_md_info_t* mbedtls_md_info_from_string(const char* md_name) Prototype const mbedtls_md_info_t* mbedtls_md_info_from_string(const char* md_name) Description This function returns the message-digest information associated with the given digest name. Parameters md_name: The name of the digest to search for. Return values The message-digest information associated with md_name. NULL if the associated message-digest information is not found. mbedtls_md_type_t mbedtls_md_get_type(const mbedtls_md_info_t* md_info) Prototype const mbedtls_md_info_t* mbedtls_md_info_from_string(const char* md_name) Description This function extracts the message-digest type from the messagedigest information structure. Parameters md_info: The information structure of the message-digest algorithm to use. Return values The type of the message digest. unsigned char mbedtls_md_get_size(const mbedtls_md_info_t* md_info) Prototype unsigned char mbedtls_md_get_size(const mbedtls_md_info_t* md_info) Description This function extracts the message-digest size from the messagedigest information structure. Parameters md_info: The information structure of the message-digest algorithm to use. Return values The size of the message-digest output in Bytes. const char* mbedtls_md_get_name(const mbedtls_md_info_t* md_info) Prototype const char* mbedtls_md_get_name(const mbedtls_md_info_t* md_info) Description This function extracts the message-digest name from the messagedigest information structure. Parameters md_info: The information structure of the message-digest algorithm to use. User Manual CFR0012 Revision 2.2 143 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide Return values The name of the message digest. const int* mbedtls_md_list(void) Prototype const int* mbedtls_md_list(void) Description This function returns the list of digests supported by the generic digest module. Parameters None. Return values A statically allocated array of digests. Each element in the returned list is an integer belonging to the message-digest enumeration mbedtls_md_type_t. The last entry is 0. Second, the example code below describes how a HASH function could be calculated using the generic message-digest function. In this sample, the input value is a text string type. int crypto_sample_hash_md_wrapper_text(char *md_name, char *text_src_string, char *hex_hash_string) { const mbedtls_md_info_t *md_info = NULL; // Get the message-digest information associated with the given digest name. md_info = mbedtls_md_info_from_string(md_name); /* Calculates the message-digest of a buffer, * with respect to a configurable message-digest algorithm in a single call. */ ret = mbedtls_md(md_info, (const unsigned char *)text_src_string, strlen(text_src_string), output); } The text_src_string is input data to calculate the message-digest algorithm, and the hex_hash_string is the expected output. int mbedtls_md(const mbedtls_md_info_t* md_info, const unsigned char* input, size_t ilen, unsigned char* output) Prototype int mbedtls_md(const mbedtls_md_info_t* md_info, const unsigned char* input, size_t ilen, unsigned char* output) Description This function calculates the message-digest of a buffer, with respect to a configurable message-digest algorithm in a single call. The result is calculated as Output = message_digest(input buffer). Parameters md_info: The information structure of the message-digest algorithm to use. input: The buffer holding the data. ilen: The length of the input data. output: The generic message-digest checksum result. Return values 0 on success. MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification failure. Third, the example below is like the second example. The difference is that in this example the input values are multiple text strings. int crypto_sample_hash_md_wrapper_text_multi(char *md_name, char *text_src_string, char *hex_hash_string) { const mbedtls_md_info_t *md_info = NULL; mbedtls_md_context_t *ctx = NULL; //The generic message-digest context. /* Initialize a message-digest context without binding it User Manual CFR0012 Revision 2.2 144 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide * to a particular message-digest algorithm. */ mbedtls_md_init(ctx); // Get the message-digest information associated with the given digest name. md_info = mbedtls_md_info_from_string(md_name); // Select the message digest algorithm to use, and allocates internal structures. ret = mbedtls_md_setup(ctx, md_info, 0); // Start a message-digest computation. ret = mbedtls_md_starts(ctx); // Feed an input buffer into an ongoing message-digest computation. ret = mbedtls_md_update(ctx, (const unsigned char *)text_src_string, halfway); // Feed an input buffer into an ongoing message-digest computation. ret = mbedtls_md_update(ctx, (const unsigned char *)(text_src_string + halfway), len - halfway); // Finish the digest operation, and writes the result to the output buffer. ret = mbedtls_md_finish(ctx, output); /* Clear the internal structure of ctx and frees any embedded internal structure, * but does not free ctx itself. */ mbedtls_md_free(ctx); } The text_src_string is input data to calculate the message-digest algorithm, and the hex_hash_string is the expected output. To support multiple input data, the message-digest should be set up. The details are as follows: void mbedtls_md_init(mbedtls_md_context_t* ctx) Prototype void mbedtls_md_init(mbedtls_md_context_t* ctx) Description This function initializes a message-digest context without binding to a particular message-digest algorithm. Parameters ctx: The context to initialize. Return values None int mbedtls_md_setup(mbedtls_md_context_t* ctx, const mbedtls_md_info_t * md_info, int hmac) Prototype int mbedtls_md_setup(mbedtls_md_context_t* ctx, const mbedtls_md_info_t * md_info, int hmac) Description This function selects the message digest algorithm to use and allocates internal structures. Parameters ctx: The context to set up. md_info: The information structure of the message-digest algorithm to use. hmac: Defines if HMAC is used. 0: HMAC is not used (saves some memory), or non-zero: HMAC is used with this context. Return values 0 on success. MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification failure. User Manual CFR0012 Revision 2.2 145 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide MBEDTLS_ERR_MD_ALLOC_FAILED on memory-allocation failure. int mbedtls_md_update(mbedtls_md_context_t* ctx, const unsigned char* input, size_t ilen) Prototype int mbedtls_md_update(mbedtls_md_context_t* ctx, const unsigned char* input, size_t ilen) Description This function feeds an input buffer into an ongoing message-digest computation. Parameters ctx: The generic message-digest context. input: The buffer holding the input data. ilen: The length of the input data. Return values 0 on success. MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification failure. int mbedtls_md_finish(mbedtls_md_context_t* ctx, unsigned char* output) Prototype int mbedtls_md_finish(mbedtls_md_context_t* ctx, unsigned char* output) Description This function finishes the digest operation and writes the result to the output buffer. Parameters ctx: The generic message-digest context. output: The buffer for the generic message-digest checksum result. Return values 0 on success. MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification failure. void mbedtls_md_free(mbedtls_md_context_t* ctx) Prototype void mbedtls_md_free(mbedtls_md_context_t* ctx) Description This function clears the internal structure of ctx and frees any embedded internal structure but does not free ctx itself. Parameters ctx: The generic message-digest context. Return values None. Fourth, the sample code below shows how the HMAC function could be calculated using the generic message-digest wrapper function. The input value for this example is single hex data. int crypto_sample_hash_md_wrapper_hmac(char *md_name, int trunc_size, char *hex_key_string, char *hex_src_string, char *hex_hash_string) { const mbedtls_md_info_t *md_info = NULL; // Get the message-digest information associated with the given digest name. md_info = mbedtls_md_info_from_string(md_name); // Calculate the full generic HMAC on the input buffer with the provided key. ret = mbedtls_md_hmac(md_info, key_str, key_len, src_str, src_len, output); } The hex_key_string is the HMAC secret key, the hex_src_string is input data, and the hex_hash_string is expected output. The mbedtls_md_hmac function will help the HMAC function for single input data. int mbedtls_md_hmac(const mbedtls_md_info_t* md_info, const unsigned char * key, size_t keylen, const unsigned char* input, size_t ilen, unsigned char* output) User Manual CFR0012 Revision 2.2 146 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide Prototype Description Parameters Return values int mbedtls_md_hmac(const mbedtls_md_info_t* md_info, const unsigned char * key, size_t keylen, const unsigned char* input, size_t ilen, unsigned char* output) This function calculates the full generic HMAC on the input buffer with the provided key. The function allocates the context, does the calculation and frees the context. The HMAC result is calculated as output = generic HMAC(hmac key, input buffer). md_info: The information structure of the message-digest algorithm to use. key: The HMAC secret key. keylen: The length of the HMAC secret key in Bytes. input: The buffer holding the input data. ilen: The length of the input data. output: The generic HMAC result. 0 on success. MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification failure. Fifth, the example code below is like the fourth example. The difference is that in this example the input values are multiple hex data. int crypto_sample_hash_md_wrapper_hmac_multi(char *md_name, int trunc_size, char *hex_key_string, char *hex_src_string, char *hex_hash_string) { const mbedtls_md_info_t *md_info = NULL; mbedtls_md_context_t *ctx = NULL; /* Initialize a message-digest context without binding it * to a particular message-digest algorithm. */ mbedtls_md_init(ctx); md_info = mbedtls_md_info_from_string(md_name); // Select the message digest algorithm to use, and allocates internal structures. ret = mbedtls_md_setup(ctx, md_info, 1); // Start a message-digest computation. ret = mbedtls_md_hmac_starts(ctx, key_str, key_len); // Feed an input buffer into an ongoing message-digest computation. ret = mbedtls_md_hmac_update(ctx, src_str, halfway); // Feed an input buffer into an ongoing message-digest computation. ret = mbedtls_md_hmac_update(ctx, src_str + halfway, src_len - halfway); // Finish the digest operation, and writes the result to the output buffer. ret = mbedtls_md_hmac_finish(ctx, output); /* Clear the internal structure of ctx and frees any embedded internal structure, * but does not free ctx itself. */ mbedtls_md_free(ctx); } User Manual CFR0012 Revision 2.2 147 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide The API details are as follows: int mbedtls_md_hmac_starts(mbedtls_md_context_t* ctx, const unsigned char* key, size_t keylen) Prototype int mbedtls_md_hmac_starts(mbedtls_md_context_t* ctx, const unsigned char* key, size_t keylen) Description This function sets the HMAC key and prepares to authenticate a new message. Parameters ctx: The message digest context containing an embedded HMAC context. key: The HMAC secret key. keylen: The length of the HMAC key in Bytes. Return values 0 on success. MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification failure. int mbedtls_md_hmac_update(mbedtls_md_context_t* ctx, const unsigned char * input, size_t ilen) Prototype int mbedtls_md_hmac_update(mbedtls_md_context_t* ctx, const unsigned char * input, size_t ilen) Description This function feeds an input buffer into an ongoing HMAC computation. Parameters ctx: The message digest context containing an embedded HMAC context. input: The buffer holding the input data. ilen: The length of the input data. Return values 0 on success. MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification failure. int mbedtls_md_hmac_finish(mbedtls_md_context_t* ctx, unsigned char* output) Prototype int mbedtls_md_hmac_finish(mbedtls_md_context_t* ctx, unsigned char* output) Description This function finishes the HMAC operation and writes the result to the output buffer. Parameters ctx: The message digest context containing an embedded HMAC context. output: The generic HMAC checksum result. Return values 0 on success. MBEDTLS_ERR_MD_BAD_INPUT_DATA on parameter-verification failure. Sixth, the example below describes how the HASH function can be calculated with the generic message-digest function. In this example, the input value is single hex data. This example is almost the same as the second example. int crypto_sample_hash_md_wrapper_hex(char *md_name, char *hex_src_string, char *hex_hash_string) { const mbedtls_md_info_t *md_info = NULL; // Get the message-digest information associated with the given digest name. md_info = mbedtls_md_info_from_string(md_name); /* Calculates the message-digest of a buffer, * with respect to a configurable message-digest algorithm in a single call. */ ret = mbedtls_md(md_info, src_str, src_len, output); } User Manual CFR0012 Revision 2.2 148 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide Seventh, the example below describes how the HASH function can be calculated with the generic message-digest function. In this example, the input value is multiple hex data. This example is almost the same as the third example. int crypto_sample_hash_md_wrapper_hex_multi(char *md_name, char *hex_src_string, char *hex_hash_string) { const mbedtls_md_info_t *md_info = NULL; mbedtls_md_context_t *ctx = NULL; /* Initialize a message-digest context without binding it * to a particular message-digest algorithm. */ mbedtls_md_init(ctx); // Get the message-digest information associated with the given digest name. md_info = mbedtls_md_info_from_string(md_name); // Select the message digest algorithm to use, and allocates internal structures. ret = mbedtls_md_setup(ctx, md_info, 0); // Start a message-digest computation. ret = mbedtls_md_starts(ctx); // Feed an input buffer into an ongoing message-digest computation. ret = mbedtls_md_update(ctx, src_str, halfway); // Feed an input buffer into an ongoing message-digest computation. ret = mbedtls_md_update(ctx, src_str + halfway, src_len - halfway); // Finish the digest operation, and writes the result to the output buffer. ret = mbedtls_md_finish(ctx, output); /* Clear the internal structure of ctx and frees any embedded internal structure, * but does not free ctx itself. */ mbedtls_md_free(ctx); } 6.4 Crypto Algorithms DRBG The Random generator sample application demonstrates common use cases of CTR-DRBG (Counter mode Deterministic Random Byte Generator) and HMAC-DRBG (HMAC Deterministic Random Byte Generator). The DA16200 SDK includes an "mbedTLS" library. The API of DRBG is the same as what the "mbedTLS" library provides. This section describes how the Random generator sample application is built and works. 6.4.1 How to Run 1. Open the workspace for the Crypto Algorithms for DRBG application as follows: .\sample\Crypto\Crypto_DRBG\build\DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. The example application explains how to use the DRBG function with CTR and HMAC. * CTR_DRBG (PR = TRUE): passed * CTR_DRBG (PR = FALSE): passed * HMAC_DRBG (PR = True): passed * HMAC_DRBG (PR = False): passed User Manual CFR0012 Revision 2.2 149 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 6.4.2 Application Initialization The DA16200 SDK provides an "mbedTLS" library. The library helps with an easy implementation of the user application. This example describes how the user uses CTR DRBG and HMAC DRBG of the "mbedTLS" library. CTR_DRBG is a standardized way of building a PRNG from a block-cipher in counter mode operation, as defined in NIST SP 800-90A: Recommendation for Random Number Generation Using Deterministic Random Bit Generators. The "mbedTLS" implementation of CTR_DRBG uses AES-256 (default) or AES-128 as the underlying block cipher. HMAC_DRBG is based on Hash-based message authentication code. void crypto_sample_drbg(ULONG arg) { crypto_sample_ctr_drbg_pr_on(); crypto_sample_ctr_drbg_pr_off(); crypto_sample_hmac_drbg_pr_on(); crypto_sample_hmac_drbg_pr_off(); return ; } 6.4.3 CTR_DRBG with Prediction Resistance This example describes how to use CTR_DRBG with prediction resistance. int crypto_sample_drbg_pr_on() { mbedtls_ctr_drbg_context *ctx = NULL; //The CTR_DRBG context structure. // Based on a NIST CTR_DRBG test vector (PR = True) PRINTF("* CTR_DRBG (PR = TRUE): "); // Initialize the CTR_DRBG context. mbedtls_ctr_drbg_init( ctx ); ret = mbedtls_ctr_drbg_seed_entropy_len(ctx, ctr_drbg_self_test_entropy, (void *)entropy_source_pr, nonce_pers_pr, 16, 32); // Turn prediction resistance on mbedtls_ctr_drbg_set_prediction_resistance(ctx, MBEDTLS_CTR_DRBG_PR_ON); // Generate random data using CTR_DRBG. ret = mbedtls_ctr_drbg_random(ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE); // Generate random data using CTR_DRBG. ret = mbedtls_ctr_drbg_random(ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE); // Clear CTR_CRBG context data. mbedtls_ctr_drbg_free(ctx); } The API details are as follows: void mbedtls_ctr_drbg_init(mbedtls_ctr_drbg_context* ctx) Prototype void mbedtls_ctr_drbg_init(mbedtls_ctr_drbg_context* ctx) Description This function initializes the CTR_DRBG context and prepares it for mbedtls_ctr_drbg_seed() or mbedtls_ctr_drbg_free(). Parameters ctx: The CTR_DRBG context to initialize. User Manual CFR0012 Revision 2.2 150 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide Return values None. void mbedtls_ctr_drbg_set_prediction_resistance(mbedtls_ctr_drbg_context* ctx, int resistance) Prototype void mbedtls_ctr_drbg_set_prediction_resistance(mbedtls_ctr_drbg_context* ctx, int resistance) Description This function turns prediction resistance on or off. The default value is off. Parameters resistance: MBEDTLS_CTR_DRBG_PR_ON or MBEDTLS_CTR_DRBG_PR_OFF. Return values None. int mbedtls_ctr_drbg_random(void* p_rng, unsigned char *output, size_t output_len) Prototype int mbedtls_ctr_drbg_random(void* p_rng, unsigned char *output, size_t output_len) Description This function uses CTR_DRBG to generate random data. Parameters p_rng: The CTR_DRBG context. This must be a pointer to a mbedtls_ctr_drbg_context structure. output: The buffer to fill. output_len: The length of the buffer. Return values 0 on success. MBEDTLS_ERR_CTR_DRBG_ENTROPY_SOURCE_FAILED or MBEDTLS_ERR_CTR_DRBG_REQUEST_TOO_BIG on failure. void mbedtls_ctr_drbg_free(mbedtls_ctr_drbg_context* ctx) Prototype void mbedtls_ctr_drbg_free(mbedtls_ctr_drbg_context* ctx) Description This function clears CTR_CRBG context data. Parameters ctx: The CTR_DRBG context to clear. Return values None. 6.4.4 CTR_DRBG without Prediction Resistance This example describes how to use CTR_DRBG without prediction resistance. int crypto_sample_drbg_pr_off() { mbedtls_ctr_drbg_context *ctx = NULL; //The CTR_DRBG context structure. // Based on a NIST CTR_DRBG test vector (PR = FALSE) PRINTF("* CTR_DRBG (PR = FALSE): "); // Initialize the CTR_DRBG context. mbedtls_ctr_drbg_init(ctx); ret = mbedtls_ctr_drbg_seed_entropy_len(ctx, ctr_drbg_self_test_entropy, (void *) entropy_source_nopr, nonce_pers_nopr, 16, 32); // Generate random data using CTR_DRBG. ret = mbedtls_ctr_drbg_random(ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE); // Reseed the CTR_DRBG context, that is extracts data from the entropy source. ret = mbedtls_ctr_drbg_reseed(ctx, NULL, 0); User Manual CFR0012 Revision 2.2 151 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide // Generate random data using CTR_DRBG. ret = mbedtls_ctr_drbg_random(ctx, buf, MBEDTLS_CTR_DRBG_BLOCKSIZE); // Clear CTR_CRBG context data. mbedtls_ctr_drbg_free(ctx); } 6.4.5 HMAC_DRBG with Prediction Resistance This example describes how to use HMAC_DRBG with prediction resistance. int crypto_sample_hmac_drbg_pr_on() { mbedtls_hmac_drbg_context *ctx = NULL; const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); PRINTF("* HMAC_DRBG (PR = True) : "); // Initialize HMAC DRBG context. mbedtls_hmac_drbg_init(ctx); // HMAC_DRBG initial seeding Seed and setup entropy source for future reseeds. ret = mbedtls_hmac_drbg_seed(ctx, md_info, drbg_test_entropy, (void *)crypto_sample_hmac_drbg_entropy_src_pr, NULL, 0); // Enable prediction resistance. mbedtls_hmac_drbg_set_prediction_resistance(ctx, MBEDTLS_HMAC_DRBG_PR_ON); // Generate random. ret = mbedtls_hmac_drbg_random(ctx, buf, CRYPTO_SAMPLE_HMAC_DRBG_OUTPUT_LEN); // Generate random. ret = mbedtls_hmac_drbg_random(ctx, buf, CRYPTO_SAMPLE_HMAC_DRBG_OUTPUT_LEN); // Free an HMAC_DRBG context. mbedtls_hmac_drbg_free(ctx); } The API details are as follows: void mbedtls_hmac_drbg_init (mbedtls_hmac_drbg_context* ctx) Prototype void mbedtls_hmac_drbg_init(mbedtls_hmac_drbg_context *ctx) Description HMAC_DRBG context initialization makes the context ready for mbedtls_hmac_drbg_seed(), mbedtls_hmac_drbg_seed_buf() or mbedtls_hmac_drbg_free(). Parameters ctx: HMAC_DRBG context to be initialized. Return values None. int mbedtls_hmac_drbg_seed(mbedtls_hmac_drbg_context *ctx, const mbedtls_md_info_t *md_info, int(*)(void *, unsigned char *, size_t) f_entropy, void *p_entropy, const unsigned char *custom, size_t len) Prototype int mbedtls_hmac_drbg_seed(mbedtls_hmac_drbg_context *ctx, const mbedtls_md_info_t *md_info, int(*)(void *, unsigned char *, size_t) f_entropy, void *p_entropy, const unsigned char *custom, size_t len) Description HMAC_DRBG initial seeding Seed and setup entropy source for future reseeds. Parameters ctx: HMAC_DRBG context to be seeded. User Manual CFR0012 Revision 2.2 152 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide md_info: MD algorithm to use for HMAC_DRBG. f_entropy: Entropy callback (p_entropy, buffer to fill, buffer length). p_entropy: Entropy context. custom: Personalization data (Device specific identifiers) (Can be NULL). len: Length of personalization data. Return values 0 if successful, or MBEDTLS_ERR_MD_BAD_INPUT_DATA, or MBEDTLS_ERR_MD_ALLOC_FAILED, or MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED. void mbedtls_hmac_drbg_set_prediction_resistance(mbedtls_hmac_drbg_context *ctx, int resistance) Prototype void mbedtls_hmac_drbg_set_prediction_resistance(mbedtls_hmac_drbg_context *ctx, int resistance) Description Enable / disable prediction resistance (Default: Off). Parameters ctx: HMAC_DRBG context. resistance: MBEDTLS_HMAC_DRBG_PR_ON or MBEDTLS_HMAC_DRBG_PR_OFF. Return values None. int mbedtls_hmac_drbg_random(void *p_rng, unsigned char *output, size_t out_len) Prototype int mbedtls_hmac_drbg_random(void *p_rng, unsigned char *output, size_t out_len) Description HMAC_DRBG generate random. Parameters p_rng: HMAC_DRBG context. output: Buffer to fill. out_len: Length of the buffer. Return values 0 if successful, or MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED, or MBEDTLS_ERR_HMAC_DRBG_REQUEST_TOO_BIG. void mbedtls_hmac_drbg_free(mbedtls_hmac_drbg_context *ctx) Prototype void mbedtls_hmac_drbg_free(mbedtls_hmac_drbg_context *ctx) Description Free an HMAC_DRBG context. Parameters ctx: HMAC_DRBG context to free. Return values None. int mbedtls_hmac_drbg_reseed(mbedtls_hmac_drbg_context *ctx, const unsigned char *additional, size_t len) Prototype int mbedtls_hmac_drbg_reseed(mbedtls_hmac_drbg_context *ctx, const unsigned char *additional, size_t len) Description HMAC_DRBG reseeding (extracts data from entropy source). Parameters ctx: HMAC_DRBG context. additional: Additional data to add to state (can be NULL). len: Length of additional data. Return values 0 if successful, or MBEDTLS_ERR_HMAC_DRBG_ENTROPY_SOURCE_FAILED. User Manual CFR0012 Revision 2.2 153 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 6.4.6 HMAC_DRBG Without Prediction Resistance This example describes how to use HMAC_DRBG without prediction resistance. int crypto_sample_hmac_drbg_pr_off() { mbedtls_hmac_drbg_context *ctx; const mbedtls_md_info_t *md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); PRINTF("* HMAC_DRBG (PR = False) : "); // Initialize HMAC DRBG context. mbedtls_hmac_drbg_init(ctx); // HMAC_DRBG initial seeding Seed and setup entropy source for future reseeds. ret = mbedtls_hmac_drbg_seed(ctx, md_info, drbg_test_entropy, (void *)crypto_sample_hmac_drbg_entropy_src_nopr, NULL, 0); // HMAC_DRBG reseeding (extracts data from entropy source) ret = mbedtls_hmac_drbg_reseed(ctx, NULL, 0); // Generate random. ret = mbedtls_hmac_drbg_random(ctx, buf, CRYPTO_SAMPLE_HMAC_DRBG_OUTPUT_LEN); // Generate random. ret = mbedtls_hmac_drbg_random(ctx, buf, CRYPTO_SAMPLE_HMAC_DRBG_OUTPUT_LEN); // Free an HMAC_DRBG context. mbedtls_hmac_drbg_free(ctx); } 6.5 Crypto Algorithms ECDSA The Elliptic Curve Digital Signature Algorithm sample application demonstrates common use cases of the Elliptic Curve Digital Signature Algorithm. In cryptography, the Elliptic Curve Digital Signature Algorithm (ECDSA) offers a variant of the Digital Signature Algorithm (DSA) which uses elliptic curve cryptography. The DA16200 SDK includes an "mbedTLS" library. The API of ECDSA is the same as what the "mbedTLS" library provides. This section describes how the Elliptic Curve Digital Signature Algorithm sample application is built and works. 6.5.1 How to Run 1. Open the workspace for the Crypto Algorithms for the ECDSA application as follows: ~/SDK/sample/Crypto/Crypto_ECDSA/build/DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. The example application explains how to use the ECDSA function. * Seeding the random number generator: passed * Generating key pair: passed - (key size: 192 bits) * Computing message hash: passed * Signing message hash: passed - (signature length = 56) * Preparing verification context: passed 6.5.2 Application Initialization In cryptography, the Elliptic Curve Digital Signature Algorithm (ECDSA) offers a variant of the Digital Signature Algorithm (DSA), which uses elliptic curve cryptography. The DA16200 SDK provides an "mbedTLS" library. This library helps with the easy implementation of the user application. This User Manual CFR0012 Revision 2.2 154 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide example describes how the user uses the ECDSA (Elliptic Curve Digital Signature Algorithm) of the "mbedTLS" library. void crypto_sample_ecdsa() { crypto_sample_ecdsa_test(); return ; } 6.5.3 Generates ECDSA Key Pair and Verifies ECDSA Signature This example generates an ECDSA keypair and verifies the self-computed ECDSA signature. int crypto_sample_ecdsa_test() { int ret = -1; const char *pers = "crypto_sample_ecdsa"; mbedtls_ecdsa_context ctx_sign; mbedtls_ecdsa_context ctx_verify; mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; mbedtls_sha256_context sha256_ctx; // Initialize an ECDSA context. mbedtls_ecdsa_init(&ctx_sign); mbedtls_ecdsa_init(&ctx_verify); // Initialize the CTR_DRBG context. mbedtls_ctr_drbg_init(&ctr_drbg); // Initialize the SHA-256 context. mbedtls_sha256_init(&sha256_ctx); // Initialize the entropy context. mbedtls_entropy_init(&entropy); memset(sig, 0x00, MBEDTLS_ECDSA_MAX_LEN); memset(message, 0x25, 100); /* * Generate a key pair for signing */ // Seed and sets up the CTR_DRBG entropy source for future reseeds. ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)pers, strlen(pers)); PRINTF("* Generating key pair: "); // Generate an ECDSA keypair on the given curve. ret = mbedtls_ecdsa_genkey(&ctx_sign, MBEDTLS_ECP_DP_SECP192R1, mbedtls_ctr_drbg_random, &ctr_drbg); /* * Compute message hash */ // Start a SHA-256 checksum calculation. mbedtls_sha256_starts_ret(&sha256_ctx, 0); User Manual CFR0012 Revision 2.2 155 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide // Feeds an input buffer into an ongoing SHA-256 checksum calculation. mbedtls_sha256_update_ret(&sha256_ctx, message, 100); // Finishes the SHA-256 operation, and writes the result to the output buffer. mbedtls_sha256_finish(&sha256_ctx, hash); /* * Sign message hash */ // Compute the ECDSA signature and writes it to a buffer. ret = mbedtls_ecdsa_write_signature(&ctx_sign, MBEDTLS_MD_SHA256, hash, 32, sig, &sig_len, mbedtls_ctr_drbg_random, &ctr_drbg); /* * Verify signature */ PRINTF("* Verifying signature: "); // Read and verifie an ECDSA signature. ret = mbedtls_ecdsa_read_signature(&ctx_verify, hash, 32, sig, sig_len); // Free an ECDSA context. mbedtls_ecdsa_free(&ctx_verify); mbedtls_ecdsa_free(&ctx_sign); // Clear CTR_CRBG context data. mbedtls_ctr_drbg_free(&ctr_drbg); // Free the data in the context. mbedtls_entropy_free(&entropy); //Clear s SHA-256 context. mbedtls_sha256_free(&sha256_ctx); } The API details are as follows: void mbedtls_ecdsa_init(mbedtls_ecdsa_context *ctx) Prototype void mbedtls_ecdsa_init(mbedtls_ecdsa_context *ctx) Description This function initializes an ECDSA context. Parameters ctx: The ECDSA context to initialize. This must not be NULL. Return values None. int mbedtls_ecdsa_genkey(mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid, int(*)(void *, unsigned char *, size_t)f_rng, void * p_rng) Prototype int mbedtls_ecdsa_genkey(mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid, int(*)(void *, unsigned char *, size_t)f_rng, void * p_rng) Description This function generates an ECDSA keypair on the given curve. Parameters ctx: The ECDSA context to store the keypair in. This must be initialized. gid: The elliptic curve to use. One of the various MBEDTLS_ECP_DP_XXX macros depending on configuration. f_rng: The RNG function to use. This must not be NULL. User Manual CFR0012 Revision 2.2 156 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide p_rng: The RNG context to be passed to f_rng. This may be NULL if f_rng does not need a context argument. Return values 0 on success. An MBEDTLS_ERR_ECP_XXX code on failure. int mbedtls_ecdsa_write_signature(mbedtls_ecdsa_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hlen, unsigned char *sig, size_t *slen, int(*)(void *, unsigned char *, size_t)f_rng, void *p_rng) Prototype int mbedtls_ecdsa_genkey(mbedtls_ecdsa_context *ctx, mbedtls_ecp_group_id gid, int(*)(void *, unsigned char *, size_t)f_rng, void * p_rng) Description This function computes the ECDSA signature and writes it to a buffer, serialized as defined in RFC-4492: Elliptic Curve Cryptography (ECC) Cipher Suites for Transport Layer Security (TLS). Parameters ctx: The ECDSA context to use. This must be initialized and have a group and private key bound to it, for example via mbedtls_ecdsa_genkey() or mbedtls_ecdsa_from_keypair(). md_alg: The message digest that was used to hash the message. hash: The message hash to be signed. This must be a readable buffer of length hlen Bytes. hlen: The length of the hash in Bytes. sig: The buffer to which to write the signature. This must be a writable buffer of a length at least twice as large as the size of the curve used, plus 9. For example, 73 Bytes if a 256-bit curve is used. A buffer length of MBEDTLS_ECDSA_MAX_LEN is always safe. slen: The address at which to store the actual length of the signature written. Must not be NULL. f_rng: The RNG function. This must not be NULL if MBEDTLS_ECDSA_DETERMINISTIC is unset. Otherwise, it is unused and may be set to NULL. p_rng: The RNG context to be passed to f_rng. This may be NULL if f_rng is NULL or does not use a context. Return values 0 on success. An MBEDTLS_ERR_ECP_XXX, MBEDTLS_ERR_MPI_XXX or MBEDTLS_ERR_ASN1_XXX error code on failure. int mbedtls_ecdsa_read_signature(mbedtls_ecdsa_context *ctx, const unsigned char *hash, size_t hlen, const unsigned char *sig, size_t slen) Prototype int mbedtls_ecdsa_read_signature(mbedtls_ecdsa_context *ctx, const unsigned char *hash, size_t hlen, const unsigned char *sig, size_t slen) Description This function reads and verifies an ECDSA signature. Parameters ctx: The ECDSA context to use. This must be initialized and have a group and public key bound to it. hash: The message hash that was signed. This must be a readable buffer of length size Bytes. hlen: The size of the hash. sig: The signature to read and verify. This must be a readable buffer of length slen Bytes. slen: The size of sig in Bytes. Return values 0 on success. MBEDTLS_ERR_ECP_BAD_INPUT_DATA if signature is invalid. MBEDTLS_ERR_ECP_SIG_LEN_MISMATCH if there is a valid signature in sig, but its length is less than siglen. An MBEDTLS_ERR_ECP_XXX or MBEDTLS_ERR_MPI_XXX error code on failure for any other reason. User Manual CFR0012 Revision 2.2 157 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 6.6 Crypto Algorithms Diffie-Hellman Key Exchange The Diffie-Hellman-Merkle (DHM) key exchange sample application demonstrates common use cases of DHM key exchange on the client and server sides. The DA16200 SDK includes an "mbedTLS" library. The API of DHM is the same as what the "mbedTLS" library provides. This section describes how the DHM key exchange sample application is built and works. 6.6.1 How to Run 1. Open the workspace for the Crypto Algorithms for the Diffie-Hellman Key Exchange application as follows: .\sample\Crypto\Crypto_DHM\build\DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. The example application explains how to use the Diffie-Hellman key exchange function. * DHM parameter load: passed * Diffie-Hellman full exchange: passed 6.6.2 Application Initialization The DA16200 SDK provides an "mbedTLS" library. This library helps with an easy implementation of the user application. This example includes two types. The first, function crypto_sample_dhm_parse_dhm, shows how Diffie-Hellman parameters can be loaded. The second, function crypto_sample_dhm_do_dhm, shows how DA16200 works for Diffie-Hellman key exchange. void crypto_sample_dhm() { ret = crypto_sample_dhm_parse_dhm(); for (idx = 0 ; crypto_sample_dhm_do_dhm_list[idx].title != NULL ; idx++) { ret = crypto_sample_dhm_do_dhm( crypto_sample_dhm_do_dhm_list[idx].title, crypto_sample_dhm_do_dhm_list[idx].radix_P, crypto_sample_dhm_do_dhm_list[idx].input_P, crypto_sample_dhm_do_dhm_list[idx].radix_G, crypto_sample_dhm_do_dhm_list[idx].input_G); } } 6.6.3 Load Diffie-Hellman Parameters This example application shows how the Diffie-Hellman parameters are loaded over the "mbedTLS" library's API. int crypto_sample_dhm_parse_dhm() { mbedtls_dhm_context *dhm = NULL; // The DHM context structure. // Initialize the DHM context. mbedtls_dhm_init(dhm); // Parse DHM parameters in PEM or DER format. ret = mbedtls_dhm_parse_dhm(dhm, (const unsigned char *)crypto_sample_dhm_params, crypto_sample_dhm_params_len); // Free and clear the components of a DHM context. mbedtls_dhm_free(dhm); } User Manual CFR0012 Revision 2.2 158 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide The mbedtls_dhm_parse_dhm parses DHM parameters in PEM or DER format. The crypto_sample_dhm_params is already defined in this sample. The API details are as follows: void mbedtls_dhm_init(mbedtls_dhm_context *ctx) Prototype void mbedtls_dhm_init(mbedtls_dhm_context *ctx) Description This function initializes the DHM context. Parameters ctx: The DHM context to initialize. Return values None. int mbedtls_dhm_parse_dhm(mbedtls_dhm_context *dhm, const unsigned char *dhmin, size_t dhminlen) Prototype int mbedtls_dhm_parse_dhm(mbedtls_dhm_context *dhm, const unsigned char *dhmin, size_t dhminlen) Description This function parses DHM parameters in PEM or DER format. Parameters dhm: The DHM context to import the DHM parameters into. This must be initialized. dhmin: The input buffer. This must be a readable buffer of length dhminlen Bytes. dhminlen: The size of the input buffer dhmin, including the terminating NULL Byte for PEM data. Return values 0 on success. An MBEDTLS_ERR_DHM_XXX or MBEDTLS_ERR_PEM_XXX error code on failure. void mbedtls_dhm_free(mbedtls_dhm_context *ctx) Prototype void mbedtls_dhm_free(mbedtls_dhm_context *ctx) Description This function frees and clears the components of a DHM context. Parameters dhm: The DHM context to import the DHM parameters into. This must be initialized. dhmin: The input buffer. This must be a readable buffer of length dhminlen Bytes. dhminlen: The size of the input buffer dhmin, including the terminating NULL Byte for PEM data. Return values ctx: The DHM context to free and clear. This may be NULL, in which case this function is a no-op. If it is not NULL, it must point to an initialized DHM context. 6.6.4 How Diffie-Hellman Works This sample application shows how Diffie-Hellman works over the API of the "mbedTLS" library. Diffie-Hellman operation is normally used during TLS Handshake, ServerKeyExchange and ClientKeyExchange messages. To verify the operation, this sample simulates TLS Handshake's ServerKeyExchange and ClientKeyExchange messages. int crypto_sample_dhm_do_dhm(char *title, int radix_P, char *input_P, int radix_G, char *input_G) { mbedtls_dhm_context ctx_srv; mbedtls_dhm_context ctx_cli; rnd_pseudo_info rnd_info; // Initialize the DHM context. mbedtls_dhm_init(&ctx_srv); User Manual CFR0012 Revision 2.2 159 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide mbedtls_dhm_init(&ctx_cli); // Set parameters MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&ctx_srv.P, radix_P, input_P)); MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&ctx_srv.G, radix_G, input_G)); x_size = mbedtls_mpi_size(&ctx_srv.P); pub_cli_len = x_size; /* Generate a DHM key pair and export its public part together * with the DHM parameters in the format. */ ret = mbedtls_dhm_make_params(&ctx_srv, x_size, ske, &ske_len, &rnd_pseudo_rand, &rnd_info); // Parse the DHM parameters (DHM modulus, generator, and public key) ret = mbedtls_dhm_read_params(&ctx_cli, &p, ske + ske_len); // Create a DHM key pair and export the raw public key in big-endian format. ret = mbedtls_dhm_make_public(&ctx_cli, x_size, pub_cli, pub_cli_len, &rnd_pseudo_rand, &rnd_info); // Import the raw public value of the peer. ret = mbedtls_dhm_read_public(&ctx_srv, pub_cli, pub_cli_len); // Derive and export the shared secret (G^Y)^X mod P. ret = mbedtls_dhm_calc_secret(&ctx_srv, sec_srv, DHM_BUF_SIZE, &sec_srv_len, &rnd_pseudo_rand, &rnd_info); // Derive and export the shared secret (G^Y)^X mod P. ret = mbedtls_dhm_calc_secret(&ctx_cli, sec_cli, DHM_BUF_SIZE, &sec_cli_len, NULL, NULL); // Free and clear the components of a DHM context. mbedtls_dhm_free(&ctx_srv); mbedtls_dhm_free(&ctx_cli); } The API details are as follows: int mbedtls_dhm_make_params(mbedtls_dhm_context *ctx, int x_size, unsigned char *output, size_t *olen, int(*)(void *, unsigned char *, size_t)f_rng, void *p_rng) Prototype int mbedtls_dhm_make_params(mbedtls_dhm_context *ctx, int x_size, unsigned char *output, size_t *olen, int(*)(void *, unsigned char *, size_t)f_rng, void *p_rng) Description This function generates a DHM key pair and exports its public part together with the DHM parameters in the format used in a TLS ServerKeyExchange handshake message. Parameters ctx: The DHM context to use. This must be initialized and have the DHM parameters set. It may or may not already have imported the peer's public key. x_size: The private key size in Bytes. olen: The address at which to store the number of Bytes written on success. This must not be NULL. output: The destination buffer. This must be a writable buffer of sufficient size to hold the reduced binary presentation of the modulus, the generator and the public key, each wrapped with a 2byte length field. It is the responsibility of the caller to ensure User Manual CFR0012 Revision 2.2 160 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide that enough space is available. Refer to mbedtls_mpi_size() to compute the byte-size of an MPI. f_rng: The RNG function. Must not be NULL. p_rng: The RNG context to be passed to f_rng. This may be NULL if f_rng does not need a context parameter. Return values 0 on success. An MBEDTLS_ERR_DHM_XXX error code on failure. int mbedtls_dhm_read_params(mbedtls_dhm_context *ctx, unsigned char **p, const unsigned char *end) Prototype int mbedtls_dhm_read_params(mbedtls_dhm_context *ctx, unsigned char **p, const unsigned char *end) Description This function parses the DHM parameters in a TLS ServerKeyExchange handshake message (DHM modulus, generator, and public key). Parameters ctx: The DHM context to use. This must be initialized. p: On input, *p must be the start of the input buffer. On output, *p is updated to point to the end of the data that has been read. On success, this is the first byte past the end of the ServerKeyExchange parameters. On error, this is the point at which an error has been detected, which is usually not useful except to debug failures. end: The end of the input buffer. Return values 0 on success. An MBEDTLS_ERR_DHM_XXX error code on failure. int mbedtls_dhm_make_public(mbedtls_dhm_context *ctx, int x_size, unsigned char *output, size_t olen, int(*)(void *, unsigned char *, size_t)f_rng, void *p_rng) Prototype int mbedtls_dhm_make_public(mbedtls_dhm_context *ctx, int x_size, unsigned char *output, size_t olen, int(*)(void *, unsigned char *, size_t)f_rng, void *p_rng) Description This function creates a DHM key pair and exports the raw public key in big-endian format. Parameters ctx: The DHM context to use. This must be initialized and have the DHM parameters set. It may or may not already have imported the peer's public key. x_size: The private key size in Bytes. output: The destination buffer. This must be a writable buffer of size olen Bytes. olen: The length of the destination buffer. This must be at least equal to ctx->len (the size of P). f_rng: The RNG function. This must not be NULL. p_rng: The RNG context to be passed to f_rng. This may be NULL if f_rng does not need a context argument. Return values 0 on success. An MBEDTLS_ERR_DHM_XXX error code on failure. int mbedtls_dhm_read_public(mbedtls_dhm_context *ctx, const unsigned char *input, size_t ilen) Prototype int mbedtls_dhm_read_public(mbedtls_dhm_context *ctx, const unsigned char *input, size_t ilen) Description This function imports the raw public value of the peer. Parameters ctx: The DHM context to use. This must be initialized and have its DHM parameters set, for instance via mbedtls_dhm_set_group(). It may or may not already have generated its own private key. User Manual CFR0012 Revision 2.2 161 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide input: The input buffer containing the G^Y value of the peer. This must be a readable buffer of size ilen Bytes. ilen: The size of the input buffer input in Bytes. Return values 0 on success. An MBEDTLS_ERR_DHM_XXX error code on failure. int mbedtls_dhm_calc_secret(mbedtls_dhm_context *ctx, unsigned char *output, size_t output_size, size_t *olen, int(*)(void *, unsigned char *, size_t)f_rng, void *p_rng) Prototype int mbedtls_dhm_calc_secret(mbedtls_dhm_context *ctx, unsigned char *output, size_t output_size, size_t *olen, int(*)(void *, unsigned char *, size_t)f_rng, void *p_rng) Description This function derives and exports the shared secret (G^Y)^X mod P. Parameters ctx: The DHM context to use. This must be initialized and have its own private key generated and the peer's public key imported. output: The buffer to write the generated shared key to. This must be a writable buffer of size output_size Bytes. output_size: The size of the destination buffer. This must be at least the size of ctx->len (the size of P). olen: On exit, holds the actual number of Bytes written. f_rng: The RNG function, for blinding purposes. This may be NULL if blinding is not needed. p_rng: The RNG context. This may be NULL if f_rng does not need a context argument. Return values 0 on success. An MBEDTLS_ERR_DHM_XXX error code on failure. User Manual CFR0012 Revision 2.2 162 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 6.7 Crypto Algorithms RSA PKCS#1 The RSA PKCS#1 sample application demonstrates common use cases of RSA PKCS#1 functions. The DA16200 SDK includes an "mbedTLS" library. The API of RSA PKCS#1 is the same as what an "mbedTLS" library provides. This section describes how the Key derivation function sample application is built and works. 6.7.1 How to Run 1. Open the workspace for the Crypto Algorithms for the RSA PKCS#1 application as follows: ~/SDK/sample/Crypto/Crypto_RSA/build/DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. The example application explains how to use the RSA PKCS#1 function. * RSA key validation: passed * PKCS#1 encryption : passed * PKCS#1 decryption : passed * PKCS#1 data sign : passed * PKCS#1 sig. verify: passed 6.7.2 Application Initialization The DA16200 SDK provides an "mbedTLS" library. The library helps with an easy implementation of the User Application. This example shows RSA key validation, encryption, decryption, and verification of the signature. To verify the signature, a SHA-1 Hash algorithm is used. void crypto_sample_rsa(ULONG arg) { crypto_sample_rsa_pkcs1(); } 6.7.3 How RSA PKCS#1 Works The example application below shows how RSA PKCS#1 works over the API of the "mbedTLS" library. To verify, an RSA-1024 keypair and a SHA-1 Hash algorithm are used on RSA PKCS-1 v1.5. int crypto_sample_rsa_pkcs1() { mbedtls_rsa_context *rsa = NULL; unsigned char *sha1sum = NULL; // The RSA context structure. // Initializes an RSA context. mbedtls_rsa_init(rsa, MBEDTLS_RSA_PKCS_V15, 0); PRINTF("* RSA key validation: "); // Check if a context contains at least an RSA public key. ret = mbedtls_rsa_check_pubkey(rsa); ret = mbedtls_rsa_check_privkey(rsa); PRINTF("* PKCS#1 encryption : "); // Add the message padding, then performs an RSA operation. ret = mbedtls_rsa_pkcs1_encrypt(rsa, myrand, NULL, MBEDTLS_RSA_PUBLIC, PT_LEN, rsa_plaintext, rsa_ciphertext); PRINTF("* PKCS#1 decryption : "); // Perform an RSA operation, then removes the message padding. ret = mbedtls_rsa_pkcs1_decrypt(rsa, myrand, User Manual CFR0012 Revision 2.2 163 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide NULL, MBEDTLS_RSA_PRIVATE, &len, rsa_ciphertext, rsa_decrypted, (PT_LEN * sizeof(unsigned char))); PRINTF("* PKCS#1 data sign : "); mbedtls_sha1_ret(rsa_plaintext, PT_LEN, sha1sum); // Perform a private RSA operation to sign a message digest using PKCS#1. ret = mbedtls_rsa_pkcs1_sign(rsa, myrand, NULL, MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA1, 0, sha1sum, rsa_ciphertext); PRINTF("* PKCS#1 sig. verify: "); // Perform a public RSA operation and checks the message digest. ret = mbedtls_rsa_pkcs1_verify(rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA1, 0, sha1sum, rsa_ciphertext); // Free the components of an RSA key. mbedtls_rsa_free(rsa); } The API details are as follows: void mbedtls_rsa_init(mbedtls_rsa_context *ctx, int padding, int hash_id) Prototype void mbedtls_rsa_init(mbedtls_rsa_context *ctx, int padding, int hash_id) Description This function initializes an RSA context. Parameters ctx: The RSA context to initialize. This must not be NULL. padding: The padding mode to use. This must be either MBEDTLS_RSA_PKCS_V15 or MBEDTLS_RSA_PKCS_V21. hash_id: The hash identifier of mbedtls_md_type_t type, if padding is MBEDTLS_RSA_PKCS_V21. It is otherwise unused. Return values None. int mbedtls_rsa_check_pubkey(const mbedtls_rsa_context *ctx) Prototype int mbedtls_rsa_check_pubkey(const mbedtls_rsa_context *ctx) Description This function checks if a context contains at least an RSA public key. If the function runs successfully, it is guaranteed that enough information is present to do an RSA public key operation with mbedtls_rsa_public(). Parameters ctx: The initialized RSA context to check. Return values 0 on success. An MBEDTLS_ERR_RSA_XXX error code on failure. int mbedtls_rsa_check_privkey(const mbedtls_rsa_context *ctx) Prototype int mbedtls_rsa_check_pubkey(const mbedtls_rsa_context *ctx) Description This function checks if a context contains an RSA private key and does basic consistency checks. Parameters ctx: The initialized RSA context to check. Return values 0 on success. An MBEDTLS_ERR_RSA_XXX error code on failure. User Manual CFR0012 Revision 2.2 164 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide int mbedtls_rsa_pkcs1_encrypt(mbedtls_rsa_context *ctx, int(*)(void *, unsigned char *, size_t)f_rng, void *p_rng, int mode, size_t ilen, const unsigned char *input, unsigned char *output) Prototype int mbedtls_rsa_pkcs1_encrypt(mbedtls_rsa_context *ctx, int(*)(void *, unsigned char *, size_t)f_rng, void *p_rng, int mode, size_t ilen, const unsigned char *input, unsigned char *output) Description This function adds the message padding, then does an RSA operation. It is the generic wrapper to do a PKCS#1 encryption operation with the mode from the context. Parameters ctx: The initialized RSA context to use. f_rng: The RNG to use. It is mandatory for PKCS#1 v2.1 padding encoding, and for PKCS#1 v1.5 padding encoding when used with mode set to MBEDTLS_RSA_PUBLIC. For PKCS#1 v1.5 padding encoding and mode set to MBEDTLS_RSA_PRIVATE, it is used for blinding and should be provided in this case. See mbedtls_rsa_private() for more information. p_rng: The RNG context to be passed to f_rng. May be NULL if f_rng is NULL or if f_rng does not need a context argument. mode: The mode of operation. This must be either MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE (deprecated). ilen: The length of the plaintext in Bytes. input: The input data to encrypt. This must be a readable buffer of size ilen Bytes. This must not be NULL. output: The output buffer. This must be a writable buffer of length ctx->len Bytes. For example, 256 Bytes for a 2048-bit RSA modulus. Return values 0 on success. An MBEDTLS_ERR_RSA_XXX error code on failure. int mbedtls_rsa_pkcs1_decrypt(mbedtls_rsa_context *ctx, int(*)(void *, unsigned char *, size_t)f_rng, void *p_rng, int mode, size_t *olen, const unsigned char *input, unsigned char *output, size_t output_max_len) Prototype int mbedtls_rsa_pkcs1_decrypt(mbedtls_rsa_context *ctx, int(*)(void *, unsigned char *, size_t)f_rng, void *p_rng, int mode, size_t *olen, const unsigned char *input, unsigned char *output, size_t output_max_len) Description This function does an RSA operation, then removes the message padding. It is the generic wrapper to do a PKCS#1 decryption operation with the mode from the context. Parameters ctx: The initialized RSA context to use. f_rng: The RNG function. If mode is MBEDTLS_RSA_PRIVATE, this is used for blinding and should be provided; see mbedtls_rsa_private() for more. If mode is MBEDTLS_RSA_PUBLIC, it is ignored. p_rng: The RNG context to be passed to f_rng. This may be NULL if f_rng is NULL or does not need a context. mode: The mode of operation. This must be either MBEDTLS_RSA_PRIVATE or MBEDTLS_RSA_PUBLIC (deprecated). olen: The address at which to store the length of the plaintext. This must not be NULL. input: The ciphertext buffer. This must be a readable buffer of length ctx->len Bytes. For example, 256 Bytes for a 2048-bit RSA modulus. output: The buffer used to hold the plaintext. This must be a writable buffer of length output_max_len Bytes. output_max_len: The length in Bytes of the output buffer output. User Manual CFR0012 Revision 2.2 165 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide Return values 0 on success. An MBEDTLS_ERR_RSA_XXX error code on failure. int mbedtls_rsa_pkcs1_sign(mbedtls_rsa_context *ctx, int(*)(void *, unsigned char *, size_t)f_rng, void *p_rng, int mode, mbedtls_md_type_t md_alg, unsigned int hashlen, const unsigned char *hash, unsigned char *sig) Prototype int mbedtls_rsa_pkcs1_sign(mbedtls_rsa_context *ctx, int(*)(void *, unsigned char *, size_t)f_rng, void *p_rng, int mode, mbedtls_md_type_t md_alg, unsigned int hashlen, const unsigned char *hash, unsigned char *sig) Description This function does a private RSA operation to sign a message digest with PKCS#1. It is the generic wrapper to do a PKCS#1 signature with the mode from the context. Parameters ctx: The initialized RSA context to use. f_rng: The RNG function to use. If the padding mode is PKCS#1 v2.1, this must be provided. If the padding mode is PKCS#1 v1.5 and the mode is MBEDTLS_RSA_PRIVATE, it is used for blinding and should be provided. See mbedtls_rsa_private() for more information. It is otherwise ignored. p_rng: The RNG context to be passed to f_rng. This may be NULL if f_rng is NULL or does not need a context argument. mode: The mode of operation. This must be either MBEDTLS_RSA_PRIVATE or MBEDTLS_RSA_PUBLIC (deprecated). md_alg: The message-digest algorithm used to hash the original data. Use MBEDTLS_MD_NONE for signing raw data. hashlen: The length of the message digest. This is only used if md_alg is MBEDTLS_MD_NONE. hash: The buffer holding the message digest or raw data. If md_alg is MBEDTLS_MD_NONE, this must be a readable buffer of length hashlen Bytes. If md_alg is not MBEDTLS_MD_NONE, it must be a readable buffer of length the size of the hash corresponding to md_alg. sig: The buffer to hold the signature. This must be a writable buffer of length ctx->len Bytes. For example, 256 Bytes for a 2048bit RSA modulus. Return values 0 on success. An MBEDTLS_ERR_RSA_XXX error code on failure. int mbedtls_rsa_pkcs1_verify(mbedtls_rsa_context *ctx, int(*)(void *, unsigned char *, size_t)f_rng, void *p_rng, int mode, mbedtls_md_type_t md_alg, unsigned int hashlen, const unsigned char *hash, const unsigned char *sig) Prototype int mbedtls_rsa_pkcs1_verify(mbedtls_rsa_context *ctx, int(*)(void *, unsigned char *, size_t)f_rng, void *p_rng, int mode, mbedtls_md_type_t md_alg, unsigned int hashlen, const unsigned char *hash, const unsigned char *sig) Description This function does a public RSA operation and checks the message digest. This is the generic wrapper to do PKCS#1 verification with the mode from the context. Parameters ctx: The initialized RSA public key context to use. f_rng: The RNG function to use. If mode is MBEDTLS_RSA_PRIVATE, this is used for blinding and should be provided; see mbedtls_rsa_private() for more. Otherwise, it is ignored. p_rng: The RNG context to be passed to f_rng. This may be NULL if f_rng is NULL or does not need a context. mode: The mode of operation. This must be either MBEDTLS_RSA_PUBLIC or MBEDTLS_RSA_PRIVATE (deprecated). User Manual CFR0012 Revision 2.2 166 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide md_alg: The message-digest algorithm used to hash the original data. Use MBEDTLS_MD_NONE for signing raw data. hashlen: The length of the message digest. This is only used if md_alg is MBEDTLS_MD_NONE. hash: The buffer holding the message digest or raw data. If md_alg is MBEDTLS_MD_NONE, this must be a readable buffer of length hashlen Bytes. If md_alg is not MBEDTLS_MD_NONE, it must be a readable buffer of length the size of the hash that corresponds to md_alg. sig: The buffer holding the signature. This must be a readable buffer of length ctx->len Bytes. For example, 256 Bytes for a 2048bit RSA modulus. Return values 0 on success. An MBEDTLS_ERR_RSA_XXX error code on failure. void mbedtls_rsa_free(mbedtls_rsa_context *ctx) Prototype void mbedtls_rsa_free(mbedtls_rsa_context *ctx) Description This function frees the components of an RSA key. Parameters ctx: The RSA context to free. May be NULL, in which case this function is a no-op. If it is not NULL, it must point to an initialized RSA context. Return values None. 6.8 Crypto Algorithms ECDH The Elliptic-curve Diffie-Hellman (ECDH) sample application demonstrates common use cases of Elliptic-curve Diffie-Hellman (ECDH) key exchange. It is a variant of the Diffie-Hellman protocol that uses elliptic-curve cryptography. The DA16200 SDK includes an "mbedTLS" library. The API of ECDH is the same as what the "mbedTLS" library provides. This section describes how the Ellipticcurve Diffie-Hellman sample application is built and works. 6.8.1 How to Run 1. Open the workspace for the Crypto Algorithms for ECDH application as follows: .\sample\Crypto\Crypto_ECDH\build\DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. The example application explains how to use the ECDH function. >>> Using Elliptic Curve: SECP224R1 * Seeding the random number generator: passed * Setting up client context: passed * Setting up server context: passed * Server reading client key and computing secret: passed * Client reading server key and computing secret: passed * Checking if both computed secrets are equal: passed >>> Using Elliptic Curve: SECP256R1 * Seeding the random number generator: passed * Setting up client context: passed * Setting up server context: passed * Server reading client key and computing secret: passed * Client reading server key and computing secret: passed * Checking if both computed secrets are equal: passed >>> Using Elliptic Curve: SECP384R1 * Seeding the random number generator: passed * Setting up client context: passed * Setting up server context: passed User Manual CFR0012 Revision 2.2 167 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide * Server reading client key and computing secret: passed * Client reading server key and computing secret: passed * Checking if both computed secrets are equal: passed >>> Using Elliptic Curve: SECP521R1 * Seeding the random number generator: passed * Setting up client context: passed * Setting up server context: passed * Server reading client key and computing secret: passed * Client reading server key and computing secret: passed * Checking if both computed secrets are equal: passed >>> Using Elliptic Curve: Curve25519 * Seeding the random number generator: passed * Setting up client context: passed * Setting up server context: passed * Server reading client key and computing secret: passed * Client reading server key and computing secret: passed * Checking if both computed secrets are equal: passed 6.8.2 Application Initialization The DA16200 SDK provides an "mbedTLS" library. This library helps with the easy implementation of the User Application. This example describes how the Elliptic Curve Diffie-Hellman (ECDH) key exchange works with the use of Elliptic Curve SECP224R1, SECP256R1, SECP384R1, SECP521R1, and Curve25519. void crypto_sample_ecdh(ULONG arg) { mbedtls_ecp_group_id ids[5] = { MBEDTLS_ECP_DP_SECP224R1, /*!< 224-bits NIST curve */ MBEDTLS_ECP_DP_SECP256R1, /*!< 256-bits NIST curve */ MBEDTLS_ECP_DP_SECP384R1, /*!< 384-bits NIST curve */ MBEDTLS_ECP_DP_SECP521R1, /*!< 521-bits NIST curve */ MBEDTLS_ECP_DP_CURVE25519 /*!< Curve25519 */ }; for (idx = 0 ; idx < 5 ; idx++) { ret = crypto_sample_ecdh_key_exchange(ids[idx]); if (ret) { break; } } } 6.8.3 How ECDH Key Exchange Works This sample application shows how ECDH works over the API of the "mbedTLS" library. In this example, the ECDH key exchange is verified on the server and client side. int crypto_sample_ecdh_key_exchange(mbedtls_ecp_group_id id) { mbedtls_ecdh_context *ctx_cli = NULL; mbedtls_ecdh_context *ctx_srv = NULL; mbedtls_entropy_context *entropy = NULL; mbedtls_ctr_drbg_context *ctr_drbg = NULL; // Initialize an ECDH context. mbedtls_ecdh_init(ctx_cli); mbedtls_ecdh_init(ctx_srv); User Manual CFR0012 Revision 2.2 168 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide // Initialize the CTR_DRBG context. mbedtls_ctr_drbg_init(ctr_drbg); // Initialize the entropy context. mbedtls_entropy_init(entropy); PRINTF( ">>> Using Elliptic Curve: "); switch (id) { case MBEDTLS_ECP_DP_SECP224R1: PRINTF("SECP224R1\n"); break; case MBEDTLS_ECP_DP_SECP256R1: PRINTF("SECP256R1\n"); break; case MBEDTLS_ECP_DP_SECP384R1: PRINTF("SECP384R1\n"); break; case MBEDTLS_ECP_DP_SECP521R1: PRINTF("SECP521R1\n"); break; case MBEDTLS_ECP_DP_CURVE25519: PRINTF("Curve25519\n"); break; default: PRINTF("failed - [%s] Invalid Curve selected!\n"); goto cleanup; } /* * Initialize random number generation */ ret = mbedtls_ctr_drbg_seed(ctr_drbg, mbedtls_entropy_func, entropy, (const unsigned char *)pers, sizeof pers); /* * Client: inialize context and generate keypair */ // Sets up an ECP group context from a standardized set of domain parameters. ret = mbedtls_ecp_group_load(&(ctx_cli->grp), id); // Generate an ECDH keypair on an elliptic curve. ret = mbedtls_ecdh_gen_public(&(ctx_cli->grp), &(ctx_cli->d), &(ctx_cli->Q), mbedtls_ctr_drbg_random, ctr_drbg); // Export multi-precision integer (MPI) into unsigned binary data, // big endian (X coordinate of ECP point) MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&(ctx_cli->Q.X), cli_to_srv_x, buflen)); // Export multi-precision integer (MPI) into unsigned binary data, // big endian (Y coordinate of ECP point) MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&(ctx_cli->Q.Y), cli_to_srv_y, buflen)); /* * Server: initialize context and generate keypair */ // Sets up an ECP group context from a standardized set of domain parameters. ret = mbedtls_ecp_group_load(&(ctx_srv->grp), id); User Manual CFR0012 Revision 2.2 169 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide // Generate a public key ret = mbedtls_ecdh_gen_public(&(ctx_srv->grp), &(ctx_srv->d), &(ctx_srv->Q), mbedtls_ctr_drbg_random, ctr_drbg); // Export multi-precision integer (MPI) into unsigned binary data, big endian (X coordinate of ECP point) MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&(ctx_srv->Q.X), srv_to_cli_x, buflen)); // Export multi-precision integer (MPI) into unsigned binary data, big endian (Y coordinate of ECP point) MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&(ctx_srv->Q.Y), srv_to_cli_y, buflen)); /* * Server: read peer's key and generate shared secret */ // Set the Z component of the peer's public value (public key) to 1 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&(ctx_srv->Qp.Z), 1)); // Set the X component of the peer's public value based on what was passed from client in the buffer MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&(ctx_srv->Qp.X), cli_to_srv_x, buflen)); // Set the Y component of the peer's public value based on what was passed from client in the buffer MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&(ctx_srv->Qp.Y), cli_to_srv_y, buflen)); // Compute the shared secret. ret = mbedtls_ecdh_compute_shared(&(ctx_srv->grp), &(ctx_srv->z), &(ctx_srv->Qp), &(ctx_srv->d), mbedtls_ctr_drbg_random, ctr_drbg); /* * Client: read peer's key and generate shared secret */ MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&(ctx_cli->Qp.Z), 1)); MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&(ctx_cli->Qp.X), srv_to_cli_x, buflen)); MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&(ctx_cli->Qp.Y), srv_to_cli_y, buflen)); // Compute the shared secret. ret = mbedtls_ecdh_compute_shared( &(ctx_cli->grp), &(ctx_cli->z), &(ctx_cli->Qp), &(ctx_cli->d), mbedtls_ctr_drbg_random, ctr_drbg ); /* * Verification: are the computed secrets equal? */ PRINTF("* Checking if both computed secrets are equal: "); MBEDTLS_MPI_CHK(mbedtls_mpi_cmp_mpi(&(ctx_cli->z), &(ctx_srv->z))); // Free ECDH context. User Manual CFR0012 Revision 2.2 170 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide if (ctx_cli) mbedtls_ecdh_free(ctx_cli); if (ctx_srv) mbedtls_ecdh_free(ctx_srv); // Free the data in the context. if (entropy) mbedtls_entropy_free(entropy); // Clear CTR_CRBG context data. if (ctr_drbg) mbedtls_ctr_drbg_free(ctr_drbg); } The API details are as follows: void mbedtls_ecdh_init(mbedtls_ecdh_context *ctx) Prototype void mbedtls_ecdh_init(mbedtls_ecdh_context *ctx) Description This function initializes an ECDH context. Parameters ctx: The ECDH context to initialize. This must not be NULL. Return values None. int mbedtls_ecp_group_load(mbedtls_ecp_group *grp, mbedtls_ecp_group_id id) Prototype int mbedtls_ecp_group_load(mbedtls_ecp_group *grp, mbedtls_ecp_group_id id) Description This function sets up an ECP group context from a standardized set of domain parameters. Parameters grp: The group context to setup. This must be initialized. id: The identifier of the domain parameter set to load. Return values 0 on success. MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE if the id does not correspond to a known group. Another negative error code on other kinds of failure. int mbedtls_ecdh_gen_public(mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q, int(*)(void *, unsigned char *, size_t)f_rng, void *p_rng) Prototype int mbedtls_ecdh_gen_public(mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q, int(*)(void *, unsigned char *, size_t)f_rng, void *p_rng) Description This function generates an ECDH keypair on an elliptic curve. This function does the first of two core computations implemented during the ECDH key exchange. The second core computation is done by mbedtls_ecdh_compute_shared(). Parameters grp: The ECP group to use. This must be initialized and have domain parameters loaded, for example through mbedtls_ecp_load() or mbedtls_ecp_tls_read_group(). d: The destination MPI (private key). This must be initialized. Q: The destination point (public key). This must be initialized. f_rng: The RNG function to use. This must not be NULL. p_rng: The RNG context to be passed to f_rng. This may be NULL in case f_rng does not need a context argument. Return values 0 on success. Another MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code on failure. int mbedtls_ecdh_compute_shared(mbedtls_ecp_group *grp, mbedtls_mpi *z, const mbedtls_ecp_point *Q, const mbedtls_mpi *d, int(*)(void *, unsigned char *, size_t)f_rng, void *p_rng) User Manual CFR0012 Revision 2.2 171 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide Prototype int mbedtls_ecdh_compute_shared(mbedtls_ecp_group *grp, mbedtls_mpi *z, const mbedtls_ecp_point *Q, const mbedtls_mpi *d, int(*)(void *, unsigned char *, size_t)f_rng, void *p_rng) Description This function computes the shared secret. This function does the second of two core computations implemented during the ECDH key exchange. The first core computation is done by mbedtls_ecdh_gen_public(). Parameters grp: The ECP group to use. This must be initialized and have domain parameters loaded, for example through mbedtls_ecp_load() or mbedtls_ecp_tls_read_group(). z: The destination MPI (shared secret). This must be initialized. Q: The public key from another party. This must be initialized. d: Our secret exponent (private key). This must be initialized. f_rng: The RNG function. This may be NULL if randomization of intermediate results during the ECP computations is not needed (discouraged). See the documentation of mbedtls_ecp_mul() for more information. p_rng: The RNG context to be passed to f_rng. This may be NULL if f_rng is NULL or does not need a context argument. Return values 0 on success. Another MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code on failure. void mbedtls_ecdh_free(mbedtls_ecdh_context *ctx) Prototype void mbedtls_ecdh_free(mbedtls_ecdh_context *ctx) Description This function frees a context. Parameters ctx: The context to free. This may be NULL, in which case this function does nothing. If it is not NULL, it must point to an initialized ECDH context. Return values None. 6.9 Crypto Algorithms KDF The Key Derivation Function (KDF) sample application demonstrates common use cases of PKCS#5 functions. The DA16200 SDK includes an "mbedTLS" library. The API of KDF is the same as what the "mbedTLS" library provides. This section describes how the Key Derivation Function sample application is built and works. 6.9.1 How to Run 1. Open the workspace for the Crypto Algorithms for KDF application as follows: .\sample\Crypto\Crypto_KDF\build\DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. The example application explains how to use the KDF. * PBKDF2 (SHA1): passed 6.9.2 Application Initialization The DA16200 SDK provides an "mbedTLS" library. This library helps with the easy implementation of the User Application. This example uses a password-based Key Derivation Function specified in PKCS#5 PBKDF2 and implemented in "mbedTLS" in function mbedtls_pkcs5_pdkdf2_hmac. User Manual CFR0012 Revision 2.2 172 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide void crypto_sample_kdf(ULONG arg) { crypto_sample_pkcs5(); } 6.9.3 How KDF Works This example application shows how KDF works over the API of the "mbedTLS" library. In this example, PKCS#5 PBKDF2 is used. To verify, a SHA-1 Hash algorithm is used. int crypto_sample_pkcs5() { mbedtls_md_context_t *sha1_ctx = NULL; const mbedtls_md_info_t *info_sha1; // Initialize a SHA-1 context. mbedtls_md_init(sha1_ctx); // Get the message-digest information associated with the given digest type. info_sha1 = mbedtls_md_info_from_type(MBEDTLS_MD_SHA1); // Select the message digest algorithm to use, and allocates internal structures. ret = mbedtls_md_setup(sha1_ctx, info_sha1, 1); PRINTF("* PBKDF2 (SHA1): "); // Derive a key from a password using PBKDF2 function with HMAC ret = mbedtls_pkcs5_pbkdf2_hmac(sha1_ctx, pkcs5_password, pkcs5_plen, pkcs5_salt, pkcs5_slen, pkcs5_it_cnt, pkcs5_key_len, key); /* Clear the internal structure of ctx and frees any embedded internal structure, * but does not free ctx itself. */ if (sha1_ctx) mbedtls_md_free(sha1_ctx); } The API details are as follows: int mbedtls_pkcs5_pbkdf2_hmac(mbedtls_md_context_t *ctx, const unsigned char *password, size_t plen, const unsigned char *salt, size_t slen, unsigned int iteration_count, uint32_t key_length, unsigned char *output) Prototype int mbedtls_pkcs5_pbkdf2_hmac(mbedtls_md_context_t *ctx, const unsigned char *password, size_t plen, const unsigned char *salt, size_t slen, unsigned int iteration_count, uint32_t key_length, unsigned char *output) Description PKCS#5 PBKDF2 using HMAC. Parameters ctx: Generic HMAC context. password: Password to use when generating a key. plen: Length of password. salt: Salt to use when generating a key. slen: Length of salt. iteration_count: Iteration count. key_length: Length of generated key in bytes. User Manual CFR0012 Revision 2.2 173 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide output: Generated key. Must be at least as big as key_length. Return values 0 on success, or a MBEDTLS_ERR_XXX code if verification fails. 6.10 Crypto Algorithms Public Key Abstraction Layer The "mbedTLS" library provides the Public Key abstraction layer for confidentiality, integrity, authentication, and non-repudiation based on asymmetric algorithms, with either the traditional RSA or Elliptic Curves. The Public Key abstraction layer sample application demonstrates common use cases of the APIs. This section describes how the Public Key abstraction layer sample application is built and works. 6.10.1 How to Run 1. Open the workspace for the Public Key Abstraction Layer application as follows: ~/SDK/sample/Crypto/Crypto_PK/build/DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. The example application explains how to use KDF. * PK Information >>> RSA: passed >>> EC: passed >>> EC_DH: passed >>> ECDSA: passed * RSA Verification Test >>> RSA verify test vector #1 (good): passed >>> RSA verify test vector #2 (bad): passed * Signature Verification Test >>> ECDSA: passed >>> EC(DSA): passed >>> EC_DH (no): passed >>> RSA: passed * Decryption Test >>> RSA decrypt test vector #1: passed >>> RSA decrypt test vector #2: passed RSA Alt Test: passed * RSA Verification with option Test >>> Verify ext RSA #2 (PKCS1 v2.1, salt_len = ANY, wrong message): passed >>> Verify ext RSA #3 (PKCS1 v2.1, salt_len = 0, OK): passed >>> Verify ext RSA #4 (PKCS1 v2.1, salt_len = max, OK): passed >>> Verify ext RSA #5 (PKCS1 v2.1, wrong salt_len): passed >>> Verify ext RSA #6 (PKCS1 v2.1, MGF1 alg != MSG hash alg): passed >>> Verify ext RSA #7 (PKCS1 v2.1, wrong MGF1 alg != MSG hash alg): passed >>> Verify ext RSA #8 (PKCS1 v2.1, RSASSA-PSS without options): passed >>> Verify ext RSA #9 (PKCS1 v1.5, RSA with options): passed >>> Verify ext RSA #10 (PKCS1 v1.5, RSA without options): passed >>> Verify ext RSA #11 (PKCS1 v2.1, asking for ECDSA): passed >>> Verify ext RSA #12 (PKCS1 v1.5, good): passed * PK pair Test >>> Check pair #1 (EC, OK): passed >>> Check pair #2 (EC, bad): passed 6.10.2 User Thread The user thread of the Public Key Abstraction Layer application is added as shown in the example below and is executed by the system. SAMPLE_CRYPTO_PK should be a unique name to create a thread. ~/SDK/sample/Crypto/Crypto_PK/src/sample_apps.c User Manual CFR0012 Revision 2.2 174 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide static const app_thread_info_t sample_apps_table[] = { { SAMPLE_CRYPTO_PK, crypto_sample_pk, 4096, USER_PRI_APP(1), FALSE, FALSE, UNDEF_PORT, RUN_ALL_MODE }, }; 6.10.3 Application Initialization The DA16200 SDK provides an "mbedTLS" library. This library helps with an easy implementation of the User Application. This example shows how to use Public Key Abstraction Layer of the "mbedTLS" library. void crypto_sample_pk(ULONG arg) { PRINTF("* PK Information\n"); ret = crypto_sample_pk_utils( crypto_sample_pk_utils_list[i].type, crypto_sample_pk_utils_list[i].size, crypto_sample_pk_utils_list[i].len, crypto_sample_pk_utils_list[i].name); PRINTF("* RSA Verification Test\n"); ret = crypto_sample_pk_rsa_verify_test_vec( crypto_sample_pk_rsa_verify_test_vec_list[i].title, crypto_sample_pk_rsa_verify_test_vec_list[i].message_hex_string, crypto_sample_pk_rsa_verify_test_vec_list[i].digest, crypto_sample_pk_rsa_verify_test_vec_list[i].mod, crypto_sample_pk_rsa_verify_test_vec_list[i].radix_N, crypto_sample_pk_rsa_verify_test_vec_list[i].input_N, crypto_sample_pk_rsa_verify_test_vec_list[i].radix_E, crypto_sample_pk_rsa_verify_test_vec_list[i].input_E, crypto_sample_pk_rsa_verify_test_vec_list[i].result_hex_str, crypto_sample_pk_rsa_verify_test_vec_list[i].result); PRINTF("* Signuature Verification Test\n"); ret = crypto_sample_pk_sign_verify( crypto_sample_pk_sign_verify_list[i].title, crypto_sample_pk_sign_verify_list[i].type, crypto_sample_pk_sign_verify_list[i].sign_ret, crypto_sample_pk_sign_verify_list[i].verify_ret); PRINTF("* Decryption Test\n"); ret = crypto_sample_pk_rsa_decrypt_test_vec( crypto_sample_pk_rsa_decrypt_list[i].title, crypto_sample_pk_rsa_decrypt_list[i].cipher_hex, crypto_sample_pk_rsa_decrypt_list[i].mod, crypto_sample_pk_rsa_decrypt_list[i].radix_P, crypto_sample_pk_rsa_decrypt_list[i].input_P, crypto_sample_pk_rsa_decrypt_list[i].radix_Q, crypto_sample_pk_rsa_decrypt_list[i].input_Q, crypto_sample_pk_rsa_decrypt_list[i].radix_N, crypto_sample_pk_rsa_decrypt_list[i].input_N, crypto_sample_pk_rsa_decrypt_list[i].radix_E, crypto_sample_pk_rsa_decrypt_list[i].input_E, crypto_sample_pk_rsa_decrypt_list[i].clear_hex, crypto_sample_pk_rsa_decrypt_list[i].result); ret = crypto_sample_pk_rsa_alt(); PRINTF("* RSA Verification with option Test\n"); ret = crypto_sample_pk_rsa_verify_ext_test_vec( crypto_sample_pk_rsa_verify_ext_list[i].title, User Manual CFR0012 Revision 2.2 175 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide crypto_sample_pk_rsa_verify_ext_list[i].message_hex_string, crypto_sample_pk_rsa_verify_ext_list[i].digest, crypto_sample_pk_rsa_verify_ext_list[i].mod, crypto_sample_pk_rsa_verify_ext_list[i].radix_N, crypto_sample_pk_rsa_verify_ext_list[i].input_N, crypto_sample_pk_rsa_verify_ext_list[i].radix_E, crypto_sample_pk_rsa_verify_ext_list[i].input_E, crypto_sample_pk_rsa_verify_ext_list[i].result_hex_str, crypto_sample_pk_rsa_verify_ext_list[i].pk_type, crypto_sample_pk_rsa_verify_ext_list[i].mgf1_hash_id, crypto_sample_pk_rsa_verify_ext_list[i].salt_len, crypto_sample_pk_rsa_verify_ext_list[i].result); PRINTF("* PK pair Test\n"); ret = crypto_sample_pk_check_pair( crypto_sample_pk_check_pair_list[i].title, crypto_sample_pk_check_pair_list[i].pub_file, crypto_sample_pk_check_pair_list[i].prv_file, crypto_sample_pk_check_pair_list[i].result); } 6.10.4 How Public Key Abstraction Layer is Used The "mbedTLS" library provides the Public Key Abstraction Layer for confidentiality, integrity, authentication, and non-repudiation based on asymmetric algorithms, with either the traditional RSA or Elliptic Curves. 1. The user needs to check which public key could be supported by the "mbedTLS" library. The example code below shows how to get and check public key information. int crypto_sample_pk_utils(mbedtls_pk_type_t type, int size, int len, char *name) { mbedtls_pk_context pk; // Initialize a mbedtls_pk_context. mbedtls_pk_init(&pk); /* Initialize a PK context with the information given * and allocates the type-specific PK subcontext. */ ret = mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(type)); // Get the key type. if (mbedtls_pk_get_type(&pk) != type) { } // Tell if a context can do the operation given by type. if (!mbedtls_pk_can_do(&pk, type)) { } // Get the size in bits of the underlying key. if (mbedtls_pk_get_bitlen(&pk) != (unsigned)size) { } // Get the length in bytes of the underlying key. if (mbedtls_pk_get_len(&pk) != (unsigned)len) { } // Access the type name. if ((ret = strcmp(mbedtls_pk_get_name(&pk), name)) != 0) { } User Manual CFR0012 Revision 2.2 176 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide // Free the components of a mbedtls_pk_context. mbedtls_pk_free(&pk); } The API details are as follows: void mbedtls_pk_init(mbedtls_pk_context *ctx) Prototype void mbedtls_pk_init(mbedtls_pk_context *ctx) Description Initialize an mbedtls_pk_context (as NONE). Parameters ctx: The context to initialize. This must not be NULL. Return values None. int mbedtls_pk_setup(mbedtls_pk_context *ctx, const mbedtls_pk_info_t *info) Prototype int mbedtls_pk_setup(mbedtls_pk_context *ctx, const mbedtls_pk_info_t *info) Description Initialize a PK context with the information given and allocates the type-specific PK subcontext. Parameters ctx: Context to initialize. It must not have been set up yet (type MBEDTLS_PK_NONE). info: Information to use. Return values 0 on success, MBEDTLS_ERR_PK_BAD_INPUT_DATA on invalid input, MBEDTLS_ERR_PK_ALLOC_FAILED on allocation failure. mbedtls_pk_type_t mbedtls_pk_get_type(const mbedtls_pk_context *ctx) Prototype mbedtls_pk_type_t mbedtls_pk_get_type(const mbedtls_pk_context *ctx) Description Get the key type. Parameters ctx: The PK context to use. It must have been initialized. Return values MBEDTLS_PK_NONE for a context that has not been set up. int mbedtls_pk_can_do(const mbedtls_pk_context *ctx, mbedtls_pk_type_t type) Prototype int mbedtls_pk_can_do(const mbedtls_pk_context *ctx, mbedtls_pk_type_t type) Description Tell if a context can do the operation given by the type. Parameters ctx: The context to query. It must have been initialized. type: The desired type. Return values 1 if the context can do operations on the given type. 0 if the context cannot do the operations on the given type. This is always the case for a context that has been initialized but not set up, or that has been cleared with mbedtls_pk_free(). size_t mbedtls_pk_get_bitlen(const mbedtls_pk_context *ctx) Prototype size_t mbedtls_pk_get_bitlen(const mbedtls_pk_context *ctx) Description Get the size in bits of the underlying key. Parameters ctx: The context to query. It must have been initialized. Return values Key size in bits, or 0 on error. static size_t mbedtls_pk_get_len(const mbedtls_pk_context *ctx) Prototype static size_t mbedtls_pk_get_len(const mbedtls_pk_context *ctx) Description Get the length in bytes of the underlying key. User Manual CFR0012 Revision 2.2 177 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide Parameters ctx: The context to query. It must have been initialized. Return values Key size in bits, or 0 on error. const char* mbedtls_pk_get_name(const mbedtls_pk_context *ctx) Prototype const char* mbedtls_pk_get_name(const mbedtls_pk_context *ctx) Description Access the type name. Parameters ctx: The PK context to use. It must have been initialized. Return values Type name on success, or "invalid PK". void mbedtls_pk_free(mbedtls_pk_context *ctx) Prototype void mbedtls_pk_free(mbedtls_pk_context *ctx) Description Free the components of a mbedtls_pk_context. Parameters ctx: The context to clear. It must have been initialized. If this is NULL, this function does nothing. Return values None. 2. Function crypto_sample_pk_genkey describes how to generate a public key with the given algorithms (RSA or Elliptic curves). int crypto_sample_pk_genkey(mbedtls_pk_context *pk) { mbedtls_entropy_context *entropy = NULL; mbedtls_ctr_drbg_context *ctr_drbg = NULL; // Initialize the entropy context. mbedtls_entropy_init(entropy); // Initialize the CTR_DRBG context. mbedtls_ctr_drbg_init(ctr_drbg); // Seed and sets up the CTR_DRBG entropy source for future reseeds. mbedtls_ctr_drbg_seed(ctr_drbg, mbedtls_entropy_func, entropy, NULL, 0); #if defined(MBEDTLS_RSA_C) && defined(MBEDTLS_GENPRIME) if (mbedtls_pk_get_type(pk) == MBEDTLS_PK_RSA) { // Generate the RSA key pair. ret = mbedtls_rsa_gen_key(mbedtls_pk_rsa(*pk), rnd_std_rand, ctr_drbg, RSA_KEY_SIZE, 3); } #endif #if defined(MBEDTLS_ECP_C) if ((mbedtls_pk_get_type(pk) == MBEDTLS_PK_ECKEY) || (mbedtls_pk_get_type(pk) == MBEDTLS_PK_ECKEY_DH) || (mbedtls_pk_get_type(pk) == MBEDTLS_PK_ECDSA)) { // Set a group using well-known domain parameters. ret = mbedtls_ecp_group_load(&mbedtls_pk_ec(*pk)->grp, MBEDTLS_ECP_DP_SECP192R1); // Generate key pair, wrapper for conventional base point ret = mbedtls_ecp_gen_keypair(&mbedtls_pk_ec(*pk)->grp, &mbedtls_pk_ec(*pk)>d, &mbedtls_pk_ec(*pk)->Q, rnd_std_rand, ctr_drbg); } #endif mbedtls_ctr_drbg_free(ctr_drbg); User Manual CFR0012 Revision 2.2 178 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide mbedtls_entropy_free(entropy); } The API details are as follows: int mbedtls_rsa_gen_key(mbedtls_rsa_context *ctx, int(*)(void *, unsigned char *, size_t) f_rng, void *p_rng, unsigned int nbits, int exponent) Prototype int mbedtls_rsa_gen_key(mbedtls_rsa_context *ctx, int(*)(void *, unsigned char *, size_t)f_rng, void *p_rng, unsigned int nbits, int exponent) Description This function generates an RSA keypair. Parameters ctx: The initialized RSA context used to hold the key. f_rng: The RNG function to be used for key generation. This must not be NULL. p_rng: The RNG context to be passed to f_rng. This may be NULL if f_rng does not need a context. nbits: The size of the public key in bits. exponent: The public exponent to use. For example, 65537. This must be odd and greater than 1. Return values 0 on success. An MBEDTLS_ERR_RSA_XXX error code on failure. int mbedtls_ecp_gen_keypair(mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q, int(*)(void *, unsigned char *, size_t)f_rng, void *p_rng) Prototype int mbedtls_ecp_gen_keypair (mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q, int(*)(void *, unsigned char *, size_t)f_rng, void *p_rng) Description This function generates an ECP keypair. Parameters grp: The ECP group to generate a key pair for. This must be initialized and have group parameters set, for example through mbedtls_ecp_group_load(). d: The destination MPI (secret part). This must be initialized. Q: The destination point (public part). This must be initialized. f_rng: The RNG function. This must not be NULL. p_rng: The RNG context to be passed to f_rng. This may be NULL if f_rng does not need a context argument. Return values 0 on success. An MBEDTLS_ERR_ECP_XXX or MBEDTLS_MPI_XXX error code on failure. 3. Function crypto_sample_pk_rsa_verify_test_vec describes how an RSA signature is verified with Public Key abstraction Layer functions. int crypto_sample_pk_rsa_verify_test_vec(char *title, char *message_hex_string, mbedtls_md_type_t digest, int mod, int radix_N, char *input_N, int radix_E, char *input_E, char *result_hex_str, int result) { mbedtls_rsa_context *rsa = NULL; mbedtls_pk_context pk; // Initialize a mbedtls_pk_context. mbedtls_pk_init(&pk); /* Initialize a PK context with the information given * and allocates the type-specific PK subcontext. */ ret = mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)); User Manual CFR0012 Revision 2.2 179 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide // Quick access to an RSA context inside a PK context. rsa = mbedtls_pk_rsa(pk); rsa->len = mod / 8; MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&rsa->N, radix_N, input_N)); MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&rsa->E, radix_E, input_E)); msg_len = unhexify(message_str, message_hex_string); unhexify(result_str, result_hex_str); // Get the message-digest information associated with the given digest type. if (mbedtls_md_info_from_type(digest) != NULL) { /* Calculates the message-digest of a buffer, * with respect to a configurable message-digest algorithm in a single call. */ ret = mbedtls_md(mbedtls_md_info_from_type(digest), message_str, msg_len, hash_result); } // Verify signature (including padding if relevant) & Check result with expected result. ret = mbedtls_pk_verify(&pk, digest, hash_result, 0, result_str, mbedtls_pk_get_len(&pk)); // Free the components of a mbedtls_pk_context. mbedtls_pk_free(&pk); } The API details are as follows: int mbedtls_pk_verify(mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, const unsigned char *sig, size_t sig_len) Prototype int mbedtls_pk_verify(mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, const unsigned char *sig, size_t sig_len) Description Verify signature (including padding if relevant). Parameters ctx: The PK context to use. It must have been set up. md_alg: Hash algorithm used. hash: Hash of the message to sign. hash_len: Hash length or 0. sig: Signature to verify. sig_len: Signature length. Return values 0 on success (signature is valid), MBEDTLS_ERR_PK_SIG_LEN_MISMATCH if there is a valid signature in sig but its length is less than siglen, or a specific error code. 4. Function crypto_sample_pk_sign_verify describes to generate a key, make a signature, and to verify this with the given crypto algorithms. int crypto_sample_pk_sign_verify(char *title, mbedtls_pk_type_t type, int sign_ret, int verify_ret) { mbedtls_pk_context pk; // Initialize a mbedtls_pk_context. User Manual CFR0012 Revision 2.2 180 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide mbedtls_pk_init(&pk); /* Initialize a PK context with the information given * and allocates the type-specific PK subcontext. */ ret = mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(type)); // Generate key pair by the type. ret = crypto_sample_pk_genkey(&pk); // Make signature, including padding if relevant and Check result with expected result. ret = mbedtls_pk_sign(&pk, MBEDTLS_MD_SHA256, hash, 64, sig, &sig_len, rnd_std_rand, NULL); // Verify signature (including padding if relevant) and Check result with expected result. ret = mbedtls_pk_verify(&pk, MBEDTLS_MD_SHA256, hash, 64, sig, sig_len); // Free the components of a mbedtls_pk_context. mbedtls_pk_free(&pk); } The API details are as follows: int mbedtls_pk_sign(mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, unsigned char *sig, size_t *sig_len, int(*)(void *, unsigned char *, size_t)f_rng, void *p_rng) Prototype int mbedtls_pk_sign(mbedtls_pk_context *ctx, mbedtls_md_type_t md_alg, const unsigned char *hash, size_t hash_len, unsigned char *sig, size_t *sig_len, int(*)(void *, unsigned char *, size_t)f_rng, void *p_rng) Description Make signature, including padding if relevant. Parameters ctx: The PK context to use. Must have been set up with a private key. md_alg: Hash algorithm used (see notes). hash: Hash of the message to sign. hash_len: Hash length or 0 (see notes). sig: Place to write the signature. sig_len: Number of bytes written. f_rng: RNG function. p_rng: RNG parameter. Return values 0 on success, or a specific error code. 5. Function crypto_sample_pk_rsa_decrypt_test_vec describes how RSA is decrypted using Public Key Abstraction Layer's functions. Encryption could also be used. But this example only explains RSA decryption. int crypto_sample_pk_rsa_decrypt_test_vec(char *title, char *cipher_hex, int mod, int radix_P, char *input_P, int radix_Q, char *input_Q, int radix_N, char *input_N, int radix_E, char *input_E, char *clear_hex, int result) { rnd_pseudo_info *rnd_info = NULL; mbedtls_rsa_context *rsa = NULL; mbedtls_pk_context pk; // Initialize a mbedtls_pk_context. mbedtls_pk_init(&pk); User Manual CFR0012 Revision 2.2 181 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide /* Initialize a PK context with the information given * and allocates the type-specific PK subcontext. */ ret = mbedtls_pk_setup(&pk, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)); // Quick access to an RSA context inside a PK context. rsa = mbedtls_pk_rsa(pk); // Import a set of core parameters into an RSA context. ret = mbedtls_rsa_import(rsa, &N, &P, &Q, NULL, &E); // Retrieve the length of RSA modulus in Bytes. if (mbedtls_rsa_get_len(rsa) != (size_t)(mod / 8)) { } // Complete an RSA context from a set of imported core parameters. ret = mbedtls_rsa_complete(rsa); // Decrypt message (including padding if relevant). ret = mbedtls_pk_decrypt(&pk, cipher, cipher_len, output, &olen, (1000 * sizeof(unsigned char)), rnd_pseudo_rand, rnd_info); // Free the components of a mbedtls_pk_context. mbedtls_pk_free(&pk); } The API details are as follows: int mbedtls_rsa_import(mbedtls_rsa_context *ctx, const mbedtls_mpi *N, const mbedtls_mpi *P, const mbedtls_mpi *Q, const mbedtls_mpi *D, const mbedtls_mpi *E) Prototype int mbedtls_rsa_import(mbedtls_rsa_context *ctx, const mbedtls_mpi *N, const mbedtls_mpi *P, const mbedtls_mpi *Q, const mbedtls_mpi *D, const mbedtls_mpi *E) Description This function imports a set of core parameters into an RSA context. Parameters ctx: The initialized RSA context to store the parameters in. N: The RSA modulus. This may be NULL. P: The first prime factor of N. This may be NULL. Q: The second prime factor of N. This may be NULL. D: The private exponent. This may be NULL. E: The public exponent. This may be NULL. Return values 0 on success. A non-zero error code on failure. int mbedtls_rsa_complete(mbedtls_rsa_context *ctx) Prototype int mbedtls_rsa_complete(mbedtls_rsa_context *ctx) Description This function completes an RSA context from a set of imported core parameters. To setup an RSA public key, precisely N and E must have been imported. To setup an RSA private key, sufficient information must be present for the other parameters to be derivable. The default implementation supports the following: > Derive P, Q from N, D, E. > Derive N, D from P, Q, E. Alternative implementations need not support these. User Manual CFR0012 Revision 2.2 182 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide If this function runs successfully, it guarantees that the RSA context can be used for RSA operations without the risk of failure or crash. Parameters ctx: The initialized RSA context holding imported parameters. Return values 0 on success. MBEDTLS_ERR_RSA_BAD_INPUT_DATA if the attempted derivations failed. int mbedtls_pk_decrypt(mbedtls_pk_context *ctx, const unsigned char *input, size_t ilen, unsigned char *output, size_t *olen, size_t osize, int(*)(void *, unsigned char *, size_t)f_rng, void *p_rng) Prototype int mbedtls_pk_decrypt(mbedtls_pk_context *ctx, const unsigned char *input, size_t ilen, unsigned char *output, size_t *olen, size_t osize, int(*)(void *, unsigned char *, size_t)f_rng, void *p_rng) Description Decrypt message (including padding if relevant). Parameters ctx: The PK context to use. It must have been set up with a private key. input: Input to decrypt. ilen: Input size. output: Decrypted output. olen: Decrypted message length. osize: Size of the output buffer. f_rng: RNG function. p_rng: RNG parameter. Return values 0 on success, or a specific error code. 6. Function crypto_sample_pk_rsa_alt describes how RSA ALT context progresses to make a signature and to decrypt. int crypto_sample_pk_rsa_alt() { /* * An rsa_alt context can only do private operations (decrypt, sign). * Test it against the public operations (encrypt, verify) of a * corresponding rsa context. */ mbedtls_rsa_context *raw = NULL; mbedtls_pk_context rsa, alt; mbedtls_pk_debug_item *dbg_items = NULL; // Initialize an RSA context. mbedtls_rsa_init(raw, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE); // Initialize a mbedtls_pk_context. mbedtls_pk_init(&rsa); mbedtls_pk_init(&alt); /* Initialize a PK context with the information given * and allocates the type-specific PK subcontext. */ ret = mbedtls_pk_setup(&rsa, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)); // Generate key pair by the type. ret = crypto_sample_pk_genkey(&rsa); // Copy the components of an RSA context. ret = mbedtls_rsa_copy(raw, mbedtls_pk_rsa( rsa)); User Manual CFR0012 Revision 2.2 183 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide // Initialize PK RSA_ALT context ret = mbedtls_pk_setup_rsa_alt(&alt, (void *)raw, crypto_sample_rsa_decrypt_func, crypto_sample_rsa_sign_func, crypto_sample_rsa_key_len_func); // Encrypt message (including padding if relevant). ret = mbedtls_pk_encrypt(&rsa, msg, 50, cipher, &cipher_len, 1000, rnd_std_rand, NULL); // Decrypt message (including padding if relevant). ret = mbedtls_pk_decrypt(&alt, cipher, cipher_len, test, &test_len, 1000, rnd_std_rand, NULL); // Free the components of an RSA key. mbedtls_rsa_free(raw); // Free the components of a mbedtls_pk_context. mbedtls_pk_free(&rsa); mbedtls_pk_free(&alt); } The API details are as follows: int mbedtls_pk_setup_rsa_alt(mbedtls_pk_context *ctx, void *key, mbedtls_pk_rsa_alt_decrypt_func decrypt_func, mbedtls_pk_rsa_alt_sign_func sign_func, mbedtls_pk_rsa_alt_key_len_func key_len_func) Prototype int mbedtls_pk_setup_rsa_alt(mbedtls_pk_context *ctx, void *key, mbedtls_pk_rsa_alt_decrypt_func decrypt_func, mbedtls_pk_rsa_alt_sign_func sign_func, mbedtls_pk_rsa_alt_key_len_func key_len_func) Description Initialize an RSA-alt context. Parameters ctx: Context to initialize. It must not have been set up yet (type MBEDTLS_PK_NONE). key: RSA key pointer. decrypt_func: Decryption function. sign_func: Signing function. key_len_func: Function returning key length in bytes. Return values 0 on success, or MBEDTLS_ERR_PK_BAD_INPUT_DATA if the context was not already initialized as RSA_ALT. 7. The code example shows how to check if a public and private pair of keys matches. int crypto_sample_pk_check_pair(char *title, char *pub_file, char *prv_file, int result) { mbedtls_pk_context pub, prv, alt; // Initialize a mbedtls_pk_context. mbedtls_pk_init(&pub); mbedtls_pk_init(&prv); // Parse a public key in PEM or DER format. ret = mbedtls_pk_parse_public_key(&pub, (const unsigned char *)pub_file, (strlen(pub_file)+1)); // Parse a private key in PEM or DER format. ret = mbedtls_pk_parse_key(&prv, (const unsigned char *)prv_file, (strlen(prv_file)+1), NULL, 0); User Manual CFR0012 Revision 2.2 184 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide // Check if a public-private pair of keys matches. ret = mbedtls_pk_check_pair(&pub, &prv); mbedtls_pk_free(&pub); mbedtls_pk_free(&prv); } The API details are as follows: int mbedtls_pk_parse_public_key(mbedtls_pk_context *ctx, const unsigned char *key, size_t keylen) Prototype int mbedtls_pk_parse_public_key(mbedtls_pk_context *ctx, const unsigned char *key, size_t keylen) Description Parse a public key in PEM or DER format. Parameters ctx: The PK context to fill. It must have been initialized but not set up. key: Input buffer to parse. The buffer must contain the input exactly, with no extra trailing material. For PEM, the buffer must contain a null-terminated string. keylen: Size of key in bytes. For PEM data, this includes the terminating null byte, so keylen must be equal to strlen(key) + 1. Return values 0 if successful, or a specific PK or PEM error code int mbedtls_pk_parse_key(mbedtls_pk_context *ctx, const unsigned char *key, size_t keylen, const unsigned char *pwd, size_t pwdlen) Prototype int mbedtls_pk_parse_key(mbedtls_pk_context *ctx, const unsigned char *key, size_t keylen, const unsigned char *pwd, size_t pwdlen) Description Parse a private key in PEM or DER format. Parameters ctx: The PK context to fill. It must have been initialized but not set up. key: Input buffer to parse. The buffer must contain the input exactly, with no extra trailing material. For PEM, the buffer must contain a null-terminated string. keylen: Size of key in bytes. For PEM data, this includes the terminating null byte, so keylen must be equal to strlen(key) + 1. pwd: Optional password for decryption. Pass NULL if expecting a nonencrypted key. Pass a string of pwdlen bytes if expecting an encrypted key; a non-encrypted key will also be accepted. The empty password is not supported. pwdlen: Size of the password in bytes. Ignored if pwd is NULL. Return values 0 if successful, or a specific PK or PEM error code int mbedtls_pk_check_pair(const mbedtls_pk_context *pub, const mbedtls_pk_context *prv) Prototype int mbedtls_pk_check_pair(const mbedtls_pk_context *pub, const mbedtls_pk_context *prv) Description Check if a public-private pair of keys matches. User Manual CFR0012 Revision 2.2 185 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide Parameters pub: Context holding a public key. prv: Context holding a private (and public) key. Return values 0 on success or MBEDTLS_ERR_PK_BAD_INPUT_DATA 6.11 Crypto Algorithms Generic Cipher Wrapper The Generic cipher wrapper sample application demonstrates common use cases of a generic cipher wrapper API of the "mbedTLS" library that is included in the DA16200 SDK. The generic cipher wrapper API is the same as what the "mbedTLS" library provides. This section describes how the Generic cipher wrapper sample application is built and works. 6.11.1 How to Run 1. Open the workspace for the Crypto Algorithms for Generic Cipher Wrapper application as follows: .\sample\Crypto\Crypto_Cipher\build\DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. The example application explains how to use the generic cipher wrapper function. * AES-128-ECB(enc, dec): passed * AES-192-ECB(enc, dec): passed * AES-256-ECB(enc, dec): passed * AES-128-CBC(enc, dec): passed * AES-192-CBC(enc, dec): passed * AES-256-CBC(enc, dec): passed * AES-128-CFB128(enc, dec): passed * AES-192-CFB128(enc, dec): passed * AES-256-CFB128(enc, dec): passed * AES-128-CTR(enc, dec): passed * AES-192-CTR(enc, dec): passed * AES-256-CTR(enc, dec): passed * AES-128-GCM(enc, dec): passed * AES-192-GCM(enc, dec): passed * AES-256-GCM(enc, dec): passed * DES-CBC(enc, dec): passed * DES-EDE-CBC(enc, dec): passed * DES-EDE3-CBC(enc, dec): passed * ARC4-128(enc, dec): passed * AES-128-CCM(enc, dec): passed * AES-192-CCM(enc, dec): passed * AES-256-CCM(enc, dec): passed 6.11.2 Application Initialization The DA16200 SDK provides an "mbedTLS" library. This library helps with an easy implementation of the User Application. The generic cipher wrapper contains an abstraction interface for use with the cipher primitives that the library provides. It provides a common interface to all the available cipher operations. void crypto_sample_cipher(ULONG arg) { crypto_sample_cipher_wrapper(); } 6.11.3 How Generic Cipher Wrapper is Used This example describes how to encrypt and decrypt with generic cipher wrapper functions. int crypto_sample_cipher_wrapper() User Manual CFR0012 Revision 2.2 186 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide { mbedtls_cipher_context_t *cipher_ctx; mbedtls_cipher_type_t cipher_type; mode} pairs. mbedtls_cipher_info_t *cipherinfo; mbedtls_cipher_mode_t cipher_mode; // Generic cihper context. // Supported {cipher type, cipher // Cipher information. // Cipher mode. for (cipher_type = MBEDTLS_CIPHER_AES_128_ECB ; cipher_type <= MBEDTLS_CIPHER_CAMELLIA_256_CCM ; cipher_type++) { flag_pass = FALSE; // Initialize a cipher_context as NONE. mbedtls_cipher_init(cipher_ctx); // Retrieve the cipher-information structure associated with the given cipher type. cipherinfo = (mbedtls_cipher_info_t *)mbedtls_cipher_info_from_type(cipher_type); // Initialize and fills the cipher-context structure with the appropriate values. mbedtls_cipher_setup(cipher_ctx, cipherinfo); // Return the key length of the cipher. cipher_keylen = mbedtls_cipher_get_key_bitlen(cipher_ctx); // Return the mode of operation for the cipher. cipher_mode = mbedtls_cipher_get_cipher_mode(cipher_ctx); // Return the size of the IV or nonce of the cipher, in Bytes. cipher_ivlen = mbedtls_cipher_get_iv_size(cipher_ctx); // Return the block size of the given cipher. cipher_blksiz = mbedtls_cipher_get_block_size(cipher_ctx); // Return the name of the given cipher as a string. cipher_name = (char *)mbedtls_cipher_get_name(cipher_ctx); PRINTF("* %s", cipher_name); PRINTF("(enc, "); if (cipher_adlen == 0) { // No CCM or GCM // Set the key to use with the given context. cipher_status = mbedtls_cipher_setkey(cipher_ctx, cipher_key, cipher_keylen, MBEDTLS_ENCRYPT); // Set the initialization vector (IV) or nonce. cipher_status = mbedtls_cipher_set_iv(cipher_ctx, cipher_iv, cipher_ivlen); // Reset the cipher state. cipher_status = mbedtls_cipher_reset(cipher_ctx); // Encrypt or decrypt using the given cipher context. cipher_status = mbedtls_cipher_update(cipher_ctx, plain_in, plain_inlen, User Manual CFR0012 Revision 2.2 187 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide ciphertext, &ciphertext_len); // Finish the operation. cipher_status = mbedtls_cipher_finish(cipher_ctx, &(ciphertext[ciphertext_len]), &ciphertext_finlen); } else { // Set the key to use with the given context. cipher_status = mbedtls_cipher_setkey(cipher_ctx, cipher_key, cipher_keylen, MBEDTLS_ENCRYPT); // Perform autenticated encryption (AEAD). cipher_status = mbedtls_cipher_auth_encrypt(cipher_ctx, cipher_iv, cipher_ivlen, cipher_ad, cipher_adlen, plain_in, plain_inlen, ciphertext, &ciphertext_len, cipher_tag, cipher_taglen); } PRINTF("dec): "); if (cipher_adlen == 0) { // No CCM or GCM // Set the key to use with the given context. cipher_status = mbedtls_cipher_setkey(cipher_ctx, cipher_key, cipher_keylen, MBEDTLS_DECRYPT); // Set the initialization vector (IV) or nonce. cipher_status = mbedtls_cipher_set_iv(cipher_ctx, cipher_iv, cipher_ivlen); // Reset the cipher state. cipher_status = mbedtls_cipher_reset(cipher_ctx); // Encrypt or decrypt using the given cipher context. cipher_status = mbedtls_cipher_update(cipher_ctx, ciphertext, (ciphertext_len + ciphertext_finlen), plain_out, &plain_outlen); // Finish the operation. cipher_status = mbedtls_cipher_finish(cipher_ctx, &(plain_out[plain_outlen]), &plain_finlen); } else { // Set the key to use with the given context. cipher_status = mbedtls_cipher_setkey(cipher_ctx, cipher_key, cipher_keylen, MBEDTLS_DECRYPT); // Perform autenticated decryption (AEAD). cipher_status = mbedtls_cipher_auth_decrypt(cipher_ctx, cipher_iv, cipher_ivlen, cipher_ad, cipher_adlen, ciphertext, ciphertext_len, plain_out, &plain_outlen, cipher_tag, cipher_taglen); } // Free and clear the cipher-specific context of ctx. User Manual CFR0012 Revision 2.2 188 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide mbedtls_cipher_free(cipher_ctx); } } The API details are as follows: void mbedtls_cipher_init(mbedtls_cipher_context_t *ctx) Prototype void mbedtls_cipher_init(mbedtls_cipher_context_t *ctx) Description This function initializes a cipher_context as NONE. Parameters ctx: The context to be initialized. This must not be NULL. Return values None. void mbedtls_cipher_free(mbedtls_cipher_context_t *ctx) Prototype void mbedtls_cipher_free(mbedtls_cipher_context_t *ctx) Description This function frees and clears the cipher-specific context of ctx. Freeing ctx itself remains the responsibility of the caller. Parameters ctx: The context to be freed. If this is NULL, the function has no effect, otherwise this must point to an initialized context. Return values None. const mbedtls_cipher_info_t* mbedtls_cipher_info_from_type(const mbedtls_cipher_type_t cipher_type) Prototype Const mbedtls_cipher_info_t* mbedtls_cipher_info_from_type(const mbedtls_cipher_type_t cipher_type) Description This function retrieves the cipher-information structure associated with the given cipher type. Parameters cipher_type: Type of the cipher to search for. Return values The cipher information structure associated with the given cipher_type. NULL if the associated cipher information is not found. int mbedtls_cipher_setup(mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info) Prototype int mbedtls_cipher_setup(mbedtls_cipher_context_t *ctx, const mbedtls_cipher_info_t *cipher_info) Description This function initializes and fills the cipher-context structure with the appropriate values. It also clears the structure. Parameters ctx: The context to initialize. This must be initialized. cipher_info: The cipher to use. Return values 0 on success. MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on parameter-verification failure. MBEDTLS_ERR_CIPHER_ALLOC_FAILED if allocation of the cipher-specific context fails. static int mbedtls_cipher_get_key_bitlen(const mbedtls_cipher_context_t *ctx) Prototype static int mbedtls_cipher_get_key_bitlen(const mbedtls_cipher_context_t *ctx) Description This function returns the key length of the cipher. Parameters ctx: The context of the cipher. This must be initialized. Return values The key length of the cipher in bits. User Manual CFR0012 Revision 2.2 189 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide MBEDTLS_KEY_LENGTH_NONE if ctx has not been initialized. static mbedtls_cipher_mode_t mbedtls_cipher_get_cipher_mode(const mbedtls_cipher_context_t *ctx) Prototype static mbedtls_cipher_mode_t mbedtls_cipher_get_cipher_mode(const mbedtls_cipher_context_t *ctx) Description This function returns the mode of operation for the cipher. Parameters ctx: The context of the cipher. This must be initialized. Return values The mode of operation. MBEDTLS_MODE_NONE if ctx has not been initialized. static int mbedtls_cipher_get_iv_size(const mbedtls_cipher_context_t *ctx) Prototype static int mbedtls_cipher_get_iv_size(const mbedtls_cipher_context_t *ctx) Description This function returns the size of the IV or nonce of the cipher, in Bytes. Parameters ctx: The context of the cipher. This must be initialized. Return values The recommended IV size if no IV has been set. 0 for ciphers not using an IV or a nonce. The actual size if an IV has been set. static unsigned int mbedtls_cipher_get_block_size(const mbedtls_cipher_context_t *ctx) Prototype static unsigned int mbedtls_cipher_get_block_size(const mbedtls_cipher_context_t *ctx) Description This function returns the block size of the given cipher. Parameters ctx: The context of the cipher. This must be initialized. Return values The block size of the underlying cipher. 0 if ctx has not been initialized. static const char* mbedtls_cipher_get_name(const mbedtls_cipher_context_t *ctx) Prototype static const char* mbedtls_cipher_get_name(const mbedtls_cipher_context_t *ctx) Description This function returns the name of the given cipher as a string. Parameters ctx: The context of the cipher. This must be initialized. Return values The name of the cipher. NULL if ctx is not initialized. int mbedtls_cipher_setkey(mbedtls_cipher_context_t *ctx, const unsigned char *key, int key_bitlen, const mbedtls_operation_t operation) Prototype int mbedtls_cipher_setkey(mbedtls_cipher_context_t *ctx, const unsigned char *key, int key_bitlen, const mbedtls_operation_t operation) Description This function sets the key to use with the given context. Parameters ctx: The generic cipher context. This must be initialized and bound to a cipher information structure. key: The key to use. This must be a readable buffer of at least key_bitlen Bits. key_bitlen: The key length to use, in Bits. User Manual CFR0012 Revision 2.2 190 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide operation: The operation that the key will be used for: MBEDTLS_ENCRYPT or MBEDTLS_DECRYPT. Return values 0 on success. MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on parameter-verification failure. A cipher-specific error code on failure. int mbedtls_cipher_set_iv(mbedtls_cipher_context_t *ctx, const unsigned char *iv, size_t iv_len) Prototype int mbedtls_cipher_set_iv(mbedtls_cipher_context_t *ctx, const unsigned char *iv, size_t iv_len) Description This function sets the initialization vector (IV) or nonce. Parameters ctx: The generic cipher context. This must be initialized and bound to a cipher information structure. iv: The IV to use, or NONCE_COUNTER for CTR-mode ciphers. This must be a readable buffer of at least iv_len Bytes. iv_len: The IV length for ciphers with variable-size IV. This parameter is discarded by ciphers with fixed-size IV. Return values 0 on success. MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on parameter-verification failure. int mbedtls_cipher_reset(mbedtls_cipher_context_t *ctx) Prototype int mbedtls_cipher_reset(mbedtls_cipher_context_t *ctx) Description This function resets the cipher state. Parameters ctx: The generic cipher context. This must be initialized. Return values 0 on success. MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on parameter-verification failure. int mbedtls_cipher_update(mbedtls_cipher_context_t *ctx, const unsigned char *input, size_t ilen, unsigned char *output, size_t *olen) Prototype int mbedtls_cipher_update(mbedtls_cipher_context_t *ctx, const unsigned char *input, size_t ilen, unsigned char *output, size_t *olen) Description The generic cipher update function. It encrypts or decrypts using the given cipher context. Writes as many block-sized blocks of data as possible to output. Any data that cannot be written immediately is either added to the next block or flushed when mbedtls_cipher_finish() is called. Exception: For MBEDTLS_MODE_ECB, expects a single block in size. For example, 16 Bytes for AES. Parameters ctx: The generic cipher context. This must be initialized and bound to a key. input: The buffer holding the input data. This must be a readable buffer of at least ilen Bytes. ilen: The length of the input data. output: The buffer for the output data. This must be able to hold at least ilen + block_size. This must not be the same buffer as input. olen: The length of the output data, to be updated with the actual number of Bytes written. This must not be NULL. Return values 0 on success. MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on parameter-verification failure. User Manual CFR0012 Revision 2.2 191 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE on an unsupported mode for a cipher. A cipher-specific error code on failure. int mbedtls_cipher_finish(mbedtls_cipher_context_t *ctx, unsigned char *output, size_t *olen) Prototype int mbedtls_cipher_finish(mbedtls_cipher_context_t *ctx, unsigned char *output, size_t *olen) Description The generic cipher finalization function. If data still needs to be flushed from an incomplete block, the data contained in it is padded to the size of the last block and written to the output buffer. Parameters ctx: The generic cipher context. This must be initialized and bound to a key. output: The buffer to write data to. This needs to be a writable buffer of at least block_size Bytes. olen: The length of the data written to the output buffer. This may not be NULL. Return values 0 on success. MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on parameter-verification failure. MBEDTLS_ERR_CIPHER_FULL_BLOCK_EXPECTED on decryption expecting a full block but not receiving one. MBEDTLS_ERR_CIPHER_INVALID_PADDING on invalid padding while decrypting. A cipher-specific error code on failure. int mbedtls_cipher_auth_encrypt(mbedtls_cipher_context_t *ctx, const unsigned char *iv, size_t iv_len, const unsigned char *ad, size_t ad_len, const unsigned char *input, size_t ilen, unsigned char *output, size_t *olen, unsigned char *tag, size_t tag_len) Prototype int mbedtls_cipher_auth_encrypt(mbedtls_cipher_context_t *ctx, const unsigned char *iv, size_t iv_len, const unsigned char *ad, size_t ad_len, const unsigned char *input, size_t ilen, unsigned char *output, size_t *olen, unsigned char *tag, size_t tag_len) Description The generic authenticated encryption (AEAD) function. Parameters ctx: The generic cipher context. This must be initialized and bound to a key. iv: The IV to use, or NONCE_COUNTER for CTR-mode ciphers. This must be a readable buffer of at least iv_len Bytes. iv_len: The IV length for ciphers with variable-size IV. This parameter is discarded by ciphers with fixed-size IV. ad: The additional data to authenticate. This must be a readable buffer of at least ad_len Bytes. ad_len: The length of ad. input: The buffer holding the input data. This must be a readable buffer of at least ilen Bytes. ilen: The length of the input data. output: The buffer for the output data. This must be able to hold at least ilen Bytes. olen: The length of the output data, to be updated with the actual number of Bytes written. This must not be NULL. User Manual CFR0012 Revision 2.2 192 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide tag: The buffer for the authentication tag. This must be a writable buffer of at least tag_len Bytes. tag_len: The desired length of the authentication tag. Return values 0 on success. MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on parameter-verification failure. A cipher-specific error code on failure. int mbedtls_cipher_auth_decrypt(mbedtls_cipher_context_t *ctx, const unsigned char *iv, size_t iv_len, const unsigned char *ad, size_t ad_len, const unsigned char *input, size_t ilen, unsigned char *output, size_t *olen, const unsigned char *tag, size_t tag_len) Prototype int mbedtls_cipher_auth_decrypt(mbedtls_cipher_context_t *ctx, const unsigned char *iv, size_t iv_len, const unsigned char *ad, size_t ad_len, const unsigned char *input, size_t ilen, unsigned char *output, size_t *olen, const unsigned char *tag, size_t tag_len) Description The generic authenticated decryption (AEAD) function. Parameters ctx: The generic cipher context. This must be initialized and bound to a key. iv: The IV to use, or NONCE_COUNTER for CTR-mode ciphers. This must be a readable buffer of at least iv_len Bytes. iv_len: The IV length for ciphers with variable-size IV. This parameter is discarded by ciphers with fixed-size IV. ad: The additional data to be authenticated. This must be a readable buffer of at least ad_len Bytes. ad_len: The length of ad. input: The buffer holding the input data. This must be a readable buffer of at least ilen Bytes. ilen: The length of the input data. output: The buffer for the output data. This must be able to hold at least ilen Bytes. olen: The length of the output data, to be updated with the actual number of Bytes written. This must not be NULL. tag: The buffer holding the authentication tag. This must be a readable buffer of at least tag_len Bytes. tag_len: The length of the authentication tag. Return values 0 on success. MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA on parameter-verification failure. MBEDTLS_ERR_CIPHER_AUTH_FAILED if data is not authentic. A cipher-specific error code on failure. User Manual CFR0012 Revision 2.2 193 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 7 Peripheral Examples 7.1 UART Along with a UART0 interface for the debug console, the DA16200 SDK has a UART1 or UART2 interface to communicate with an external MCU. GPIOA[4] and GPIOA[5] are dedicated to this interface. 7.1.1 How to Run 1. Open the workspace for the UART sample application as follows: ~/SDK/sample/Peripheral/UART1/build/DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. 3. The start log message will be shown in the console terminal and UART1 terminal. 4. To test with UART1, input test data (hexa or ascii) on the UART1 terminal and press the Enter key to send data to DA16200. Then the console terminal shows the received data in hexadecimal and sends the message "- Data receiving OK..." to UART1. a. UART1 terminal b. Console terminal 7.1.2 Application Initialization This is an example of a user application to initialize and communicate between the DA16200 and a MCU that is connected through the UART1 interface. Function user_uart1_init() initializes the UART1 H/W resource and then uart1_monitor_sample() is run to communicate with the host through the UART1 interface. ~/SDK/sample/Peripheral/UART1/src/uart1_sample.c /* Local static variables */ static int sample_uart_idx = UART_UNIT_1; // UART_UNIT_1, UART_UNIT_2 /* * For Customer's configuration for UART devices * * "user_UART_config_info" data is located in /SDK/customer/src/user_uart.c. * * This data is temporay for sample application. */ static uart_info_t sample_UART_config_info = { UART_BAUDRATE_115200, /* baud */ UART_DATABITS_8, /* bits */ UART_PARITY_NONE, /* parity */ UART_STOPBITS_1, /* stopbit */ UART_FLOWCTL_OFF /* flow control */ }; User Manual CFR0012 Revision 2.2 194 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide void run_uart1_sample(UINT32 arg) { int status; /* Set UART configuration */ status = set_user_UART_conf(sample_uart_idx, &sample_UART_config_info, FALSE); if (status != TX_SUCCESS) { PRINTF("[%S] Error to configure for UART1 !!!\n", __func__); return; } /* Initialize UART device */ status = UART_init(sample_uart_idx); if (status != TX_SUCCESS) { PRINTF("Error to initialize UART1 with sample_UART_config !!!\n"); return; } /* Start UART monitor */ uart1_sample(); } Function uart1_sample() invokes function get_data_from_uart1() repeatedly to read data from UART1. Customer/Developer can enable/disable the UART echo function by setting "echo_enable". static void uart1_sample(void) { int i; char *init_str = "- Start UART1 communicate module ...\r\n"; char *rx_buf = NULL; char *tx_buf = "\r\n- Data receiving OK...\r\n"; int tx_len; /* Print-out test string to console and to UART1 device */ PRINTF((const char *)init_str); // For Console puts_UART(sample_uart_idx, init_str, strlen((const char *)init_str)); UART1 // for echo_enable = TRUE; rx_buf = malloc(USER_UART1_BUF_SZ); while (1) { memset(rx_buf, 0, USER_UART1_BUF_SZ); /* Get on byte from uart1 comm port */ get_data_from_uart1(rx_buf); ... ... 7.1.3 Data Read / Write Use getchar_UART() to read a charactor from UART1 or UART2. This example shows how to read data from UART device until meets characters `\n' or `\r'. Customer/Developer can modify this function for customized application opeartion. #define USER_DELIMITER_0 '\0' User Manual CFR0012 Revision 2.2 195 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide #define USER_DELIMITER_1 '\n' #define USER_DELIMITER_2 '\r' static void get_data_from_uart1(char *buf) { char ch = 0; int i = 0; while (1) { /* Get on byte from uart1 comm port */ ch = getchar_UART(sample_uart_idx, TX_WAIT_FOREVER); if (ch == NULL) { tx_thread_sleep(10); continue; } if (echo_enable == TRUE) { puts_UART(sample_uart_idx, &ch, sizeof(char)); // echo } /* check data length */ if (i >= (USER_UART1_BUF_SZ - 1)) { i = USER_UART1_BUF_SZ - 2; } if (ch == USER_DELIMITER_1 || ch == USER_DELIMITER_2) { buf[i++] = USER_DELIMITER_0; break; } else { buf[i++] = ch; } } } And also this example shows how to send data to UART1 using by puts_UART() API. ~/SDK/src/common/inc/common_uart.h /** **************************************************************************************** * @brief Put character string to UART device * @param[in] uart_idx Index value of UART interface (UART_UNIT_1, UART_UNIT_2) * @param[in] *data Text string to write * @param[in] len Write length * @return None **************************************************************************************** */ void puts_UART(int uart_idx, char *data, int data_len); User Manual CFR0012 Revision 2.2 196 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 7.2 GPIO This application shows how to read/write the GPIO port and use the GPIO interrupt. 7.2.1 How to Run 1. Open the workspace for the GPIO sample application as follows: ~/SDK/sample/Peripheral/GPIO/build/DA16xxx.eww 2. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. 3. The status of GPIOA[0] and GPIOA[1] is printed every 1 second. GPIOA[0] output low, GPIOA[4] output low, GPIOA[1] input low GPIOA[0] output high, GPIOA[4] output high, GPIOA[1] input low GPIOA[0] output low, GPIOA[4] output low, GPIOA[1] input low 7.2.2 Operation 1. Create and initialize a GPIO handle. HANDLE gpio; gpio = GPIO_CREATE(GPIO_UNIT_0); GPIO_INIT(gpio); 2. Set pin multiplexing. /* AMUX to GPIOA[1:0] */ _da16x_io_pinmux(PIN_AMUX, AMUX_GPIO); /* BMUX to GPIOA[3:2] */ _da16x_io_pinmux(PIN_BMUX, BMUX_GPIO); /* CMUX to GPIOA[5:4] */ _da16x_io_pinmux(PIN_CMUX, CMUX_GPIO); 3. Set GPIOA[0], GPIOA[4] as output mode and GPIOA[1] as input mode. /* GPIOA[0],GPIOA[4] output high low toggle */ pin = GPIO_PIN0 | GPIO_PIN4; GPIO_IOCTL(gpio, GPIO_SET_OUTPUT, &pin); /* GPIOA[1] input */ pin = GPIO_PIN1; GPIO_IOCTL(gpio, GPIO_SET_INPUT, &pin); 4. Set GPIOA[2] as an interrupt source with active low and register a callback function. /* GPIOA[2] interrupt active low */ pin = GPIO_PIN2; GPIO_IOCTL(gpio, GPIO_SET_INPUT, &pin); GPIO_IOCTL(gpio, GPIO_GET_INTR_MODE, &ioctldata[0]); ioctldata[0] |= pin; /* interrupt type 1: edge, 0: level*/ ioctldata[1] &= ~pin; /* interrupt pol 1: high active, 0: low active */ GPIO_IOCTL(gpio, GPIO_SET_INTR_MODE, &ioctldata[0]); /* register callback function */ ioctldata[0] = pin; ioctldata[1] = (UINT32)gpio_callback; ioctldata[2] = (UINT32)2; GPIO_IOCTL(gpio, GPIO_SET_CALLACK, ioctldata); /* interrupt pin */ /* callback function */ /* param data */ 5. Set GPIOA[3] as an interrupt source with active high and register a callback function. /* GPIOA[3] interrupt active high */ pin = GPIO_PIN3; GPIO_IOCTL(gpio, GPIO_SET_INPUT, &pin); User Manual CFR0012 Revision 2.2 197 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide GPIO_IOCTL(gpio, GPIO_GET_INTR_MODE, &ioctldata[0]); ioctldata[0] |= pin; /* interrupt type 1: edge, 0: level*/ ioctldata[1] |= pin; /* interrupt pol 1: high active, 0: low active */ GPIO_IOCTL(gpio, GPIO_SET_INTR_MODE, &ioctldata[0]); /* register callback function */ ioctldata[0] = pin; ioctldata[1] = (UINT32)gpio_callback; ioctldata[2] = (UINT32)3; GPIO_IOCTL(gpio, GPIO_SET_CALLACK, ioctldata); /* interrupt pin */ /* callback function */ /* param data */ 6. Enable the interrupt for GPIOA[3:2]. If GPIOA[3:2] is set, then the callback function will be invoked. /* enable GPIOA[3:2] interrupt */ pin = GPIO_PIN2 | GPIO_PIN3; GPIO_IOCTL(gpio, GPIO_SET_INTR_ENABLE, &pin); 7. Write GPIOA[0], GPIOA[4] and read GPIOA[1]. /* GPIOA[0],GPIOA[4] to high */ write_data = GPIO_PIN0 | GPIO_PIN4; GPIO_WRITE(gpio, GPIO_PIN0 | GPIO_PIN4, &write_data, sizeof(UINT16)); GPIO_READ(gpio, GPIO_PIN1, &read_data, sizeof(UINT16)); 7.3 GPIO Retention This application shows how to use GPIO retention. If the GPIO pin is set to retention high, it is kept in the high state during the sleep period. If the GPIO pin is set to retention low, it is kept in the low state during the sleep period. 7.3.1 How to Run 1. Open the workspace for the GPIO Retention sample application as follows: ~/SDK/sample/Peripheral/GPIO_Retention/build/DA16xxx.eww 2. Build the main project, download the image to your DA16200 EVB and reboot. 3. Toggle switch 13 (SW13). 4. Use an oscilloscope to check that the GPIOA [10: 8] and GPIOC [7] keep their PIN states. 7.3.2 Operation 1. Set pin multiplexing. /* * 1. Set to GPIOA[11:8], GPIOC[8:6] * 2. Need be written to "config_pin_mux" function. */ _da16x_io_pinmux(PIN_EMUX, EMUX_GPIO); _da16x_io_pinmux(PIN_FMUX, FMUX_GPIO); _da16x_io_pinmux(PIN_UMUX, UMUX_GPIO); 2. Set GPIO Retention Config. /* Set GPIOA[9:8] to retention high */ _GPIO_RETAIN_HIGH(GPIO_UNIT_A, GPIO_PIN8 | GPIO_PIN9); /* Set GPIOA[10] to retention low */ _GPIO_RETAIN_LOW(GPIO_UNIT_A, GPIO_PIN10); /* Set GPIOC[7] to retention high */ _GPIO_RETAIN_HIGH(GPIO_UNIT_C, GPIO_PIN7); 3. Power Down. User Manual CFR0012 Revision 2.2 198 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide char * _argv[3] = {"down", "pri", "10"}; cmd_power_down_config(3, _argv); /* Set GPIOC[7] to retention high */ _GPIO_RETAIN_HIGH(GPIO_UNIT_C, GPIO_PIN7); 7.4 I2C This section shows how to use the I2C interface. 7.4.1 How to Run 1. Open the workspace for the I2C. a. Path: .\sample\Peripheral\I2C\build\DA16xxx.eww b. The sample application code is written in the following source file: .\sample\Peripheral\I2C\src\i2c_sample.c 7.4.2 Operation 1. Hardware setup: a. Remove resistor R6 and R7. b. Connect the AT24C512 EEPROM with the DIALOG EVK. c. Connect each 1,2 K Pull-Up resistor with GPIOA0 and GPIOA1. GPIOA0= SDA, GPIOA1=SCL d. Run I2C example code. 2. i2c init. // GPIO Select for I2C working. GPIO1 = SCL, GPIO0= SDA Board_initialization();FC9K_CLOCK_SCGATE->Off_DAPB_I2CM = 0; FC9K_CLOCK_SCGATE->Off_DAPB_APBS = 0; // Create Handle for I2C Device I2C = DRV_I2C_CREATE(i2c_0); // Initialization I2C Device DRV_I2C_INIT(I2C); 3. i2c addr. // Set Address for Atmel eeprom AT24C512 addr = htoi(argv[2]); DRV_I2C_IOCTL(I2C, I2C_SET_CHIPADDR, &addr); 4. i2c clock. // Set Address for Atmel eeprom AT24C512 DRV_I2C_IOCTL(I2C, I2C_SET_CHIPADDR, &addr); 5. i2c write. // Data Random Write to EEPROM // Address = 0, Length = 4, Word Address Length = 2 // [Start] - [Device addr. W] - [1st word addr.] - [2nd word addr.] - [wdata0] ~ [wdata31] - [Stop] i2c_data[0] = AT_I2C_FIRST_WORD_ADDRESS; //Word Address to Write Data. 2 Bytes. refer at24c512 DataSheet i2c_data[1] = AT_I2C_SECOND_WORD_ADDRESS; //Word Address to Write Data. 2 Bytes. refer at24c512 DataSheet // Fill Ramp Data For (int I = 0 ; I < AT_I2C_DATA_LENGTH; i++) { i2c_data[i+AT_I2C_LENGTH_FOR_WORD_ADDRESS] = i; } User Manual CFR0012 Revision 2.2 199 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide status = DRV_I2C_WRITE(I2C, i2c_data, AT_I2C_DATA_LENGTH + AT_I2C_LENGTH_FOR_WORD_ADDRESS, 1, 0); // Handle, buffer, length, stop enable, dummy if (status != TRUE) PRINTF("ret : 0x%08x\r\n", status); 6. i2c read. // Data Random Read from EEPROM // Address = 0, Length = 4, Word Address Length = 2 // [Start] - [Device addr. W] - [1st word addr.] - [2nd word addr.] [Device addr. R] - [rdata0] ~ [rdata31] - [Stop] - [Start] - i2c_data_read[0] = AT_I2C_FIRST_WORD_ADDRESS;//Word Address to Write Data. 2 Bytes. refer at24c512 DataSheet i2c_data_read[1] = AT_I2C_SECOND_WORD_ADDRESS;//Word Address to Write Data. 2 Bytes. refer at24c512 DataSheet status = DRV_I2C_READ(I2C, i2c_data_read, AT_I2C_DATA_LENGTH, AT_I2C_LENGTH_FOR_WORD_ADDRESS, 0); // Handle, buffer, length, address length, dummy if (status != TRUE) PRINTF("ret : 0x%08x\r\n", status); //Check Data for (int i = 0; i < AT_I2C_DATA_LENGTH; i++) { if (i2c_data_read[i] != i2c_data[i + AT_I2C_LENGTH_FOR_WORD_ADDRESS]) { PRINTF(" %dth data is different W:0x%02x, R:0x%02x\r\n", i, i2c_data[i + AT_I2C_LENGTH_FOR_WORD_ADDRESS], i2c_data_read[i]); status = AT_I2C_ERROR_DATA_CHECK; } } if (status != AT_I2C_ERROR_DATA_CHECK) PRINTF("***** 32 Bytes Data Write and Read Success *****\r\n"); 7. i2c read_nostop. // Current Address Data Read from EEPROM // Length = 4, Word Address Length = 0 // [Start] -[Device addr. R] - [rdata0] ~ [rdata31] - [Stop] status = DRV_I2C_READ(I2C, i2c_data_read, 4, 0, 0); // Handle, buffer, length, address length, dummy if (status != TRUE) PRINTF("ret : 0x%08x\r\n", status); 7.5 I2S This section shows how to use the I2S interface. 7.5.1 How to Run 1. Open the workspace for the I2S. a. Path: .\sample\Peripheral\I2S\build\DA16xxx.eww b. The sample application code is written in the following source file: .\sample\Peripheral\I2S\src\i2s_sample.c User Manual CFR0012 Revision 2.2 200 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 7.5.2 User Thread The user thread of the I2S application is added as shown in the example below and will be executed by the system. SAMPLE_I2S should be a unique name to create a thread. The port number does not need to be set, because this is a non-network thread. [\src\application\sample_code\sample_apps.c] static const app_thread_info_t sample_apps_table[] = { { SAMPLE_I2S, run_i2s_sample, 2048, USER_PRI_APP(1), FALSE, FALSE, UNDEF_PORT, RUN_ALL_MODE }, }; 7.5.3 Operation 1. Create and initialize an I2S handle. HANDLE gi2shandle = NULL; I2S_HANDLER_TYPE *i2s; unsigned int mode = 0, data; FC9K_CLOCK_SCGATE->Off_DAPB_I2S = 0; FC9K_CLOCK_SCGATE->Off_DAPB_APBS = 0; gi2shandle = DRV_I2S_CREATE(I2S_0); i2s = (I2S_HANDLER_TYPE *) gi2shandle; if (!gi2shandle) return; /* Set I2S Output Mode */ if (DRV_I2S_INIT(gi2shandle, mode) == FALSE) return; 2. Set the internal DAC or the external DAC. // GPIO[3] - I2S_LRCK, GPIO[2] - I2S_SDO _da16x_io_pinmux(PIN_BMUX, BMUX_I2S); // GPIO[1] - I2S_MCLK, GPIO[0] - I2S_BCLK _da16x_io_pinmux(PIN_AMUX, AMUX_I2S); DRV_I2S_SET_CLOCK(gi2shandle, 1, 0); 3. Set additional configuration. data = TRUE; DRV_I2S_IOCTL(i2s,I2S_SET_STEREO, &data); /* Set Stereo Output Mode */ data = I2S_CFG_PCM_16; DRV_I2S_IOCTL(i2s,I2S_SET_PCM_RESOLUTION, &data); /* Set 16bit resolution Mode */ 4. Write and read data. DRV_I2S_WRITE (i2s, (unsigned int *)sinewave_pattern, 768, 0); // Wait Until I2S end while( (HW_REG_READ32_I2S(i2s->regmap->i2s_sr) & I2S_STT_BUSY) == I2S_STT_BUSY ); 7.6 PWM This section shows how to use PWM interface. 7.6.1 How to Run 1. Open the workspace for the PWM. a. Path: .\sample\Peripheral\PWM\build\DA16xxx.eww b. The sample application code is written in the following source file. .\sample\Peripheral\PWM\src\pwm_sample.c User Manual CFR0012 Revision 2.2 201 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 7.6.2 Operation 1. Hardware setup: a. Remove resistor R6~R9. b. Run the PWM example command. c. Get waveform from P7~P9 in connector J4. d. Compare the waveform with the PWM setting inside example code. 2. pwm setgpio. Board_Init(); FC9K_CLOCK_SCGATE->Off_CAPB_PWM = 0; gpio = GPIO_CREATE(GPIO_UNIT_A); GPIO_INIT(gpio); GPIO_SET_ALT_FUNC(gpio, GPIO_ALT_FUNC_PWM_OUT0, GPIO_ALT_FUNC_GPIO0); GPIO_SET_ALT_FUNC(gpio, GPIO_ALT_FUNC_PWM_OUT1, GPIO_ALT_FUNC_GPIO1); GPIO_SET_ALT_FUNC(gpio, GPIO_ALT_FUNC_PWM_OUT2, GPIO_ALT_FUNC_GPIO2); GPIO_SET_ALT_FUNC(gpio, GPIO_ALT_FUNC_PWM_OUT3, GPIO_ALT_FUNC_GPIO3); 3. pwm init. pwm[0] = DRV_PWM_CREATE(pwm_0); pwm[1] = DRV_PWM_CREATE(pwm_1); pwm[2] = DRV_PWM_CREATE(pwm_2); pwm[3] = DRV_PWM_CREATE(pwm_3); DRV_PWM_INIT(pwm[0]); DRV_PWM_INIT(pwm[1]); DRV_PWM_INIT(pwm[2]); DRV_PWM_INIT(pwm[3]); 4. pwm start_time. period = 10; // 10us duty_percent = 30; //30%, duration high 3us per 10us DRV_PWM_START(pwm[0], period, duty_percent, PWM_DRV_MODE_US); //PWM Start period = 20; // 20us duty_percent = 40; //40%, duration high 8us per 10us DRV_PWM_START(pwm[1], period, duty_percent, PWM_DRV_MODE_US); //PWM Start period = 40; // 40us duty_percent = 50; //50%, duration high 20us per 10us DRV_PWM_START(pwm[2], period, duty_percent, PWM_DRV_MODE_US); //PWM Start period = 80; // 80us duty_percent = 80; //80%, duration high 64us per 10us DRV_PWM_START(pwm[3], period, duty_percent, PWM_DRV_MODE_US); //PWM Start 5. pwm start_cycle. cycle = 2400-1; //2400 cycles(=30us @ 80MHz), cycle = value + 1 duty_cycle = 1680-1; //1680 cycles(=21us@80MHz, 70% Duty High), duty_cycle = value + 1 DRV_PWM_START(pwm[0], cycle, duty_cycle, PWM_DRV_MODE_CYC); //PWM Start cycle = 2400-1; //2400 cycles(=30us @ 80MHz), cycle = value + 1 duty_cycle = 1680-1; //1680 cycles(=21us@80MHz, 70% Duty High), 70% Duty High), duty_cycle = value + 1 DRV_PWM_START(pwm[1], cycle, duty_cycle, PWM_DRV_MODE_CYC); //PWM Start User Manual CFR0012 Revision 2.2 202 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide cycle = 2400-1; //2400 cycles(=30us @ 80MHz), cycle = value + 1 duty_cycle = 1680-1; //1680 cycles(=21us@80MHz, 70% Duty High), 70% Duty High), duty_cycle = value + 1 DRV_PWM_START(pwm[2], cycle, duty_cycle, PWM_DRV_MODE_CYC); //PWM Start cycle = 2400-1; //2400 cycles(=30us @ 80MHz), cycle = value + 1 duty_cycle = 1680-1; //1680 cycles(=21us@80MHz, 70% Duty High), 70% Duty High), duty_cycle = value + 1 DRV_PWM_START(pwm[3], cycle, duty_cycle, PWM_DRV_MODE_CYC); //PWM Start 6. pwm stop. DRV_PWM_STOP(pwm[0], 0); DRV_PWM_STOP(pwm[1], 0); DRV_PWM_STOP(pwm[2], 0); DRV_PWM_STOP(pwm[3], 0); 7.7 ADC This section shows how to use ADC interface. 7.7.1 How to Run 1. Open the workspace for the ADC: a. Path: .\sample\Peripheral\ADC\build\DA16xxx.eww. b. The sample application code is written in the following source file. .\sample\Peripheral\ADC\src\adc_sample.c 7.7.2 Operation 1. Hardware setup: a. Provide 0~1.3 V voltage to P7 ~ P9, in connector J4. b. Run the ADC example command and read the ADC value. c. Compare the value with the voltage supplied. 2. adc init. // Set PAD Mux. GPIO 0 (ADC_CH0), GPIO_1(ADC_CH1) _da16x_io_pinmux(PIN_AMUX, AMUX_AD12); FC9K_CLOCK_SCGATE->Off_DAPB_AuxA = 0; FC9K_CLOCK_SCGATE->Off_DAPB_APBS = 0; // Create Handle hadc = DRV_ADC_CREATE(FC9K_ADC_DEVICE_ID); // Initialization DRV_ADC_INIT(hadc, FC9K_ADC_NO_TIMESTAMP); 3. adc start. // Start. Set Sampling Frequency. 12B ADC Set to 200KHz DRV_ADC_START(hadc, FC9K_ADC_DIVIDER_12, 0); 4. adc enable. // Set ADC_0 to 12Bit ADC, ADC_1 to 12Bit ADC DRV_ADC_ENABLE_CHANNEL(hadc, FC9050_ADC_CH_0, FC9050_ADC_SEL_ADC_12, 0); DRV_ADC_ENABLE_CHANNEL(hadc, FC9050_ADC_CH_1, FC9050_ADC_SEL_ADC_12, 0); 5. adc dmaread. // Read 16ea ADC_0 Value. 12B ADC, Bit [15:4] is valid adc_data, [3:0] is zero DRV_ADC_READ_DMA(hadc, FC9050_ADC_CH_0, data12, FC9050_ADC_NUM_READ * 2, FC9050_ADC_TIMEOUT_DMA, 0); User Manual CFR0012 Revision 2.2 203 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide // Read 16ea ADC_1 Value DRV_ADC_READ_DMA(hadc, FC9050_ADC_CH_1, data16, FC9050_ADC_NUM_READ * 2, FC9050_ADC_TIMEOUT_DMA, 0); 6. adc read. // Read Current ADC_0 Value. Caution!! When read current adc value consequently, need delay at each read function bigger than Sampling Frequency DRV_ADC_READ(hadc, FC9050_ADC_CH_0, &data, 0); 7. adc close. // Close ADC DRV_ADC_CLOSE(hadc); User Manual CFR0012 Revision 2.2 204 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 7.8 SPI This section shows how the SPI loopback operation works. 7.8.1 How to Run 1. Open the workspace for the SPI sample application as follows: ~/SDK/sample/Peripheral/SPI/build/DA16xxx.eww 2. Connect the SPI master pins and SPI slave pins. 3. GPIOA[0] (SPI_MISO) - GPIOA[9] (E_SPI_DIO1) 4. GPIOA[1] (SPI_MOSI) - GPIOA[8] (E_SPI_DIO0) 5. GPIOA[2] (SPI_CSB) - GPIOA[6] (E_SPI_CSB) 6. GPIOA[3] (SPI_CLK) - GPIOA[7] (E_SPI_CLK) 7. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. 8. The SPI loopback communication works as shown in Figure 59. Figure 61: SPI Loopback Communication 7.8.2 Operation 1. Create an SPI handle and configure the interface. spi = SPI_CREATE(SPI_UNIT_0); if(spi != NULL ) { /* * SPI master initialization */ ioctldata[0] = (1*MBYTE) ; SPI_IOCTL(spi, SPI_SET_MAX_LENGTH, ioctldata ); _sys_clock_read( ioctldata, sizeof(UINT32) ); SPI_IOCTL(spi, SPI_SET_CORECLOCK, ioctldata ); ioctldata[0] = spi_clock * MHz; SPI_IOCTL(spi, SPI_SET_SPEED, ioctldata ); ioctldata[0] = SPI_TYPE_MOTOROLA_O0H0 ; SPI_IOCTL(spi, SPI_SET_FORMAT, ioctldata ); ioctldata[0] = SPI_DMA_MP0_BST(8) | SPI_DMA_MP0_IDLE(1) | SPI_DMA_MP0_HSIZE(XHSIZE_DWORD) | SPI_DMA_MP0_AI(SPI_ADDR_INCR) ; SPI_IOCTL(spi, SPI_SET_DMA_CFG, ioctldata); SPI_IOCTL(spi, SPI_SET_DMAMODE, NULL); ioctldata[0] = spi_cs; ioctldata[1] = 4; // 4-wire SPI_IOCTL( spi, SPI_SET_WIRE, (VOID *)ioctldata); SPI_INIT(spi); } 2. Set pin multiplexing as SPI master and SPI slave. User Manual CFR0012 Revision 2.2 205 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide // pinmux config for SPI Slave - GPIOA[3:0] _da16x_io_pinmux(PIN_AMUX, AMUX_SPIs); _da16x_io_pinmux(PIN_BMUX, BMUX_SPIs); // pinmux config for SPI Host - GPIOA[9:6] _da16x_io_pinmux(PIN_DMUX, DMUX_SPIm); _da17x_io_pinmux(PIN_EMUX, EMUX_SPIm); 3. Write data. tx_data[0] = (laddr >> 8) & 0xff; tx_data[1] = (laddr >> 0) & 0xff; tx_data[2] = (command & 0xff) | (common_addr_mode << 5) | (ref_len<<4)|((length>>8)&0xf); tx_data[3] = (length)&0xff; /* copy tx data */ DRIVER_MEMCPY(&(tx_data[4]), &data, sizeof(UINT32)); // Bus Lock : CSEL0 ioctldata[0] = TRUE; ioctldata[1] = OAL_SUSPEND; ioctldata[2] = SPI_CSEL_0; SPI_IOCTL(spi, SPI_SET_LOCK, (VOID *)ioctldata); ret = SPI_WRITE(spi, 1, tx_data, 8); // Bus Unlock ioctldata[0] = FALSE; ioctldata[1] = OAL_SUSPEND; ioctldata[2] = SPI_CSEL_0; SPI_IOCTL(spi, SPI_SET_LOCK, (VOID *)ioctldata); 4. Read data. tx_data[0] = (laddr >> 8) & 0xff; tx_data[1] = (laddr >> 0) & 0xff; tx_data[2] = command | (common_addr_mode << 5) | (ref_len<<4)|((len>>8)&0xf); tx_data[3] = (len)&0xff; // Bus Lock : CSEL0 ioctldata[0] = TRUE; ioctldata[1] = OAL_SUSPEND; ioctldata[2] = SPI_CSEL_0; SPI_IOCTL(spi, SPI_SET_LOCK, (VOID *)ioctldata); ret = SPI_WRITE_READ(spi, 1, tx_data, 4, rx_data, len); // Bus Unlock ioctldata[0] = FALSE; ioctldata[1] = OAL_SUSPEND; ioctldata[2] = SPI_CSEL_0; SPI_IOCTL(spi, SPI_SET_LOCK, (VOID *)ioctldata); 7.9 SDIO The DA16200 can be accessed with the SDIO interface. If the user wants to test it, then another host system is needed. 7.9.1 How to Run 1. Open the workspace for the SDIO slave. ~/SDK/sample/Peripheral/SDIO/build/DA16xxx.eww. User Manual CFR0012 Revision 2.2 206 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 2. The sample application code is written in the following source file: ~/SDK/sample/Peripheral/SDIO/src/sdio_sample.c GPIOA[9:4] needs to connect to the HOST system. GPIOA[9] - SDIO_D0, GPIOA[8] - SDIO_D1 GPIOA[7] - SDIO_D2, GPIOA[6] - SDIO_D3 GPIOA[5] - SDIO_CLK, GPIOA[4] - SDIO_CMD 3. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. 4. The sample runs as soon as the boot up is completed. [/DA16200] # sdio_slave start Now the sdio host can access the DA16200 [/DA16200] # Now the DA16200 is ready to receive an SDIO command. 7.9.2 Operation In DA16200, the loopback test between SD host and sdio_slave is not supported. Instead, in the sample code provided, SDIO is just waiting for a request from the host after initialization. /* GPIO configuration */ { /* SDIO Slave */ // GPIO[9] - SDIO_D0, GPIO[8] - SDIO_D1 _da16x_io_pinmux(PIN_EMUX, EMUX_SDs); // GPIO[5] - SDIO_CLK, GPIO[4] - SDIO_CMD _da16x_io_pinmux(PIN_CMUX, CMUX_SDs); // GPIO[7] - SDIO_D2, GPIO[6] - SDIO_D3 _da17x_io_pinmux(PIN_DMUX, DMUX_SDs); } // clock enable sdio_slave FC9K_CLOCK_SCGATE->Off_SSI_M3X1 = 0; FC9K_CLOCK_SCGATE->Off_SSI_SDIO = 0; SDIO_SLAVE_INIT(); sdio_slave_buf = HAL_MALLOC(1024); PRINTF("sdio_slave init buf %x\n", sdio_slave_buf); PRINTF("Now the host can access the DA16200 by SDIO\n"); 7.10 SD/eMMC This section shows how to use the SD/eMMC interface. 7.10.1 How to Run 1. Open the workspace for the SD_EMMC. ~/SDK/sample/Peripheral/SD_EMMC/build/DA16xxx.eww. 2. The sample application code is written in the following source file: ~/SDK/sample/Peripheral/SD_EMMC/src/sd_emmc_sample.c 3. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. 4. The sample runs as soon as the boot up is completed. [/DA16200] # emmc sample start fail / total 0 / 100 [/DA16200] # 5. If the SD card is not ready, then message "emmc_init fail" is returned. 6. Connect GPIOA[9:4] to the SD card socket as shown below. User Manual CFR0012 Revision 2.2 207 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide Figure 62: SDIO and SD/eMMC Connector a. GPIOA[9] - mSDeMMCIO_D0, GPIOA[8] - mSDeMMCIO_D1 b. GPIOA[7] - mSDeMMCIO_D2, GPIOA[6] - mSDeMMCIO_D3 c. GPIOA[5] - mSDeMMCIO_CLK, GPIOA[4] - mSDeMMCIO_CMD d. GPIOA[10] is not mandatory (for write protect function). 7.10.2 Operation This sample code shows how the eMMC host writes random data to a slave memory card and reads back the written data to check if that data matches. Function Emmc_verify() compares the written data with the data read from the SD memory card. The sector size of the SD memory card is 512 bytes. The "addr" variable value (210) in the code is just an example sector number in the SD memory card. void emmc_init() { ... FC9K_CLOCK_SCGATE->Off_SysC_HIF = 0; FC9050_SYSCLOCK->CLK_DIV_EMMC = EMMC_CLK_DIV_VAL; FC9050_SYSCLOCK->CLK_EN_SDeMMC = 0x01; // clock enable ... 1. Set pin multiplexing. /* * SDIO Master */ // GPIO[9] - mSDeMMCIO_D0, GPIO[8] - mSDeMMCIO_D1 _da16x_io_pinmux(PIN_EMUX, EMUX_SDm); // GPIO[5] - mSDeMMCIO_CLK, GPIO[4] - mSDeMMCIO_CMD _da16x_io_pinmux(PIN_CMUX, CMUX_SDm); // GPIO[7] - mSDeMMCIO_D2, GPIO[6] - mSDeMMCIO_D3 _da16x_io_pinmux(PIN_DMUX, DMUX_SDm); 2. Create and initialize an SD/eMMC handle. _emmc = EMMC_CREATE(); err = EMMC_INIT(_emmc); User Manual CFR0012 Revision 2.2 208 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 7.11 User SFLASH Read / Write Example 1. Open the workspace for the DTLS Server in the DPM sample application as follows: ~/SDK/sample/Peripheral/Sflash_API/build/DA16xxx.eww 2. The sample application code is written in the following source file: ~/SDK/sample/Peripheral/Sflash_API/src/sflash_sample.c 3. Build the DA16200 SDK, download the RTOS image to your DA16200 EVB and reboot. 4. After boot, the sample will start automatically. Figure 63: sflash Example Sample Test 7.11.1 User Thread The user thread of the sflash api sample application is defined as below and is executed by the system. SAMPLE_SFLASH should be a unique name in order to create a thread. This test is not related to network initialization and DPM mode. ~/SDK/sample/Peripheral/Sflash_API/src/sample_apps.c static const app_thread_info_t sample_apps_table[] = { { SAMPLE_SFLASH, user_sflash_test, 1024, USER_PRI_APP(1), FALSE, FALSE, UNDEF_PORT, RUN_ALL_MODE }, }; 7.11.2 Application Initialization The user_sflash_test function is run after the basic ThreadX initialization is complete. void user_sflash_test(ULONG arg) { PRINTF("\n- Test Serial-Flash Read/Write ...\n\n"); /* Test File-System on FC9K */ test_sflash_write(); OAL_MSLEEP(100); test_sflash_read(); } User Manual CFR0012 Revision 2.2 209 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide 7.11.3 Sflash Read and Write // user sflash APIs /* sflash user area available: - User area of 2MB sflash: 12KB (SFLASH_USER_AREA_START~) */ extern UINT user_sflash_read(UINT sflash_addr, VOID *rd_buf, UINT rd_size); sflash_addr: please see above user sflash area rd_buf: buffer to which data is copied rd_size: data size extern UINT user_sflash_write(UINT sflash_addr, UCHAR *wr_buf, UINT wr_size); sflash_addr: please see above user sflash area rd_buf: buffer from which data is copied to sflash_addr rd_size: data size ... void test_sflash_write(void) { UCHAR *wr_buf = TX_NULL; UINT wr_addr; #define #define SFLASH_WR_TEST_ADDR SFLASH_USER_AREA_START // write address TEST_WR_SIZE SF_SECTOR_SZ // 4K wr_buf = (UCHAR *)malloc(TEST_WR_SIZE); if (wr_buf == TX_NULL) { PRINTF("[%s] malloc fail ...\n", __func__); return; } memset(wr_buf, 0, TEST_WR_SIZE); for (int i = 0; i < TEST_WR_SIZE; i++) { wr_buf[i] = 0x41; // A } wr_addr = SFLASH_WR_TEST_ADDR; PRINTF("=== SFLASH Write Data ======================\n"); user_sflash_write(wr_addr, wr_buf, TEST_WR_SIZE); // this is the function to invoke to write data to sflash user area } void test_sflash_read(void) { UCHAR *rd_buf = TX_NULL; UINT rd_addr; UINT status; #define #define SFLASH_RD_TEST_ADDR SFLASH_USER_AREA_START TEST_RD_SIZE (1 * 1024) rd_buf = (UCHAR *)malloc(TEST_RD_SIZE); if (rd_buf == TX_NULL) { PRINTF("[%s] malloc fail ...\n", __func__); return; } User Manual CFR0012 Revision 2.2 210 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide memset(rd_buf, 0, TEST_RD_SIZE); rd_addr = SFLASH_RD_TEST_ADDR; status = user_sflash_read(rd_addr, (VOID *)rd_buf, TEST_RD_SIZE); // this is the function to invoke to read data from sflash user area if (status == TRUE) { hex_dump(rd_buf, 128); } free(rd_buf); } NOTE user_sflash_read/write is a blocking function. Take special care when you run this code under DPM mode enabled (sleep2 or sleep3 applications): when you invoke user_sflash_write( ), please make sure that you get the result before the DPM sleeping API is invoked. User Manual CFR0012 Revision 2.2 211 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide Appendix A Mosquitto 1.4.14 License Eclipse Distribution License 1.0 Copyright (c) 2007, Eclipse Foundation, Inc. and its licensors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Eclipse Foundation, Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ------------------------------------------------------------------------------------------------------ -------------------------------- User Manual CFR0012 Revision 2.2 212 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide Revision History Revision 2.2 2.1 Date 10-Mar-2021 15-Feb-2021 2.0 08-Dec-2020 1.9 14-Sep-2020 1.8 17-Aug-2020 1.7 12-Jun-2020 1.6 24-Apr-2020 1.5 30-Mar-2020 1.4 22-Nov-2019 1.3 21-Nov-2019 1.2 10-Nov-2019 1.1 30-Aug-19 1.0 03-Jul-2019 Description 5.4 SoftAP Provisioning Sample added Section 4.3.2, 4.4.2 Corrected minor typo. Section 4.8 Added sample description to Certificate and MCU FW update. Added Test DUT of each test cases. Modified and rearranged the document format. Added description of 4.6 HTTP server. Added Section 4.7 OTA FW Update. Moved section 2.8.2 How it Works. Small updates in various `Operation' sections. Added Section 1. How to start. Added HTTP Client and HTTP Server sections. Updated contents for Generic SDK v2.0.0. Finalized for publication. Technical review. Editorial review. Added the test log of TCP/UDP examples. Corrected commands of setting IP and Port in TCP example. Preliminary DRAFT Release. User Manual CFR0012 Revision 2.2 213 of 214 10-Mar-2021 © 2021 Dialog Semiconductor UM-WI-007 DA16200 Example Application Guide Status Definitions Status DRAFT APPROVED or unmarked Definition The content of this document is under review and subject to formal approval, which may result in modifications or additions. The content of this document has been approved for publication. Disclaimer Unless otherwise agreed in writing, the Dialog Semiconductor products (and any associated software) referred to in this document are not designed, authorized or warranted to be suitable for use in life support, life-critical or safety-critical systems or equipment, nor in applications where failure or malfunction of a Dialog Semiconductor product (or associated software) can reasonably be expected to result in personal injury, death or severe property or environmental damage. Dialog Semiconductor and its suppliers accept no liability for inclusion and/or use of Dialog Semiconductor products (and any associated software) in such equipment or applications and therefore such inclusion and/or use is at the customer's own risk. Information in this document is believed to be accurate and reliable. However, Dialog Semiconductor does not give any representations or warranties, express or implied, as to the accuracy or completeness of such information. Dialog Semiconductor furthermore takes no responsibility whatsoever for the content in this document if provided by any information source outside of Dialog Semiconductor. Dialog Semiconductor reserves the right to change without notice the information published in this document, including, without limitation, the specification and the design of the related semiconductor products, software and applications. Notwithstanding the foregoing, for any automotive grade version of the device, Dialog Semiconductor reserves the right to change the information published in this document, including, without limitation, the specification and the design of the related semiconductor products, software and applications, in accordance with its standard automotive change notification process. Applications, software, and semiconductor products described in this document are for illustrative purposes only. Dialog Semiconductor makes no representation or warranty that such applications, software and semiconductor products will be suitable for the specified use without further testing or modification. Unless otherwise agreed in writing, such testing or modification is the sole responsibility of the customer and Dialog Semiconductor excludes all liability in this respect. Nothing in this document may be construed as a license for customer to use the Dialog Semiconductor products, software and applications referred to in this document. Such license must be separately sought by customer with Dialog Semiconductor. All use of Dialog Semiconductor products, software and applications referred to in this document is subject to Dialog Semiconductor's Standard Terms and Conditions of Sale, available on the company website (www.dialog-semiconductor.com) unless otherwise stated. Dialog, Dialog Semiconductor and the Dialog logo are trademarks of Dialog Semiconductor Plc or its subsidiaries. All other product or service names and marks are the property of their respective owners. © 2021 Dialog Semiconductor. All rights reserved. Contacting Dialog Semiconductor United Kingdom (Headquarters) Dialog Semiconductor (UK) LTD Phone: +44 1793 757700 Germany Dialog Semiconductor GmbH Phone: +49 7021 805-0 The Netherlands Dialog Semiconductor B.V. Phone: +31 73 640 8822 Email: enquiry@diasemi.com North America Dialog Semiconductor Inc. Phone: +1 408 845 8500 Japan Dialog Semiconductor K. K. Phone: +81 3 5769 5100 Taiwan Dialog Semiconductor Taiwan Phone: +886 281 786 222 Web site: www.dialog-semiconductor.com Hong Kong Dialog Semiconductor Hong Kong Phone: +852 2607 4271 Korea Dialog Semiconductor Korea Phone: +82 2 3469 8200 User Manual Revision 2.2 CFR0012 214 of 214 China (Shenzhen) Dialog Semiconductor China Phone: +86 755 2981 3669 China (Shanghai) Dialog Semiconductor China Phone: +86 21 5424 9058 10-Mar-2021 © 2021 Dialog SemiconductorMicrosoft Word for Office 365