Contents
1. Introduction
2. Sockets Overview
3. Why HTTP?
4. Creating a HTTP Client
5. Parsing Text Data
6. Securing Communications with SSL/TLS - Overview
7. Certificates
8. Transferring Files with UniFlash – Certificates and Executables
9. Creating a Secured HTTP (HTTPS) Client
10. Using an I2C Text Display
11. Summary
1. Introduction
Part 1 earlier examined the CC3200 combined microcontroller and 802.11 (Wi-Fi) integrated circuit and contained a quick guide on how to set up a development environment ready for working with the CC3200 LaunchPad, and walked through how to compile/build and run a demo application, and how to perform general purpose I/O and serial I2C operations with the board.
Part 2 now concentrates on network operations to communicate over the Internet. Both unsecured and secured application data transfer capabilities using HTTP will be covered. The example project is a weather monitor type of device. The complete source code is attached at the bottom of the post.
2. Sockets Overview
There is a set of standard function calls (also known as an application programming interface or API) that allow devices to communicate across a network or across the Internet without really needing to know the underlying complexity (such as routing, bits/bytes, error-checking and so on). This standard is known as a ‘Socket Networking API’ and it means that if you write some code that takes advantage of it, then the same code could be run on different hardware with little to no modifications, regardless of access methods (e.g. 802.11, 3G/4G, DSL, etc); in other words the code will therefore be portable and future-proof with no vendor lock-in.
Conveniently the CC3200 supports a very socket-like API (note that some other manufacturer 802.11 dev-boards do not support such an API, and instead offer a more simplistic API; it is proposed that such cut-down APIs are an anachronism, because nowadays there is sufficient processing power in low-cost devices to use a more standards based API).
In fact, the CC3200 is supplied with a volume of code with a whole range of functions to support projects. The SimpleLink API documentation is the main resource that will be used throughout this blog post to access the Socket API.
For a more detailed background to the Socket API, a good reference book is ‘UNIX Network Programming’ by W. Richard Stevens.
3. Why HTTP?
HTTP has become a protocol of choice to transfer data between applications. It is text based which means that one can do a lot with string functions, to construct up or parse content sent inside HTTP. Applications can be tested using just a web browser. There are platform-as-a-service (PaaS) offerings such as Google AppEngine to speed up development of custom cloud based applications. There are well-known Software-as-a-Service offerings like SalesForce and PayPal. There are also plenty of web services (with functions or API-like calls that can be executed over the network) which use HTTP, such as Yahoo’s Developer Network offerings. These services use queries constructed inside HTML and communication uses existing HTML methods; the API becomes known as a RESTful API.
By exploring it is possible to find lots of interesting queries possible with such APIs (Paste into a browser to test, or edit them first). Here is one which provides weather information for London (replace the text ‘london’ and ‘uk’ for a different desired location):
- http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22london%2C%20uk%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys
Here is another which provides detailed weather, wind speed, direction and temperature information for thousands of locations in the UK; this URL is for the Isle of Wight (it requires free registration for a key, go to the UK Met Office site if you want this):
- http://datapoint.metoffice.gov.uk/public/data/val/wxfcs/all/xml/354652?res=3hourly&key=my-key
RSS feeds are another way of obtaining information. This one tells about traffic incidents on UK motorways:
- https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20feed%20where%20url%3D%27http%3A%2F%2Fhatrafficinfo.dft.gov.uk%2Ffeeds%2Frss%2FUnplannedEvents.xml%27&diagnostics=true&diagnostics=true
UK severe weather warnings:
- http://www.metoffice.gov.uk/public/data/PWSCache/WarningsRSS/Region/UK
4. Creating a HTTP Client
In order to access a site or service using HTTP, the Socket API is used to create the connection, send the request and then receive the result. This example will build on the wlan_station demo code that was used in part 1. The wlan_station demo unmodified performs the following actions:
- Board initialisation
- Task created for SimpleLink
- Task ‘WlanStationMode’ is created
- Start up the task scheduler
Once the tasks have been started up, the WlanStationMode task performs these actions:
- Connect to the WLAN access point and obtain an IP address using DHCP
- Ping the default gateway IP address
- Ping www.ti.com site
- Display a success message
The first step is to inspect the wlan_station code (main.c file) and comment out the code for items 2 and 3 above and replace with the desired functionality (the desired functionality is to connect to a web service and retrieve weather information using HTTP).
Next, since HTTP messages can be very verbose, a reasonable amount of space needs to be allocated for the task that will handle them. Here it is set to 6000 bytes (only the relevant code snippets are shown below; the code needs to be placed in the appropriate places in the code, or inspect the final code which is attached):
- #define OSI_STACK_SIZE 6000
- //
- // Start the WlanStationMode task
- //
- lRetVal = osi_TaskCreate( WlanStationMode, \
- (const signed char*)"Wlan Station Task", \
- OSI_STACK_SIZE, NULL, 1, NULL );
Note that the return values should be checked here and for the other functions below; it is not shown in the text here for clarity, but the final code does contain error checking. It will save hours/days to know immediately where a problem is occurring, so it is good not to skimp on error checking, even if it is just to print a log message.
The next step is to find out the IP address of the destination device to connect to. The following code will query the DNS server to find out what the IP address of the site is, based on the site name (fully qualified domain name).
- #define SERVER_NAME "query.yahooapis.com"
- signed char *g_Host = SERVER_NAME;
- unsigned int uiIP;
- lRetVal = sl_NetAppDnsGetHostByName(g_Host, strlen((const char *)g_Host), (unsigned long*)&uiIP, SL_AF_INET);
The Socket library inside the SimpleLink code is now instructed that it is desired to create a connection. This is known as creating a TCP socket:
- int iSockID;
- iSockID = sl_Socket(SL_AF_INET,SL_SOCK_STREAM, 0);
What the line above does is allocate some resources (memory, state information and so on) and returns an identifier (or 'handle') to the socket.
The next step is to build up a structure which will contain IP address and port information:
- SlSockAddrIn_t Addr;
- int iAddrSize;
- Addr.sin_family = SL_AF_INET;
- Addr.sin_port = sl_Htons(80); // default port for http
- Addr.sin_addr.s_addr = sl_Htonl(uiIP);
- iAddrSize = sizeof(SlSockAddrIn_t);
Next, the connect function in the Socket API is called. This will send a packet over the Internet to the remote site, and perform a particular handshake. This is known as TCP session establishment.
- lRetVal = sl_Connect(iSockID, ( SlSockAddr_t *)&Addr, iAddrSize);
Note that the code should now check the returned value. If there was an error then a negative value will be returned. An example error situation would be if the remote server was down for example. If the connect was successful, it is said that the TCP connection (or session) is established. The software application on the CC3200, and the remote server application are now free to send information to each other.
To send data, the following code is used:
- #define GET_TEXT "GET /v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22london%2C%20uk%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys/ HTTP/1.1\r\nHost:query.yahooapis.com\r\nAccept: */*\r\n\r\n"
- int iTXStatus;
- char acSendBuff[512];
- strcpy(acSendBuff, GET_TEXT);
- iTXStatus = sl_Send(iSockID, acSendBuff, strlen(acSendBuff), 0);
The content that was sent was a HTTP GET method, containing the desired query. Since HTTP is text based, it is easy to use familiar string functions such as strcpy to construct up the content.
So, to summarise so far, the connection was established with the remote server and then a HTTP GET method was sent containing the desired required request.
Data that is sent from the server back to the CC3200 client can be accessed using a receive function as shown here:
- int iRXDataStatus;
- char acRecvBuff[4096];
- iRXDataStatus = sl_Recv(iSockID, acRecvbuff, 4096, 0);
The code above will wait (i.e. the function will not necessarily return immediately) until 1024 bytes have been received, or if some internal buffer size has been reached, or if there is a timeout or if the socket is closed by the remote side. Basically there are a lot of reasons why a different amount of bytes are read than expected. So, the code above is a little impractical. A better solution is something like this:
- int iRXDataStatus;
- char acRecvBuff[4096];
- int uNumOfBytesToRead=4096;
- int recvlen = 0;
- memset(acRecvbuff, 0, sizeof(acRecvbuff));
- do
- {
- iRXDataStatus = sl_Recv(iSockID, &acRecvbuff[recvlen], uNumOfBytesToRead - recvlen, 0);
- if(!(iRXDataStatus > 0))
- {
- // No more to read, or error
- sl_Close(iSockID);
- break; // Handling the error code is specific to the application
- }
- recvlen += iRXDataStatus;
- } while(recvlen < uNumOfBytesToRead);
The code above will repeatedly loop to read data until the expected number of bytes has been reached.
You may not know how many bytes to read, so it is up to the software application code to parse the data and decide if more data is expected. Another approach (simpler) is just wait for a timeout to occur, and then make an assumption that the server is not slow, but that there really is no more data that it needs to send to you. To use this trick, socket options can be set:
- #define SERVER_RESPONSE_TIMEOUT 10
- struct SlTimeval_t timeVal;
- timeVal.tv_sec = SERVER_RESPONSE_TIMEOUT; // Seconds
- timeVal.tv_usec = 0; // Microseconds. 10000 microseconds resolution
- lRetVal = sl_SetSockOpt(iSockID,SL_SOL_SOCKET,SL_SO_RCVTIMEO,\
- (unsigned char*)&timeVal, sizeof(timeVal));
In most cases, unless the project needs very time-critical response handling, the timeout method can be sufficient.
Finally, when the application is done with the socket and has no more need to send or receive further data, the socket can be closed:
- lRetVal = sl_Close(iSockID);
The above command will initiate an exchange over the network known as a TCP connection termination.
5. Parsing Text Data
Typically received data will be variable length and text-based, which means that the application won’t necessarily be able to know in advance which byte(s) to examine. Instead, the text needs to be parsed, searching for identifiers close to the content you actually need. As an example, for a weather monitor application, you may receive the following content (this is a truncated snippet):
- Received HTTP GET response data, length is 2437
- HTTP/1.1 200 OK
- X-AntiCRIME: FrRaSyH6rfS4f
- Set-Cookie: X-AC=wgz
- X-YQL-Host: engine9.yql.bf1.yahoo.com
- X-Content-Type-Options: nosniff
- Access-Control-Allow-Origin: *
- Cache-Control: public, max-age=199
- Content-Type: application/json;charset=utf-8
- Date: Thu, 16 Oct 2014 02:36:04 GMT
- Server: ATS
- Age: 1
- Transfer-Encoding: chunked
- Connection: keep-alive
- 968
- {"query":{"count":1,"created":"2014-10-16T02:36:05Z","lang":"en-US","results":{"channel":{"title":"Yahoo! Weather - London,
- GB","link":"http://us.rd.yahoo.com/dailynews/rss/weather/London__GB/*http://weather.yahoo.com/forecast/UKXX0085_f.html",
- "description":"Yahoo! Weather for London, GB","language":"en-us","lastBuildDate":"Thu, 16 Oct 2014 2:49 am
- BST","ttl":"60","location":{"city":"London","country":"United
- Kingdom","region":""},"units":{"distance":"mi","pressure":"in","speed":"mph","temperature":"F"},"wind":{"chill":"57",
- ...
- />\n<b>Current Conditions:</b><br />\nPartly Cloudy, 57 F<BR />\n<BR /><b>Forecast:</b><BR />\nWed - Mostly Cloudy. High: 59
- Low: 52<br />\nThu - Partly Cloudy. High: 65 Low: 55<br />\nFri - Partly Cloudy. High: 69 Low: 59<br />\nSat - PM Showers.
- High: 73 Low: 61<br />\nSun - AM Clouds/PM Sun. High: 70 Low: 55<br />\n<br />\n<a
- href=\"http://us.rd.yahoo.com/dailynews/rss/weather/London__GB/*http://weather.yahoo.com/forecast/UKXX0085_f.html\">Full
- Forecast at Yahoo! Weather</a><BR/><BR/>\n(provided by <a href=\"http://www.weather.com\" >The Weather
- ...
For a weather monitor, if the intention is to only display the current weather conditions (as an example) then the software needs to examine the text close to the words ‘Current Conditions’ in line 28 above.
This could be achieved as shown here:
- // test for: Current Conditions:</b><br />\nPartly Cloudy, 57 F<BR />
- char tbuf[32];
- char* startPtr, endPtr;
- startPtr = strstr(acRecvbuff, "Current Conditions:"); // start index now rests on the C in Current
- startPtr=startPtr+31; // move the start index to rest on the P in Partly
- endPtr=strstr(acRecvbuff, "<BR"); // endPtr is resting on the first unwanted character
- *endPtr=’\0’; // replace the unwanted character with an end-of-string identifier
- strncpy(tbuf, startPtr, 32);
- tbuf[31]=’\0’; // terminate the string in case it was too long
The above code results in the array tbuf containing the current weather conditions, all ready for sending to a display for example.
Although the example code above achieves the simple aims of this weather monitor application, in practice it would be better to create some more flexible functions to parse text data to suit needs. If the content is expected in a certain syntax (e.g. XML) then open source software will exist to help with the parsing.
6. Securing Communications with SSL/TLS - Overview
Transport Layer Security (TLS) can be used to encrypt application traffic between a device/endpoint and a server. It is one way of providing some security that may be useful for CC3200 applications.
Although the encryption may provide a level of security, you might also need to be sure that you are communicating securely to the correct remote server. This involves authentication, a process which allows one party to assert who they are to some reasonable degree of confidence to the other party, and possibly vice-versa.
Note that in the usual implementation that people are familiar with (web pages accessed using ‘https://’ instead of ‘http://’, the remote party’s server is authenticating very little; it is merely asserting to the client (you) that it has obtained a certificate from a body known as a certificate authority. By using ‘https’, the client has not authenticated itself to the server; one would need to have a username/password capability to do that. In other words, a ‘unilateral’ authentication has been achieved (the encryption is bidirectional). This is why when you access your bank’s online banking capability, after the encrypted session has been established using TLS, the user is expected to enter username/identifiers and passwords for example, so that you can assert to the bank that you are who you say you are.
All you can really confirm here is that the actual traffic will be encrypted from end to end (and even that can be doubtful, since MITM (man-in-the-middle) devices can be a definite possibility; these will terminate the TLS session (i.e. they will decrypt) and then create a new TLS session (this is not necessarily a rare situation; there are many commercial scenarios where this is done).
On the authentication point, if desired, TLS can be used to authenticate both sides, i.e. the client and the server, but this is outside the scope of this blog post.
For an explanation of TLS, refer to the blog post HTTPS – how it works and why it is used. For now, it is sufficient to know that files containing “certificates” are at the heart of authentication and key exchange to make the encrypted communications feasible.
7. Certificates
The first step is to choose an XaaS (e.g. Software-as-a-Service) provider, and identify what certificate authority is used to authenticate their certificate. This is not a straightforward thing, but one method is described here (I am not convinced I have found the best method, the below method just shows what worked for me. It may be incorrect. It was found by trial-and-error).
First, access the desired API from a web browser using ‘https://’ to confirm this works, and that a padlock appears to confirm secure communication. In this example, the service provider was Yahoo and the selected service was weather reports using their query.yahooapis.com site.
- https://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20weather.forecast%20where%20woeid%20in%20(select%20woeid%20from%20geo.places(1)%20where%20text%3D%22london%2C%20uk%22)&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys
The screenshot below shows the response. Clicking on the padlock in the address bar also confirms that the communication is secure (this is using Google Chrome, but other browsers have a similar procedure):
Your PC contains many certificates from various certificate authorities. The aim is to discover which certificate you already own allowed the web browser to successfully establish secure communications with the site in question (query.yahooapis.com).
I couldn’t reliably find a way to do this without using an additional tool. The Certificate Installation Checker from DigiCert proved helpful.
Once this tool is installed, select Tools->Certificate Installation Checker->Check Install and then it is possible to type the site address into it, and it will query the site and list the certificates that it presents. The screenshot below shows what to type and click:
On the last result result, inspect the ‘Issuer’ line as shown above, and also double-click in the white space to bring up more detail. Inspect the ‘Signature algorithm’. The aim will now be to try to match these two fields to a certificate that you already own.
To see the certificates installed on your PC, click on the Windows Start icon and type certmgr.msc to open up the Certificate Manager tool.
Now some manual inspection is needed. Double-click on individual certificates and inspect the ‘Details’ tab to see if the Issuer line fields can be matched up. In the screenshot below it can be seen that for the selected certificate in the Certificate Manager, the Issuer and Signature algorithm details are identical to those found via the DigiCert tool:
The above process has established that you own a certificate that has been issued by the same issuer as the certificate from the query.yahooapis.com site. Both certificates originated from the same Certificate Authority.
Now that there is a high chance this is the correct local certificate, click on Copy to File and select the default format which will be a DER encoded binary X.509 .CER file. This file now needs to be transferred to the CC3200 LaunchPad. This step requires the use of UniFlash which was briefly introduced in Part 1.
8. Transferring Files with UniFlash – Certificates and Executables
UniFlash is a tool that is used to get files from the PC onto the Serial Flash memory on-board the CC3200. The Serial Flash memory primarily contains the executable code for the application and upon boot-up the CC3200 will transfer the executable into its SRAM and execute it, however the Serial Flash’s file system can store other files too. For secure HTTP connections, the certificate needs to be stored on the file system.
It is not possible to see the files on the Serial Flash, so you need to remember what was stored on it, or as a last-case be prepared to wipe the entire Flash and re-format it.
Start up UniFlash, click New Target Configuration as described in Part 1 (accept the defaults) and the left side will show the file system expected on the Serial Flash. This is just a local configuration, the tool has not checked the Serial Flash. Change the COM port number to the correct value as described in Part 1 and then click on Add File. The tool will generate a random file name:
Next, click on the file name and then on the right side populate with the certificate file details as shown below. The ‘Update’ and ‘Verify’ options are selected, and everything under Mode is left unchecked. Next, click in the white space for this information to be accepted:
Since it can get hard remembering what was stored on the Serial Flash, the configuration can be saved on the PC using File->Save Configuration As.
The next step is to execute the configuration to get the certificate file uploaded. To do this, plug in the CC3200 board (if it is not already plugged in), and ensure the jumper is in the UniFlash position (See Part 1 for this detail). Press the RESET button on the LaunchPad board if the jumper is moved, since the pin is only read on reset.
Next, click on the Program button in UniFlash and observe the output in the lower window. If at any time it prompts and waits for you to restart the device, then press the RESET button on the LaunchPad.
The output will look like this:
- [17:47:51] Begin AddFile operation.
- [17:47:51] Operation AddFile returned.
- [17:49:11] Begin Program operation.
- [17:49:11] INFO: > Executing Operation: Connect
- [17:49:13] INFO: setting break signal
- [17:49:13] INFO: --- please restart the device ---
- [17:49:13] INFO: connection succeeded
- [17:49:13] INFO: getting storage list
- [17:49:13] INFO: > Executing Operation: Init
- [17:49:13] INFO: reading version info
- [17:49:13] INFO: DEVICE CC3200 ES1.32
- [17:49:13] INFO: reading version info
- [17:49:15] INFO: reading version info
- [17:49:17] INFO: > Executing Operation: Program
- [17:49:17] INFO: > File name: /sys/mcuimg.bin, Update: false, Erase: false
- [17:49:17] INFO: > File name: /cert/ca.pem, Update: false, Erase: false
- [17:49:17] INFO: > File name: /cert/client.pem, Update: false, Erase: false
- [17:49:17] INFO: > File name: /cert/private.key, Update: false, Erase: false
- [17:49:17] INFO: > File name: /tmp/pac.bin, Update: false, Erase: false
- [17:49:17] INFO: > File name: /sys/macadd.bin, Update: false, Erase: false
- [17:49:17] INFO: > File name: /cert/verisign.cer, Update: true, Erase: false
- [17:49:17] INFO: > Size of file = 576
- [17:49:17] INFO: > Update File: /cert/verisign.cer
- [17:49:17] INFO: Downloading file "/cert/verisign.cer" with size 576
- [17:49:17] INFO:
- New Token is 0x0
- [17:49:17] INFO: Download complete
- [17:49:17] INFO: Verifying Data...
- [17:49:17] INFO: get file
- [17:49:17] INFO: Done. Reading 576 bytes
- [17:49:17] INFO:
- Verification OK
- [17:49:18] INFO: > Updated Token value: 0x0
- [17:49:18] INFO: > Executing Operation: Disconnect
- [17:49:19] Operation Program returned.
The UniFlash software can get locked up. If it hangs and cannot be closed, open Windows Task Manager and kill it. If UniFlash generates an error, close the application and restart it. In summary, if in doubt, just restart UniFlash.
If the certificate file later needs to be replaced with a different file (e.g. if it was the wrong file), then to delete the old file, restart UniFlash, retrieve the configuration (or recreate the configuration since it only takes a few seconds) but this time select theErase option as shown here:
Repeat the process to program the Serial Flash, and the log will indicate that the file is erased.
- [18:03:55] Begin Program operation.
- [18:03:55] INFO: > Executing Operation: Connect
- [18:03:57] INFO: setting break signal
- [18:03:57] INFO: --- please restart the device ---
- [18:03:57] INFO: connection succeeded
- [18:03:57] INFO: getting storage list
- [18:03:57] INFO: > Executing Operation: Init
- [18:03:57] INFO: reading version info
- [18:03:57] INFO: DEVICE CC3200 ES1.32
- [18:03:57] INFO: reading version info
- [18:03:59] INFO: reading version info
- [18:04:01] INFO: > Executing Operation: Program
- [18:04:01] INFO: > File name: /sys/mcuimg.bin, Update: false, Erase: false
- [18:04:01] INFO: > File name: /cert/ca.pem, Update: false, Erase: false
- [18:04:01] INFO: > File name: /cert/client.pem, Update: false, Erase: false
- [18:04:01] INFO: > File name: /cert/private.key, Update: false, Erase: false
- [18:04:01] INFO: > File name: /tmp/pac.bin, Update: false, Erase: false
- [18:04:01] INFO: > File name: /sys/macadd.bin, Update: false, Erase: false
- [18:04:01] INFO: > File name: /cert/verisign.cer, Update: false, Erase: true
- [18:04:01] INFO: > Erase File: /cert/verisign.cer
- [18:04:01] INFO: erasing file "/cert/verisign.cer"
- [18:04:01] INFO: deleting file "/cert/verisign.cer"
- [18:04:01] INFO: erase file completed
- [18:04:01] INFO: > Executing Operation: Disconnect
- [18:04:01] Operation Program returned.
In general with UniFlash if an error occurs, restart UniFlash, check the COM port is correct, check the jumper is in the UniFlash position and press RESET on the CC3200 LaunchPad. There also appears to be a bug in that only one file can be loaded onto the Serial Flash; if it works for you, do let me know.
UniFlash will also be used to transfer the final binary executable onto the Serial Flash, once you are happy with it. The procedure is to first uncheck the Update and Program options on the certificate file (so that the file is still part of the configuration, but no actions are needed for it), and then click on /sys/mcuimg.bin in UniFlash, and then click Browse and locate the binary file on your PC. The path will be something like C:\work\wlan_station\Release for the example in this Getting Started guide if you used the paths suggested in Part 1. The file will be called wlan_station.bin. Once you have selected the file, select the Update and Verify options as before, click in the white space and then click on Program.
The output will look like this:
- [18:52:23] Begin Program operation.
- [18:52:23] INFO: > Executing Operation: Connect
- [18:52:25] INFO: setting break signal
- [18:52:25] INFO: --- please restart the device ---
- [18:52:25] INFO: connection succeeded
- [18:52:25] INFO: getting storage list
- [18:52:25] INFO: > Executing Operation: Init
- [18:52:25] INFO: reading version info
- [18:52:25] INFO: DEVICE CC3200 ES1.32
- [18:52:25] INFO: reading version info
- [18:52:27] INFO: reading version info
- [18:52:29] INFO: > Executing Operation: Program
- [18:52:29] INFO: > File name: /sys/mcuimg.bin, Update: true, Erase: false
- [18:52:29] INFO: > Size of file = 64312
- [18:52:29] INFO: > Update File: /sys/mcuimg.bin
- [18:52:29] INFO: Downloading file "/sys/mcuimg.bin" with size 64312
- [18:52:32] INFO:
- New Token is 0x0
- [18:52:32] INFO: Download complete
- [18:52:32] INFO: Verifying Data...
- [18:52:32] INFO: get file
- [18:52:34] INFO: Done. Reading 64312 bytes
- [18:52:34] INFO:
- Verification OK
- [18:52:35] INFO: > Updated Token value: 0x0
- [18:52:35] INFO: > File name: /cert/ca.pem, Update: false, Erase: false
- [18:52:35] INFO: > File name: /cert/client.pem, Update: false, Erase: false
- [18:52:35] INFO: > File name: /cert/private.key, Update: false, Erase: false
- [18:52:35] INFO: > File name: /tmp/pac.bin, Update: false, Erase: false
- [18:52:35] INFO: > File name: /sys/macadd.bin, Update: false, Erase: false
- [18:52:35] INFO: > File name: /cert/verisign.cer, Update: false, Erase: false
- [18:52:35] INFO: > Executing Operation: Disconnect
- [18:52:35] Operation Program returned.
9. Creating a Secured HTTP (HTTPS) Client
The same HTTP client code as before can be used with some very small modifications. The first step is to set the time for the SimpleLink code. Unless the time is approximately correct, HTTPS connections cannot be established. There are a few options; either a real time clock (RTC) can be implemented in code (see the cc3200-sdk\driverlib\prcm.c and cc3200-sdk\middleware\driver\rtc_hal.c files), or an external hardware RTC could be connected to the board, or the time can be retrieved from the Internet. For this example the time is statically configured:
- #define DATE 14 /* Current Date */
- #define MONTH 10 /* Month 1-12 */
- #define YEAR 2014 /* Current year */
- #define HOUR 18 /* Time - hours */
- #define MINUTE 32 /* Time - minutes */
- #define SECOND 0 /* Time - seconds */
- typedef struct
- {
- /* time */
- unsigned long tm_sec;
- unsigned long tm_min;
- unsigned long tm_hour;
- /* date */
- unsigned long tm_day;
- unsigned long tm_mon;
- unsigned long tm_year;
- unsigned long tm_week_day; //not required
- unsigned long tm_year_day; //not required
- unsigned long reserved[3];
- }SlDateTime;
- SlDateTime g_time;
- long retVal;
- g_time.tm_day = DATE;
- g_time.tm_mon = MONTH;
- g_time.tm_year = YEAR;
- g_time.tm_sec = HOUR;
- g_time.tm_hour = MINUTE;
- g_time.tm_min = SECOND;
- retVal = sl_DevSet(SL_DEVICE_GENERAL_CONFIGURATION, SL_DEVICE_GENERAL_CONFIGURATION_DATE_TIME, sizeof(SlDateTime),(unsigned char *)(&g_time));
During socket creation, an option is sent to the Socket library to indicate that HTTPS is to be used:
- iSockID = sl_Socket(SL_AF_INET,SL_SOCK_STREAM, SL_SEC_SOCKET);
The Socket library also needs to be instructed where the certificate file resides:
- #define SL_SSL_CA_CERT_FILE_NAME "/cert/verisign.cer"
- lRetVal = sl_SetSockOpt(iSockID, SL_SOL_SOCKET, \
- SL_SO_SECURE_FILES_CA_FILE_NAME, \
- SL_SSL_CA_CERT_FILE_NAME, \
- strlen(SL_SSL_CA_CERT_FILE_NAME));
The function above can also be used for setting various socket options, such as influencing which encryption algorithm gets used; the defaults should be sufficient to get the code working.
The port number needs changing from 80 (default for HTTP) to 443 (default for HTTPS):
- Addr.sin_port = sl_Htons(443); // default port for https
No more code changes are needed; when run, the communication will now be secured. HTTPS isn't really needed for a weather application, but will be needed for other scenarios.
10. I2C Text Display
This part 2 will end with a small set of functions for using an I2C based display. GPIO and I2C was covered in Part 1. This particular LCD has one reset pin, and the usual I2C SDA and SCL signals.
The first step is to configure one of the CC3200 pins as an output for the LCD reset, and to enable the I2C interface, as described in Part 1. This is the connection diagram (thanks to BigG for the LaunchPad graphics).
Next, some definitions are created to control the reset pin:
- #define LCD_RES_LOW GPIO_IF_Set(6, lcd_reset_port, lcd_reset_pin, 0)
- #define LCD_RES_HIGH GPIO_IF_Set(6, lcd_reset_port, lcd_reset_pin, 1)
- unsigned int lcd_reset_port;
- unsigned char lcd_reset_pin;
- GPIO_IF_GetPortNPin(6, &lcd_reset_port, &lcd_reset_pin);
LCD I2c address and initialization constants:
- #define LCD_ADDR 0x3e
- const char lcd_init_arr[]={ 0x38, 0x39, 0x14, 0x79, 0x50, 0x6c, 0x0c, 0x01 };
LCD routines:
- void
- lcd_init(void)
- {
- LCD_RES_HIGH;
- MAP_UtilsDelay(MSEC_VAL*50); // 50msec delay
- LCD_RES_LOW;
- MAP_UtilsDelay(MSEC_VAL*50);
- LCD_RES_HIGH;
- MAP_UtilsDelay(MSEC_VAL*50);
- int i;
- char data[2];
- data[0]=0;
- for (i=0; i<8; i++)
- {
- data[1]=lcd_init_arr[i];
- I2C_IF_Write(LCD_ADDR, data, 2, true);
- }
- }
- void
- lcd_clear(void)
- {
- char data[2];
- data[0]=0;
- data[1]=1;
- I2C_IF_Write(LCD_ADDR, data, 2, true);
- MAP_UtilsDelay(MSEC_VAL*2);
- }
- void
- lcd_setpos(char ln, char idx)
- {
- char data [2];
- data[0]=0;
- if (ln==0)
- data[1]=0x80+idx; // 0x00 | 0x80
- else
- data[1]=0xc0+idx; // 0x40 | 0x80
- I2C_IF_Write(LCD_ADDR, data, 2, true);
- }
- void
- lcd_print(char* str)
- {
- char data[2];
- data[0]=0x40;
- while(*str != '\0')
- {
- data[1]=*str++;
- I2C_IF_Write(LCD_ADDR, data, 2, true);
- }
- }
To use the LCD routines is straightforward - first call lcd_init, then lcd_clear and then lcd_setpos to select a row and column. Finally, lcd_print can be used to place text on the display.
Here is a short 30-second video of the CC3200 running the HTTPS client code and the LCD code (the screen is a bit hard to see in this video). The delay before the result is displayed is due to the application code waiting for the socket receive operation to timeout (as discussed further above, this can be avoided for time-critical applications by parsing the data as it arrives; for a weather monitor it is not critical). This demo video uses a LiPo BoosterPack for power; this needs a couple of tracks drilled out to be compatible, this post has the detail.
11. Summary
This Part 2 covered why a Sockets API is useful, and how to use it to connect to servers on the Internet to transfer content using HTTP. Because it is text based, usual string functions can be used to parse the content. Transferring content securely is possible using HTTPS; the code changes to do this are small. Certificates are stored on the file system in the Serial Flash on the CC3200 LaunchPad. The code in this post and Part 1 was combined to create a Weather Monitor using an I2C LCD display. The source code for this project is below.
No comments:
Post a Comment