DeepCover Embedded Security in IoT: Public-key Secured Data Paths

Dependencies:   MaximInterface

The MAXREFDES155# is an internet-of-things (IoT) embedded-security reference design, built to authenticate and control a sensing node using elliptic-curve-based public-key cryptography with control and notification from a web server.

The hardware includes an ARM® mbed™ shield and attached sensor endpoint. The shield contains a DS2476 DeepCover® ECDSA/SHA-2 coprocessor, Wifi communication, LCD push-button controls, and status LEDs. The sensor endpoint is attached to the shield using a 300mm cable and contains a DS28C36 DeepCover ECDSA/SHA-2 authenticator, IR-thermal sensor, and aiming laser for the IR sensor. The MAXREFDES155# is equipped with a standard Arduino® form-factor shield connector for immediate testing using an mbed board such as the MAX32600MBED#. The combination of these two devices represent an IoT device. Communication to the web server is accomplished with the shield Wifi circuitry. Communication from the shield to the attached sensor module is accomplished over I2C . The sensor module represents an IoT endpoint that generates small data with a requirement for message authenticity/integrity and secure on/off operational control.

The design is hierarchical with each mbed platform and shield communicating data from the sensor node to a web server that maintains a centralized log and dispatches notifications as necessary. The simplicity of this design enables rapid integration into any star-topology IoT network to provide security with the low overhead and cost provided by the ECDSA-P256 asymmetric-key and SHA-256 symmetric-key algorithms.

More information about the MAXREFDES155# is available on the Maxim Integrated website.

Committer:
IanBenzMaxim
Date:
Wed May 03 16:08:59 2017 -0500
Revision:
11:989eabe2a376
Parent:
10:71359af61af8
Child:
13:6a6225690c2e
Changed to always using scanline encoding for bitmaps.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
IanBenzMaxim 0:33d4e66780c0 1 /*******************************************************************************
IanBenzMaxim 0:33d4e66780c0 2 * Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved.
IanBenzMaxim 0:33d4e66780c0 3 *
IanBenzMaxim 0:33d4e66780c0 4 * Permission is hereby granted, free of charge, to any person obtaining a
IanBenzMaxim 0:33d4e66780c0 5 * copy of this software and associated documentation files (the "Software"),
IanBenzMaxim 0:33d4e66780c0 6 * to deal in the Software without restriction, including without limitation
IanBenzMaxim 0:33d4e66780c0 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
IanBenzMaxim 0:33d4e66780c0 8 * and/or sell copies of the Software, and to permit persons to whom the
IanBenzMaxim 0:33d4e66780c0 9 * Software is furnished to do so, subject to the following conditions:
IanBenzMaxim 0:33d4e66780c0 10 *
IanBenzMaxim 0:33d4e66780c0 11 * The above copyright notice and this permission notice shall be included
IanBenzMaxim 0:33d4e66780c0 12 * in all copies or substantial portions of the Software.
IanBenzMaxim 0:33d4e66780c0 13 *
IanBenzMaxim 0:33d4e66780c0 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
IanBenzMaxim 0:33d4e66780c0 15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
IanBenzMaxim 0:33d4e66780c0 16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IanBenzMaxim 0:33d4e66780c0 17 * IN NO EVENT SHALL MAXIM INTEGRATED BE LIABLE FOR ANY CLAIM, DAMAGES
IanBenzMaxim 0:33d4e66780c0 18 * OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
IanBenzMaxim 0:33d4e66780c0 19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
IanBenzMaxim 0:33d4e66780c0 20 * OTHER DEALINGS IN THE SOFTWARE.
IanBenzMaxim 0:33d4e66780c0 21 *
IanBenzMaxim 0:33d4e66780c0 22 * Except as contained in this notice, the name of Maxim Integrated
IanBenzMaxim 0:33d4e66780c0 23 * Products, Inc. shall not be used except as stated in the Maxim Integrated
IanBenzMaxim 0:33d4e66780c0 24 * Products, Inc. Branding Policy.
IanBenzMaxim 0:33d4e66780c0 25 *
IanBenzMaxim 0:33d4e66780c0 26 * The mere transfer of this software does not imply any licenses
IanBenzMaxim 0:33d4e66780c0 27 * of trade secrets, proprietary technology, copyrights, patents,
IanBenzMaxim 0:33d4e66780c0 28 * trademarks, maskwork rights, or any other form of intellectual
IanBenzMaxim 0:33d4e66780c0 29 * property whatsoever. Maxim Integrated Products, Inc. retains all
IanBenzMaxim 0:33d4e66780c0 30 * ownership rights.
IanBenzMaxim 0:33d4e66780c0 31 *******************************************************************************/
IanBenzMaxim 0:33d4e66780c0 32
IanBenzMaxim 0:33d4e66780c0 33 #include <algorithm>
IanBenzMaxim 0:33d4e66780c0 34 #include <functional>
IanBenzMaxim 0:33d4e66780c0 35 #include <list>
IanBenzMaxim 0:33d4e66780c0 36 #include "Bitmap.hpp"
IanBenzMaxim 0:33d4e66780c0 37 #include "Display.hpp"
IanBenzMaxim 0:33d4e66780c0 38 #include "Text.hpp"
IanBenzMaxim 0:33d4e66780c0 39
IanBenzMaxim 0:33d4e66780c0 40 using std::string;
IanBenzMaxim 0:33d4e66780c0 41
IanBenzMaxim 8:a0d75dff3c9b 42 static const int invalidWidthHeight = -1;
IanBenzMaxim 8:a0d75dff3c9b 43
IanBenzMaxim 8:a0d75dff3c9b 44 static const int characterWidth = 5;
IanBenzMaxim 8:a0d75dff3c9b 45 static const int characterHeight = 7;
IanBenzMaxim 0:33d4e66780c0 46
IanBenzMaxim 0:33d4e66780c0 47 static const unsigned char printableCharBegin = 0x20;
IanBenzMaxim 0:33d4e66780c0 48 static const unsigned char printableCharEnd = 0x7E;
IanBenzMaxim 0:33d4e66780c0 49
IanBenzMaxim 11:989eabe2a376 50 static const uint8_t characterMap[][characterHeight] = {
IanBenzMaxim 11:989eabe2a376 51 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // ' '
IanBenzMaxim 11:989eabe2a376 52 { 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x20 }, // '!'
IanBenzMaxim 11:989eabe2a376 53 { 0x50, 0x50, 0x50, 0x00, 0x00, 0x00, 0x00 }, // '"'
IanBenzMaxim 11:989eabe2a376 54 { 0x50, 0x50, 0xF8, 0x50, 0xF8, 0x50, 0x50 }, // '#'
IanBenzMaxim 11:989eabe2a376 55 { 0x20, 0x78, 0xA0, 0x70, 0x28, 0xF0, 0x20 }, // '$'
IanBenzMaxim 11:989eabe2a376 56 { 0xC0, 0xC8, 0x10, 0x20, 0x40, 0x98, 0x18 }, // '%'
IanBenzMaxim 11:989eabe2a376 57 { 0x60, 0x90, 0xA0, 0x40, 0xA8, 0x90, 0x68 }, // '&'
IanBenzMaxim 11:989eabe2a376 58 { 0x60, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00 }, // '''
IanBenzMaxim 11:989eabe2a376 59 { 0x10, 0x20, 0x40, 0x40, 0x40, 0x20, 0x10 }, // '('
IanBenzMaxim 11:989eabe2a376 60 { 0x40, 0x20, 0x10, 0x10, 0x10, 0x20, 0x40 }, // ')'
IanBenzMaxim 11:989eabe2a376 61 { 0x00, 0x20, 0xA8, 0x70, 0xA8, 0x20, 0x00 }, // '*'
IanBenzMaxim 11:989eabe2a376 62 { 0x00, 0x20, 0x20, 0xF8, 0x20, 0x20, 0x00 }, // '+'
IanBenzMaxim 11:989eabe2a376 63 { 0x00, 0x00, 0x00, 0x00, 0x60, 0x20, 0x40 }, // ','
IanBenzMaxim 11:989eabe2a376 64 { 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00 }, // '-'
IanBenzMaxim 11:989eabe2a376 65 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60 }, // '.'
IanBenzMaxim 11:989eabe2a376 66 { 0x00, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00 }, // '/'
IanBenzMaxim 11:989eabe2a376 67 { 0x70, 0x88, 0x98, 0xA8, 0xC8, 0x88, 0x70 }, // '0'
IanBenzMaxim 11:989eabe2a376 68 { 0x20, 0x60, 0x20, 0x20, 0x20, 0x20, 0x70 }, // '1'
IanBenzMaxim 11:989eabe2a376 69 { 0x70, 0x88, 0x08, 0x10, 0x20, 0x40, 0xF8 }, // '2'
IanBenzMaxim 11:989eabe2a376 70 { 0xF8, 0x10, 0x20, 0x10, 0x08, 0x88, 0x70 }, // '3'
IanBenzMaxim 11:989eabe2a376 71 { 0x10, 0x30, 0x50, 0x90, 0xF8, 0x10, 0x10 }, // '4'
IanBenzMaxim 11:989eabe2a376 72 { 0xF8, 0x80, 0xF0, 0x08, 0x08, 0x88, 0x70 }, // '5'
IanBenzMaxim 11:989eabe2a376 73 { 0x30, 0x40, 0x80, 0xF0, 0x88, 0x88, 0x70 }, // '6'
IanBenzMaxim 11:989eabe2a376 74 { 0xF8, 0x08, 0x10, 0x20, 0x40, 0x40, 0x40 }, // '7'
IanBenzMaxim 11:989eabe2a376 75 { 0x70, 0x88, 0x88, 0x70, 0x88, 0x88, 0x70 }, // '8'
IanBenzMaxim 11:989eabe2a376 76 { 0x70, 0x88, 0x88, 0x78, 0x08, 0x10, 0x60 }, // '9'
IanBenzMaxim 11:989eabe2a376 77 { 0x00, 0x60, 0x60, 0x00, 0x60, 0x60, 0x00 }, // ':'
IanBenzMaxim 11:989eabe2a376 78 { 0x00, 0x60, 0x60, 0x00, 0x60, 0x20, 0x40 }, // ';'
IanBenzMaxim 11:989eabe2a376 79 { 0x10, 0x20, 0x40, 0x80, 0x40, 0x20, 0x10 }, // '<'
IanBenzMaxim 11:989eabe2a376 80 { 0x00, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0x00 }, // '='
IanBenzMaxim 11:989eabe2a376 81 { 0x40, 0x20, 0x10, 0x08, 0x10, 0x20, 0x40 }, // '>'
IanBenzMaxim 11:989eabe2a376 82 { 0x70, 0x88, 0x08, 0x10, 0x20, 0x00, 0x20 }, // '?'
IanBenzMaxim 11:989eabe2a376 83 { 0x70, 0x88, 0x08, 0x68, 0xA8, 0xA8, 0x70 }, // '@'
IanBenzMaxim 11:989eabe2a376 84 { 0x70, 0x88, 0x88, 0x88, 0xF8, 0x88, 0x88 }, // 'A'
IanBenzMaxim 11:989eabe2a376 85 { 0xF0, 0x88, 0x88, 0xF0, 0x88, 0x88, 0xF0 }, // 'B'
IanBenzMaxim 11:989eabe2a376 86 { 0x70, 0x88, 0x80, 0x80, 0x80, 0x88, 0x70 }, // 'C'
IanBenzMaxim 11:989eabe2a376 87 { 0xE0, 0x90, 0x88, 0x88, 0x88, 0x90, 0xE0 }, // 'D'
IanBenzMaxim 11:989eabe2a376 88 { 0xF8, 0x80, 0x80, 0xF0, 0x80, 0x80, 0xF8 }, // 'E'
IanBenzMaxim 11:989eabe2a376 89 { 0xF8, 0x80, 0x80, 0xF0, 0x80, 0x80, 0x80 }, // 'F'
IanBenzMaxim 11:989eabe2a376 90 { 0x70, 0x88, 0x80, 0xB8, 0x88, 0x88, 0x78 }, // 'G'
IanBenzMaxim 11:989eabe2a376 91 { 0x88, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x88 }, // 'H'
IanBenzMaxim 11:989eabe2a376 92 { 0x70, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70 }, // 'I'
IanBenzMaxim 11:989eabe2a376 93 { 0x38, 0x10, 0x10, 0x10, 0x10, 0x90, 0x60 }, // 'J'
IanBenzMaxim 11:989eabe2a376 94 { 0x88, 0x90, 0xA0, 0xC0, 0xA0, 0x90, 0x88 }, // 'K'
IanBenzMaxim 11:989eabe2a376 95 { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xF8 }, // 'L'
IanBenzMaxim 11:989eabe2a376 96 { 0x88, 0xD8, 0xA8, 0xA8, 0x88, 0x88, 0x88 }, // 'M'
IanBenzMaxim 11:989eabe2a376 97 { 0x88, 0x88, 0xC8, 0xA8, 0x98, 0x88, 0x88 }, // 'N'
IanBenzMaxim 11:989eabe2a376 98 { 0x70, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70 }, // 'O'
IanBenzMaxim 11:989eabe2a376 99 { 0xF0, 0x88, 0x88, 0xF0, 0x80, 0x80, 0x80 }, // 'P'
IanBenzMaxim 11:989eabe2a376 100 { 0x70, 0x88, 0x88, 0x88, 0xA8, 0x90, 0x68 }, // 'Q'
IanBenzMaxim 11:989eabe2a376 101 { 0xF0, 0x88, 0x88, 0xF0, 0xA0, 0x90, 0x88 }, // 'R'
IanBenzMaxim 11:989eabe2a376 102 { 0x78, 0x80, 0x80, 0x70, 0x08, 0x08, 0xF0 }, // 'S'
IanBenzMaxim 11:989eabe2a376 103 { 0xF8, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, // 'T'
IanBenzMaxim 11:989eabe2a376 104 { 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70 }, // 'U'
IanBenzMaxim 11:989eabe2a376 105 { 0x88, 0x88, 0x88, 0x88, 0x88, 0x50, 0x20 }, // 'V'
IanBenzMaxim 11:989eabe2a376 106 { 0x88, 0x88, 0x88, 0xA8, 0xA8, 0xA8, 0x50 }, // 'W'
IanBenzMaxim 11:989eabe2a376 107 { 0x88, 0x88, 0x50, 0x20, 0x50, 0x88, 0x88 }, // 'X'
IanBenzMaxim 11:989eabe2a376 108 { 0x88, 0x88, 0x88, 0x50, 0x20, 0x20, 0x20 }, // 'Y'
IanBenzMaxim 11:989eabe2a376 109 { 0xF8, 0x08, 0x10, 0x20, 0x40, 0x80, 0xF8 }, // 'Z'
IanBenzMaxim 11:989eabe2a376 110 { 0x70, 0x40, 0x40, 0x40, 0x40, 0x40, 0x70 }, // '['
IanBenzMaxim 11:989eabe2a376 111 { 0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x00 }, // '\'
IanBenzMaxim 11:989eabe2a376 112 { 0x70, 0x10, 0x10, 0x10, 0x10, 0x10, 0x70 }, // ']'
IanBenzMaxim 11:989eabe2a376 113 { 0x20, 0x50, 0x88, 0x00, 0x00, 0x00, 0x00 }, // '^'
IanBenzMaxim 11:989eabe2a376 114 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8 }, // '_'
IanBenzMaxim 11:989eabe2a376 115 { 0x40, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00 }, // '`'
IanBenzMaxim 11:989eabe2a376 116 { 0x00, 0x00, 0x70, 0x08, 0x78, 0x88, 0x78 }, // 'a'
IanBenzMaxim 11:989eabe2a376 117 { 0x80, 0x80, 0xB0, 0xC8, 0x88, 0x88, 0xF0 }, // 'b'
IanBenzMaxim 11:989eabe2a376 118 { 0x00, 0x00, 0x70, 0x80, 0x80, 0x88, 0x70 }, // 'c'
IanBenzMaxim 11:989eabe2a376 119 { 0x08, 0x08, 0x68, 0x98, 0x88, 0x88, 0x78 }, // 'd'
IanBenzMaxim 11:989eabe2a376 120 { 0x00, 0x00, 0x70, 0x88, 0xF8, 0x80, 0x70 }, // 'e'
IanBenzMaxim 11:989eabe2a376 121 { 0x30, 0x48, 0x40, 0xE0, 0x40, 0x40, 0x40 }, // 'f'
IanBenzMaxim 11:989eabe2a376 122 { 0x00, 0x78, 0x88, 0x88, 0x78, 0x08, 0x70 }, // 'g'
IanBenzMaxim 11:989eabe2a376 123 { 0x80, 0x80, 0xB0, 0xC8, 0x88, 0x88, 0x88 }, // 'h'
IanBenzMaxim 11:989eabe2a376 124 { 0x20, 0x00, 0x60, 0x20, 0x20, 0x20, 0x70 }, // 'i'
IanBenzMaxim 11:989eabe2a376 125 { 0x10, 0x00, 0x30, 0x10, 0x10, 0x90, 0x60 }, // 'j'
IanBenzMaxim 11:989eabe2a376 126 { 0x80, 0x80, 0x90, 0xA0, 0xC0, 0xA0, 0x90 }, // 'k'
IanBenzMaxim 11:989eabe2a376 127 { 0x60, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70 }, // 'l'
IanBenzMaxim 11:989eabe2a376 128 { 0x00, 0x00, 0xD0, 0xA8, 0xA8, 0x88, 0x88 }, // 'm'
IanBenzMaxim 11:989eabe2a376 129 { 0x00, 0x00, 0xB0, 0xC8, 0x88, 0x88, 0x88 }, // 'n'
IanBenzMaxim 11:989eabe2a376 130 { 0x00, 0x00, 0x70, 0x88, 0x88, 0x88, 0x70 }, // 'o'
IanBenzMaxim 11:989eabe2a376 131 { 0x00, 0x00, 0xF0, 0x88, 0xF0, 0x80, 0x80 }, // 'p'
IanBenzMaxim 11:989eabe2a376 132 { 0x00, 0x00, 0x68, 0x98, 0x78, 0x08, 0x08 }, // 'q'
IanBenzMaxim 11:989eabe2a376 133 { 0x00, 0x00, 0xB0, 0xC8, 0x80, 0x80, 0x80 }, // 'r'
IanBenzMaxim 11:989eabe2a376 134 { 0x00, 0x00, 0x70, 0x80, 0x70, 0x08, 0xF0 }, // 's'
IanBenzMaxim 11:989eabe2a376 135 { 0x40, 0x40, 0xE0, 0x40, 0x40, 0x48, 0x30 }, // 't'
IanBenzMaxim 11:989eabe2a376 136 { 0x00, 0x00, 0x88, 0x88, 0x88, 0x98, 0x68 }, // 'u'
IanBenzMaxim 11:989eabe2a376 137 { 0x00, 0x00, 0x88, 0x88, 0x88, 0x41, 0x20 }, // 'v'
IanBenzMaxim 11:989eabe2a376 138 { 0x00, 0x00, 0x88, 0x88, 0xA8, 0xA8, 0x50 }, // 'w'
IanBenzMaxim 11:989eabe2a376 139 { 0x00, 0x00, 0x88, 0x50, 0x20, 0x50, 0x88 }, // 'x'
IanBenzMaxim 11:989eabe2a376 140 { 0x00, 0x00, 0x88, 0x88, 0x78, 0x08, 0x70 }, // 'y'
IanBenzMaxim 11:989eabe2a376 141 { 0x00, 0x00, 0xF8, 0x10, 0x20, 0x40, 0xF8 }, // 'z'
IanBenzMaxim 11:989eabe2a376 142 { 0x10, 0x20, 0x20, 0x40, 0x20, 0x20, 0x10 }, // '{'
IanBenzMaxim 11:989eabe2a376 143 { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }, // '|'
IanBenzMaxim 11:989eabe2a376 144 { 0x40, 0x20, 0x20, 0x10, 0x20, 0x20, 0x40 }, // '}'
IanBenzMaxim 11:989eabe2a376 145 { 0x00, 0x00, 0x40, 0xA8, 0x10, 0x00, 0x00 } // '~'
IanBenzMaxim 0:33d4e66780c0 146 };
IanBenzMaxim 0:33d4e66780c0 147
IanBenzMaxim 0:33d4e66780c0 148 static bool charPrintable(unsigned char c)
IanBenzMaxim 0:33d4e66780c0 149 {
IanBenzMaxim 0:33d4e66780c0 150 return (c >= printableCharBegin) && (c <= printableCharEnd);
IanBenzMaxim 0:33d4e66780c0 151 }
IanBenzMaxim 0:33d4e66780c0 152
IanBenzMaxim 0:33d4e66780c0 153 static void removeNonprintableChars(string & s)
IanBenzMaxim 0:33d4e66780c0 154 {
IanBenzMaxim 3:d2799d8497c0 155 s.erase(std::remove_if(s.begin(), s.end(), std::not1(std::ptr_fun(charPrintable))), s.end());
IanBenzMaxim 0:33d4e66780c0 156 }
IanBenzMaxim 0:33d4e66780c0 157
IanBenzMaxim 0:33d4e66780c0 158 static bool compareStringLength(const string & a, const string & b)
IanBenzMaxim 0:33d4e66780c0 159 {
IanBenzMaxim 0:33d4e66780c0 160 return a.length() < b.length();
IanBenzMaxim 0:33d4e66780c0 161 }
IanBenzMaxim 0:33d4e66780c0 162
IanBenzMaxim 0:33d4e66780c0 163 // Functor trims string if it exceeds a certain length.
IanBenzMaxim 0:33d4e66780c0 164 class TrimString
IanBenzMaxim 0:33d4e66780c0 165 {
IanBenzMaxim 0:33d4e66780c0 166 public:
IanBenzMaxim 0:33d4e66780c0 167 TrimString(string::size_type maxSize) : maxSize(maxSize) { }
IanBenzMaxim 0:33d4e66780c0 168
IanBenzMaxim 0:33d4e66780c0 169 void operator()(string & s)
IanBenzMaxim 0:33d4e66780c0 170 {
IanBenzMaxim 0:33d4e66780c0 171 if (s.size() > maxSize)
IanBenzMaxim 0:33d4e66780c0 172 {
IanBenzMaxim 0:33d4e66780c0 173 s.resize(maxSize);
IanBenzMaxim 0:33d4e66780c0 174 }
IanBenzMaxim 0:33d4e66780c0 175 }
IanBenzMaxim 0:33d4e66780c0 176
IanBenzMaxim 0:33d4e66780c0 177 private:
IanBenzMaxim 0:33d4e66780c0 178 string::size_type maxSize;
IanBenzMaxim 0:33d4e66780c0 179 };
IanBenzMaxim 0:33d4e66780c0 180
IanBenzMaxim 0:33d4e66780c0 181 // Split a string based on a character token. Token will be removed.
IanBenzMaxim 0:33d4e66780c0 182 static std::list<string> tokenizeString(const string & toSplit, char token)
IanBenzMaxim 0:33d4e66780c0 183 {
IanBenzMaxim 0:33d4e66780c0 184 std::list<string> toSplitLines;
IanBenzMaxim 0:33d4e66780c0 185 string::size_type beginIdx = 0, endIdx;
IanBenzMaxim 0:33d4e66780c0 186 do
IanBenzMaxim 0:33d4e66780c0 187 {
IanBenzMaxim 0:33d4e66780c0 188 endIdx = toSplit.find(token, beginIdx);
IanBenzMaxim 0:33d4e66780c0 189 toSplitLines.push_back(toSplit.substr(beginIdx, endIdx == string::npos ? string::npos : endIdx - beginIdx));
IanBenzMaxim 0:33d4e66780c0 190 beginIdx = endIdx + 1;
IanBenzMaxim 0:33d4e66780c0 191 } while (endIdx != string::npos);
IanBenzMaxim 0:33d4e66780c0 192 return toSplitLines;
IanBenzMaxim 0:33d4e66780c0 193 }
IanBenzMaxim 0:33d4e66780c0 194
IanBenzMaxim 0:33d4e66780c0 195 // Word wrap string into lines based on a specified line length.
IanBenzMaxim 0:33d4e66780c0 196 static std::list<string> wrapLines(const string & toSplit, const string::size_type lineLen)
IanBenzMaxim 0:33d4e66780c0 197 {
IanBenzMaxim 0:33d4e66780c0 198 std::list<string> toSplitLines;
IanBenzMaxim 0:33d4e66780c0 199 string::size_type beginIdx = 0;
IanBenzMaxim 0:33d4e66780c0 200 if (lineLen > 0)
IanBenzMaxim 0:33d4e66780c0 201 {
IanBenzMaxim 0:33d4e66780c0 202 // Split lines as much as necessary.
IanBenzMaxim 0:33d4e66780c0 203 string::size_type endIdx = lineLen;
IanBenzMaxim 0:33d4e66780c0 204 while (((toSplit.length() - beginIdx) > lineLen) && (endIdx != string::npos))
IanBenzMaxim 0:33d4e66780c0 205 {
IanBenzMaxim 0:33d4e66780c0 206 endIdx = toSplit.rfind(' ', endIdx);
IanBenzMaxim 0:33d4e66780c0 207 if ((endIdx == string::npos) || (endIdx <= beginIdx))
IanBenzMaxim 0:33d4e66780c0 208 {
IanBenzMaxim 0:33d4e66780c0 209 // Current word is too long to split. Find end of current word.
IanBenzMaxim 0:33d4e66780c0 210 endIdx = toSplit.find(' ', beginIdx);
IanBenzMaxim 0:33d4e66780c0 211 }
IanBenzMaxim 0:33d4e66780c0 212 if (endIdx != string::npos)
IanBenzMaxim 0:33d4e66780c0 213 {
IanBenzMaxim 0:33d4e66780c0 214 toSplitLines.push_back(toSplit.substr(beginIdx, endIdx - beginIdx));
IanBenzMaxim 0:33d4e66780c0 215 beginIdx = endIdx + 1;
IanBenzMaxim 0:33d4e66780c0 216 endIdx = beginIdx + lineLen;
IanBenzMaxim 0:33d4e66780c0 217 }
IanBenzMaxim 0:33d4e66780c0 218 }
IanBenzMaxim 0:33d4e66780c0 219 }
IanBenzMaxim 0:33d4e66780c0 220 // Last line is any remaining characters.
IanBenzMaxim 0:33d4e66780c0 221 toSplitLines.push_back(toSplit.substr(beginIdx, toSplit.length() - beginIdx));
IanBenzMaxim 0:33d4e66780c0 222 return toSplitLines;
IanBenzMaxim 0:33d4e66780c0 223 }
IanBenzMaxim 0:33d4e66780c0 224
IanBenzMaxim 8:a0d75dff3c9b 225 Text::Text() : m_text(), m_wordWrap(false), m_charSpacing(1), m_lineSpacing(1),
IanBenzMaxim 8:a0d75dff3c9b 226 m_textLines(), m_preferredWidth(invalidWidthHeight), m_preferredHeight(invalidWidthHeight) { }
IanBenzMaxim 0:33d4e66780c0 227
IanBenzMaxim 6:0c9050b02876 228 void Text::setText(const string & text)
IanBenzMaxim 0:33d4e66780c0 229 {
IanBenzMaxim 0:33d4e66780c0 230 if (m_text != text)
IanBenzMaxim 0:33d4e66780c0 231 {
IanBenzMaxim 0:33d4e66780c0 232 m_text = text;
IanBenzMaxim 8:a0d75dff3c9b 233 invalidate();
IanBenzMaxim 8:a0d75dff3c9b 234 m_preferredWidth = m_preferredHeight = invalidWidthHeight;
IanBenzMaxim 0:33d4e66780c0 235 }
IanBenzMaxim 0:33d4e66780c0 236 }
IanBenzMaxim 0:33d4e66780c0 237
IanBenzMaxim 0:33d4e66780c0 238 void Text::setWordWrap(bool wordWrap)
IanBenzMaxim 0:33d4e66780c0 239 {
IanBenzMaxim 0:33d4e66780c0 240 if (m_wordWrap != wordWrap)
IanBenzMaxim 0:33d4e66780c0 241 {
IanBenzMaxim 0:33d4e66780c0 242 m_wordWrap = wordWrap;
IanBenzMaxim 8:a0d75dff3c9b 243 invalidate();
IanBenzMaxim 8:a0d75dff3c9b 244 m_preferredWidth = m_preferredHeight = invalidWidthHeight;
IanBenzMaxim 0:33d4e66780c0 245 }
IanBenzMaxim 0:33d4e66780c0 246 }
IanBenzMaxim 0:33d4e66780c0 247
IanBenzMaxim 8:a0d75dff3c9b 248 void Text::setLineSpacing(int lineSpacing)
IanBenzMaxim 0:33d4e66780c0 249 {
IanBenzMaxim 8:a0d75dff3c9b 250 if (lineSpacing > 0 && m_lineSpacing != lineSpacing)
IanBenzMaxim 0:33d4e66780c0 251 {
IanBenzMaxim 0:33d4e66780c0 252 m_lineSpacing = lineSpacing;
IanBenzMaxim 8:a0d75dff3c9b 253 invalidate();
IanBenzMaxim 8:a0d75dff3c9b 254 m_preferredHeight = invalidWidthHeight;
IanBenzMaxim 8:a0d75dff3c9b 255 }
IanBenzMaxim 8:a0d75dff3c9b 256 }
IanBenzMaxim 8:a0d75dff3c9b 257
IanBenzMaxim 8:a0d75dff3c9b 258 void Text::setCharSpacing(int charSpacing)
IanBenzMaxim 8:a0d75dff3c9b 259 {
IanBenzMaxim 8:a0d75dff3c9b 260 if (charSpacing > 0 && m_charSpacing != charSpacing)
IanBenzMaxim 8:a0d75dff3c9b 261 {
IanBenzMaxim 8:a0d75dff3c9b 262 m_charSpacing = charSpacing;
IanBenzMaxim 8:a0d75dff3c9b 263 invalidate();
IanBenzMaxim 8:a0d75dff3c9b 264 m_preferredWidth = invalidWidthHeight;
IanBenzMaxim 8:a0d75dff3c9b 265 if (wordWrap())
IanBenzMaxim 8:a0d75dff3c9b 266 {
IanBenzMaxim 8:a0d75dff3c9b 267 m_preferredHeight = invalidWidthHeight;
IanBenzMaxim 8:a0d75dff3c9b 268 }
IanBenzMaxim 0:33d4e66780c0 269 }
IanBenzMaxim 0:33d4e66780c0 270 }
IanBenzMaxim 0:33d4e66780c0 271
IanBenzMaxim 8:a0d75dff3c9b 272 int Text::preferredWidth() const
IanBenzMaxim 8:a0d75dff3c9b 273 {
IanBenzMaxim 8:a0d75dff3c9b 274 if (m_preferredWidth == invalidWidthHeight)
IanBenzMaxim 8:a0d75dff3c9b 275 {
IanBenzMaxim 8:a0d75dff3c9b 276 calculateLayout();
IanBenzMaxim 8:a0d75dff3c9b 277 }
IanBenzMaxim 8:a0d75dff3c9b 278 return m_preferredWidth;
IanBenzMaxim 8:a0d75dff3c9b 279 }
IanBenzMaxim 8:a0d75dff3c9b 280
IanBenzMaxim 8:a0d75dff3c9b 281 int Text::preferredHeight() const
IanBenzMaxim 0:33d4e66780c0 282 {
IanBenzMaxim 8:a0d75dff3c9b 283 if (m_preferredHeight == invalidWidthHeight)
IanBenzMaxim 0:33d4e66780c0 284 {
IanBenzMaxim 8:a0d75dff3c9b 285 calculateLayout();
IanBenzMaxim 8:a0d75dff3c9b 286 }
IanBenzMaxim 8:a0d75dff3c9b 287 return m_preferredHeight;
IanBenzMaxim 8:a0d75dff3c9b 288 }
IanBenzMaxim 8:a0d75dff3c9b 289
IanBenzMaxim 8:a0d75dff3c9b 290 void Text::resized()
IanBenzMaxim 8:a0d75dff3c9b 291 {
IanBenzMaxim 8:a0d75dff3c9b 292 m_preferredWidth = invalidWidthHeight;
IanBenzMaxim 8:a0d75dff3c9b 293 if (wordWrap())
IanBenzMaxim 8:a0d75dff3c9b 294 {
IanBenzMaxim 8:a0d75dff3c9b 295 m_preferredHeight = invalidWidthHeight;
IanBenzMaxim 0:33d4e66780c0 296 }
IanBenzMaxim 0:33d4e66780c0 297 }
IanBenzMaxim 8:a0d75dff3c9b 298
IanBenzMaxim 10:71359af61af8 299 void Text::doRender(Bitmap & bitmap, int xOffset, int yOffset) const
IanBenzMaxim 8:a0d75dff3c9b 300 {
IanBenzMaxim 8:a0d75dff3c9b 301 using std::list;
IanBenzMaxim 0:33d4e66780c0 302
IanBenzMaxim 8:a0d75dff3c9b 303 // Ensure layout is up to date.
IanBenzMaxim 8:a0d75dff3c9b 304 if (m_preferredWidth == invalidWidthHeight || m_preferredHeight == invalidWidthHeight)
IanBenzMaxim 8:a0d75dff3c9b 305 {
IanBenzMaxim 8:a0d75dff3c9b 306 calculateLayout();
IanBenzMaxim 8:a0d75dff3c9b 307 }
IanBenzMaxim 8:a0d75dff3c9b 308
IanBenzMaxim 8:a0d75dff3c9b 309 // Render each line.
IanBenzMaxim 8:a0d75dff3c9b 310 int lineNum = 0;
IanBenzMaxim 8:a0d75dff3c9b 311 for (list<string>::const_iterator lineIt = m_textLines.begin(); lineIt != m_textLines.end(); lineIt++)
IanBenzMaxim 8:a0d75dff3c9b 312 {
IanBenzMaxim 8:a0d75dff3c9b 313 // Render each character.
IanBenzMaxim 8:a0d75dff3c9b 314 for (string::size_type charNum = 0; charNum < lineIt->length(); charNum++)
IanBenzMaxim 8:a0d75dff3c9b 315 {
IanBenzMaxim 10:71359af61af8 316 bitmap.overlay(
IanBenzMaxim 10:71359af61af8 317 xOffset + x() + charNum * (characterWidth + m_charSpacing),
IanBenzMaxim 11:989eabe2a376 318 yOffset + y() + lineNum * (characterHeight + m_lineSpacing),
IanBenzMaxim 11:989eabe2a376 319 &characterMap[(*lineIt)[charNum] - printableCharBegin][0],
IanBenzMaxim 11:989eabe2a376 320 characterHeight,
IanBenzMaxim 11:989eabe2a376 321 characterWidth
IanBenzMaxim 10:71359af61af8 322 );
IanBenzMaxim 8:a0d75dff3c9b 323 }
IanBenzMaxim 8:a0d75dff3c9b 324 lineNum++;
IanBenzMaxim 8:a0d75dff3c9b 325 }
IanBenzMaxim 8:a0d75dff3c9b 326 }
IanBenzMaxim 8:a0d75dff3c9b 327
IanBenzMaxim 8:a0d75dff3c9b 328 void Text::calculateLayout() const
IanBenzMaxim 0:33d4e66780c0 329 {
IanBenzMaxim 0:33d4e66780c0 330 using std::list;
IanBenzMaxim 0:33d4e66780c0 331
IanBenzMaxim 0:33d4e66780c0 332 // Split string into lines.
IanBenzMaxim 0:33d4e66780c0 333 m_textLines = tokenizeString(m_text, '\n');
IanBenzMaxim 0:33d4e66780c0 334
IanBenzMaxim 0:33d4e66780c0 335 // Remove non-printable characters.
IanBenzMaxim 0:33d4e66780c0 336 std::for_each(m_textLines.begin(), m_textLines.end(), removeNonprintableChars);
IanBenzMaxim 0:33d4e66780c0 337
IanBenzMaxim 8:a0d75dff3c9b 338 const int lineLen =
IanBenzMaxim 0:33d4e66780c0 339 (width() / (characterWidth + m_charSpacing)) +
IanBenzMaxim 0:33d4e66780c0 340 (((width() % (characterWidth + m_charSpacing)) >= characterWidth) ? 1 : 0);
IanBenzMaxim 8:a0d75dff3c9b 341 const int numLines =
IanBenzMaxim 0:33d4e66780c0 342 (height() / (characterHeight + m_lineSpacing)) +
IanBenzMaxim 0:33d4e66780c0 343 (((height() % (characterHeight + m_lineSpacing)) >= characterHeight) ? 1 : 0);
IanBenzMaxim 0:33d4e66780c0 344
IanBenzMaxim 0:33d4e66780c0 345 // Word wrap lines if enabled.
IanBenzMaxim 0:33d4e66780c0 346 if (m_wordWrap)
IanBenzMaxim 0:33d4e66780c0 347 {
IanBenzMaxim 0:33d4e66780c0 348 list<string>::iterator lineIt = m_textLines.begin();
IanBenzMaxim 0:33d4e66780c0 349 while (lineIt != m_textLines.end())
IanBenzMaxim 0:33d4e66780c0 350 {
IanBenzMaxim 0:33d4e66780c0 351 list<string>::iterator nextLineIt = lineIt;
IanBenzMaxim 0:33d4e66780c0 352 nextLineIt++;
IanBenzMaxim 0:33d4e66780c0 353
IanBenzMaxim 0:33d4e66780c0 354 // Wrap current line.
IanBenzMaxim 0:33d4e66780c0 355 list<string> wrappedLines = wrapLines(*lineIt, lineLen);
IanBenzMaxim 0:33d4e66780c0 356 m_textLines.splice(lineIt, wrappedLines);
IanBenzMaxim 0:33d4e66780c0 357 // Remove old line.
IanBenzMaxim 0:33d4e66780c0 358 m_textLines.erase(lineIt);
IanBenzMaxim 0:33d4e66780c0 359
IanBenzMaxim 0:33d4e66780c0 360 lineIt = nextLineIt;
IanBenzMaxim 0:33d4e66780c0 361 }
IanBenzMaxim 0:33d4e66780c0 362 }
IanBenzMaxim 0:33d4e66780c0 363
IanBenzMaxim 0:33d4e66780c0 364 // Calculate preferred size.
IanBenzMaxim 0:33d4e66780c0 365 string::size_type maxLineLength =
IanBenzMaxim 0:33d4e66780c0 366 std::max_element(m_textLines.begin(), m_textLines.end(), compareStringLength)->length();
IanBenzMaxim 0:33d4e66780c0 367 m_preferredWidth = (maxLineLength > 0) ?
IanBenzMaxim 0:33d4e66780c0 368 (maxLineLength * characterWidth) + ((maxLineLength - 1) * m_charSpacing) : 1;
IanBenzMaxim 0:33d4e66780c0 369 m_preferredHeight =
IanBenzMaxim 0:33d4e66780c0 370 (m_textLines.size() * characterHeight) + ((m_textLines.size() - 1) * m_lineSpacing);
IanBenzMaxim 0:33d4e66780c0 371
IanBenzMaxim 0:33d4e66780c0 372 // Remove clipped text.
IanBenzMaxim 8:a0d75dff3c9b 373 if (m_textLines.size() > static_cast<list<string>::size_type>(numLines))
IanBenzMaxim 0:33d4e66780c0 374 m_textLines.resize(numLines);
IanBenzMaxim 0:33d4e66780c0 375 std::for_each(m_textLines.begin(), m_textLines.end(), TrimString(lineLen));
IanBenzMaxim 0:33d4e66780c0 376 }