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:
Thu Apr 06 15:16:30 2017 -0500
Revision:
8:a0d75dff3c9b
Parent:
6:0c9050b02876
Child:
10:71359af61af8
Simplified graphics system for better clarity and expandability.

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 0:33d4e66780c0 50 static const uint8_t characterMap[][characterWidth] = {
IanBenzMaxim 0:33d4e66780c0 51 { 0x00, 0x00, 0x00, 0x00, 0x00 }, // ' '
IanBenzMaxim 0:33d4e66780c0 52 { 0x00, 0x00, 0xF2, 0x00, 0x00 }, // '!'
IanBenzMaxim 0:33d4e66780c0 53 { 0x00, 0xE0, 0x00, 0xE0, 0x00 }, // '"'
IanBenzMaxim 0:33d4e66780c0 54 { 0x28, 0xFE, 0x28, 0xFE, 0x28 }, // '#'
IanBenzMaxim 0:33d4e66780c0 55 { 0x24, 0x54, 0xFE, 0x54, 0x48 }, // '$'
IanBenzMaxim 0:33d4e66780c0 56 { 0xC4, 0xC8, 0x10, 0x26, 0x46 }, // '%'
IanBenzMaxim 0:33d4e66780c0 57 { 0x6C, 0x92, 0xAA, 0x44, 0x0A }, // '&'
IanBenzMaxim 0:33d4e66780c0 58 { 0x00, 0xA0, 0xC0, 0x00, 0x00 }, // '''
IanBenzMaxim 0:33d4e66780c0 59 { 0x00, 0x28, 0x44, 0x82, 0x00 }, // '('
IanBenzMaxim 0:33d4e66780c0 60 { 0x00, 0x82, 0x44, 0x38, 0x00 }, // ')'
IanBenzMaxim 0:33d4e66780c0 61 { 0x28, 0x10, 0x7C, 0x10, 0x28 }, // '*'
IanBenzMaxim 0:33d4e66780c0 62 { 0x10, 0x10, 0x7C, 0x10, 0x10 }, // '+'
IanBenzMaxim 0:33d4e66780c0 63 { 0x00, 0x0A, 0x0C, 0x00, 0x00 }, // ','
IanBenzMaxim 0:33d4e66780c0 64 { 0x10, 0x10, 0x10, 0x10, 0x10 }, // '-'
IanBenzMaxim 0:33d4e66780c0 65 { 0x00, 0x06, 0x06, 0x00, 0x00 }, // '.'
IanBenzMaxim 0:33d4e66780c0 66 { 0x04, 0x08, 0x10, 0x20, 0x40 }, // '/'
IanBenzMaxim 0:33d4e66780c0 67 { 0x7C, 0x8A, 0x92, 0xA2, 0x7C }, // '0'
IanBenzMaxim 0:33d4e66780c0 68 { 0x00, 0x42, 0xFE, 0x02, 0x00 }, // '1'
IanBenzMaxim 0:33d4e66780c0 69 { 0x42, 0x86, 0x8A, 0x92, 0x62 }, // '2'
IanBenzMaxim 0:33d4e66780c0 70 { 0x84, 0x82, 0xA2, 0xD2, 0x8C }, // '3'
IanBenzMaxim 0:33d4e66780c0 71 { 0x18, 0x28, 0x48, 0xFE, 0x08 }, // '4'
IanBenzMaxim 0:33d4e66780c0 72 { 0xE4, 0xA2, 0xA2, 0xA2, 0x9C }, // '5'
IanBenzMaxim 0:33d4e66780c0 73 { 0x3C, 0x52, 0x92, 0x92, 0x0C }, // '6'
IanBenzMaxim 0:33d4e66780c0 74 { 0x80, 0x8E, 0x90, 0xA0, 0xC0 }, // '7'
IanBenzMaxim 0:33d4e66780c0 75 { 0x6C, 0x92, 0x92, 0x92, 0x6C }, // '8'
IanBenzMaxim 0:33d4e66780c0 76 { 0x60, 0x92, 0x92, 0x94, 0x78 }, // '9'
IanBenzMaxim 0:33d4e66780c0 77 { 0x00, 0x6C, 0x6C, 0x00, 0x00 }, // ':'
IanBenzMaxim 0:33d4e66780c0 78 { 0x00, 0x6A, 0x6C, 0x00, 0x00 }, // ';'
IanBenzMaxim 0:33d4e66780c0 79 { 0x10, 0x28, 0x44, 0x82, 0x00 }, // '<'
IanBenzMaxim 0:33d4e66780c0 80 { 0x28, 0x28, 0x28, 0x28, 0x28 }, // '='
IanBenzMaxim 0:33d4e66780c0 81 { 0x00, 0x82, 0x44, 0x28, 0x10 }, // '>'
IanBenzMaxim 0:33d4e66780c0 82 { 0x40, 0x80, 0x8A, 0x90, 0x60 }, // '?'
IanBenzMaxim 0:33d4e66780c0 83 { 0x4C, 0x92, 0x9E, 0x82, 0x7C }, // '@'
IanBenzMaxim 0:33d4e66780c0 84 { 0x7E, 0x88, 0x88, 0x88, 0x7E }, // 'A'
IanBenzMaxim 0:33d4e66780c0 85 { 0xFE, 0x92, 0x92, 0x92, 0x6C }, // 'B'
IanBenzMaxim 0:33d4e66780c0 86 { 0x7C, 0x82, 0x82, 0x82, 0x44 }, // 'C'
IanBenzMaxim 0:33d4e66780c0 87 { 0xFE, 0x82, 0x82, 0x44, 0x38 }, // 'D'
IanBenzMaxim 0:33d4e66780c0 88 { 0xFE, 0x92, 0x92, 0x92, 0x82 }, // 'E'
IanBenzMaxim 0:33d4e66780c0 89 { 0xFE, 0x90, 0x90, 0x90, 0x80 }, // 'F'
IanBenzMaxim 0:33d4e66780c0 90 { 0x7C, 0x82, 0x92, 0x92, 0x5E }, // 'G'
IanBenzMaxim 0:33d4e66780c0 91 { 0xFE, 0x10, 0x10, 0x10, 0xFE }, // 'H'
IanBenzMaxim 0:33d4e66780c0 92 { 0x00, 0x82, 0xFE, 0x82, 0x00 }, // 'I'
IanBenzMaxim 0:33d4e66780c0 93 { 0x04, 0x02, 0x82, 0xFC, 0x80 }, // 'J'
IanBenzMaxim 0:33d4e66780c0 94 { 0xFE, 0x10, 0x28, 0x44, 0x82 }, // 'K'
IanBenzMaxim 0:33d4e66780c0 95 { 0xFE, 0x02, 0x02, 0x02, 0x02 }, // 'L'
IanBenzMaxim 0:33d4e66780c0 96 { 0xFE, 0x40, 0x21, 0x40, 0xFE }, // 'M'
IanBenzMaxim 0:33d4e66780c0 97 { 0xFE, 0x20, 0x10, 0x08, 0xFE }, // 'N'
IanBenzMaxim 0:33d4e66780c0 98 { 0x7C, 0x82, 0x82, 0x82, 0x7C }, // 'O'
IanBenzMaxim 0:33d4e66780c0 99 { 0xFE, 0x90, 0x90, 0x90, 0x60 }, // 'P'
IanBenzMaxim 0:33d4e66780c0 100 { 0x7C, 0x82, 0x8A, 0x82, 0x7A }, // 'Q'
IanBenzMaxim 0:33d4e66780c0 101 { 0xFE, 0x90, 0x98, 0x94, 0x62 }, // 'R'
IanBenzMaxim 0:33d4e66780c0 102 { 0x62, 0x92, 0x92, 0x92, 0x8C }, // 'S'
IanBenzMaxim 0:33d4e66780c0 103 { 0x80, 0x80, 0xFE, 0x80, 0x80 }, // 'T'
IanBenzMaxim 0:33d4e66780c0 104 { 0xFC, 0x02, 0x02, 0x02, 0xFC }, // 'U'
IanBenzMaxim 0:33d4e66780c0 105 { 0xF8, 0x04, 0x02, 0x04, 0xF8 }, // 'V'
IanBenzMaxim 0:33d4e66780c0 106 { 0xFC, 0x02, 0x1C, 0x02, 0xFC }, // 'W'
IanBenzMaxim 0:33d4e66780c0 107 { 0xC6, 0x28, 0x10, 0x28, 0xC6 }, // 'X'
IanBenzMaxim 0:33d4e66780c0 108 { 0xF0, 0x10, 0x0F, 0x10, 0xF0 }, // 'Y'
IanBenzMaxim 0:33d4e66780c0 109 { 0x86, 0x8A, 0x92, 0xA2, 0xC2 }, // 'Z'
IanBenzMaxim 0:33d4e66780c0 110 { 0x00, 0xFE, 0x82, 0x82, 0x00 }, // '['
IanBenzMaxim 0:33d4e66780c0 111 { 0x40, 0x20, 0x10, 0x08, 0x04 }, // '\'
IanBenzMaxim 0:33d4e66780c0 112 { 0x00, 0x82, 0x82, 0xFE, 0x00 }, // ']'
IanBenzMaxim 0:33d4e66780c0 113 { 0x20, 0x40, 0x80, 0x40, 0x20 }, // '^'
IanBenzMaxim 0:33d4e66780c0 114 { 0x02, 0x02, 0x02, 0x02, 0x02 }, // '_'
IanBenzMaxim 0:33d4e66780c0 115 { 0x00, 0x80, 0x40, 0x20, 0x00 }, // '`'
IanBenzMaxim 0:33d4e66780c0 116 { 0x04, 0x2A, 0x2A, 0x2A, 0x1E }, // 'a'
IanBenzMaxim 0:33d4e66780c0 117 { 0xFE, 0x12, 0x22, 0x22, 0x1C }, // 'b'
IanBenzMaxim 0:33d4e66780c0 118 { 0x1C, 0x22, 0x22, 0x22, 0x04 }, // 'c'
IanBenzMaxim 0:33d4e66780c0 119 { 0x1C, 0x22, 0x22, 0x12, 0xFE }, // 'd'
IanBenzMaxim 0:33d4e66780c0 120 { 0x1C, 0x2A, 0x2A, 0x2A, 0x18 }, // 'e'
IanBenzMaxim 0:33d4e66780c0 121 { 0x10, 0x7E, 0x90, 0x80, 0x40 }, // 'f'
IanBenzMaxim 0:33d4e66780c0 122 { 0x30, 0x4A, 0x4A, 0x4A, 0x7C }, // 'g'
IanBenzMaxim 0:33d4e66780c0 123 { 0xFE, 0x10, 0x20, 0x20, 0x1E }, // 'h'
IanBenzMaxim 0:33d4e66780c0 124 { 0x00, 0x22, 0xBE, 0x02, 0x00 }, // 'i'
IanBenzMaxim 0:33d4e66780c0 125 { 0x04, 0x02, 0x22, 0xBC, 0x00 }, // 'j'
IanBenzMaxim 0:33d4e66780c0 126 { 0xFE, 0x08, 0x14, 0x22, 0x00 }, // 'k'
IanBenzMaxim 0:33d4e66780c0 127 { 0x00, 0x82, 0xFE, 0x02, 0x00 }, // 'l'
IanBenzMaxim 0:33d4e66780c0 128 { 0x3E, 0x20, 0x18, 0x20, 0x1E }, // 'm'
IanBenzMaxim 0:33d4e66780c0 129 { 0x3E, 0x10, 0x20, 0x20, 0x1E }, // 'n'
IanBenzMaxim 0:33d4e66780c0 130 { 0x1C, 0x22, 0x22, 0x22, 0x1C }, // 'o'
IanBenzMaxim 0:33d4e66780c0 131 { 0x3E, 0x28, 0x28, 0x28, 0x10 }, // 'p'
IanBenzMaxim 0:33d4e66780c0 132 { 0x10, 0x28, 0x28, 0x18, 0x3E }, // 'q'
IanBenzMaxim 0:33d4e66780c0 133 { 0x3E, 0x10, 0x20, 0x20, 0x10 }, // 'r'
IanBenzMaxim 0:33d4e66780c0 134 { 0x12, 0x2A, 0x2A, 0x2A, 0x04 }, // 's'
IanBenzMaxim 0:33d4e66780c0 135 { 0x20, 0xFC, 0x22, 0x02, 0x04 }, // 't'
IanBenzMaxim 0:33d4e66780c0 136 { 0x3C, 0x02, 0x02, 0x04, 0x3E }, // 'u'
IanBenzMaxim 0:33d4e66780c0 137 { 0x38, 0x04, 0x02, 0x04, 0x38 }, // 'v'
IanBenzMaxim 0:33d4e66780c0 138 { 0x3C, 0x02, 0x0C, 0x02, 0x3C }, // 'w'
IanBenzMaxim 0:33d4e66780c0 139 { 0x22, 0x14, 0x08, 0x14, 0x22 }, // 'x'
IanBenzMaxim 0:33d4e66780c0 140 { 0x30, 0x0A, 0x0A, 0x0A, 0x3C }, // 'y'
IanBenzMaxim 0:33d4e66780c0 141 { 0x22, 0x26, 0x2A, 0x32, 0x22 }, // 'z'
IanBenzMaxim 0:33d4e66780c0 142 { 0x00, 0x10, 0x6C, 0x82, 0x00 }, // '{'
IanBenzMaxim 0:33d4e66780c0 143 { 0x00, 0x00, 0xFE, 0x00, 0x00 }, // '|'
IanBenzMaxim 0:33d4e66780c0 144 { 0x00, 0x82, 0x6C, 0x10, 0x00 }, // '}'
IanBenzMaxim 0:33d4e66780c0 145 { 0x10, 0x20, 0x10, 0x08, 0x10 } // '~'
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 8:a0d75dff3c9b 299 void Text::doRender(Bitmap & bitmap) 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 8:a0d75dff3c9b 316 Bitmap character(characterWidth, characterHeight,
IanBenzMaxim 8:a0d75dff3c9b 317 &characterMap[(*lineIt)[charNum] - printableCharBegin][0]);
IanBenzMaxim 8:a0d75dff3c9b 318 bitmap.overlay(character, charNum * (characterWidth + m_charSpacing),
IanBenzMaxim 8:a0d75dff3c9b 319 lineNum * (characterHeight + m_lineSpacing));
IanBenzMaxim 8:a0d75dff3c9b 320 }
IanBenzMaxim 8:a0d75dff3c9b 321 lineNum++;
IanBenzMaxim 8:a0d75dff3c9b 322 }
IanBenzMaxim 8:a0d75dff3c9b 323 }
IanBenzMaxim 8:a0d75dff3c9b 324
IanBenzMaxim 8:a0d75dff3c9b 325 void Text::calculateLayout() const
IanBenzMaxim 0:33d4e66780c0 326 {
IanBenzMaxim 0:33d4e66780c0 327 using std::list;
IanBenzMaxim 0:33d4e66780c0 328
IanBenzMaxim 0:33d4e66780c0 329 // Split string into lines.
IanBenzMaxim 0:33d4e66780c0 330 m_textLines = tokenizeString(m_text, '\n');
IanBenzMaxim 0:33d4e66780c0 331
IanBenzMaxim 0:33d4e66780c0 332 // Remove non-printable characters.
IanBenzMaxim 0:33d4e66780c0 333 std::for_each(m_textLines.begin(), m_textLines.end(), removeNonprintableChars);
IanBenzMaxim 0:33d4e66780c0 334
IanBenzMaxim 8:a0d75dff3c9b 335 const int lineLen =
IanBenzMaxim 0:33d4e66780c0 336 (width() / (characterWidth + m_charSpacing)) +
IanBenzMaxim 0:33d4e66780c0 337 (((width() % (characterWidth + m_charSpacing)) >= characterWidth) ? 1 : 0);
IanBenzMaxim 8:a0d75dff3c9b 338 const int numLines =
IanBenzMaxim 0:33d4e66780c0 339 (height() / (characterHeight + m_lineSpacing)) +
IanBenzMaxim 0:33d4e66780c0 340 (((height() % (characterHeight + m_lineSpacing)) >= characterHeight) ? 1 : 0);
IanBenzMaxim 0:33d4e66780c0 341
IanBenzMaxim 0:33d4e66780c0 342 // Word wrap lines if enabled.
IanBenzMaxim 0:33d4e66780c0 343 if (m_wordWrap)
IanBenzMaxim 0:33d4e66780c0 344 {
IanBenzMaxim 0:33d4e66780c0 345 list<string>::iterator lineIt = m_textLines.begin();
IanBenzMaxim 0:33d4e66780c0 346 while (lineIt != m_textLines.end())
IanBenzMaxim 0:33d4e66780c0 347 {
IanBenzMaxim 0:33d4e66780c0 348 list<string>::iterator nextLineIt = lineIt;
IanBenzMaxim 0:33d4e66780c0 349 nextLineIt++;
IanBenzMaxim 0:33d4e66780c0 350
IanBenzMaxim 0:33d4e66780c0 351 // Wrap current line.
IanBenzMaxim 0:33d4e66780c0 352 list<string> wrappedLines = wrapLines(*lineIt, lineLen);
IanBenzMaxim 0:33d4e66780c0 353 m_textLines.splice(lineIt, wrappedLines);
IanBenzMaxim 0:33d4e66780c0 354 // Remove old line.
IanBenzMaxim 0:33d4e66780c0 355 m_textLines.erase(lineIt);
IanBenzMaxim 0:33d4e66780c0 356
IanBenzMaxim 0:33d4e66780c0 357 lineIt = nextLineIt;
IanBenzMaxim 0:33d4e66780c0 358 }
IanBenzMaxim 0:33d4e66780c0 359 }
IanBenzMaxim 0:33d4e66780c0 360
IanBenzMaxim 0:33d4e66780c0 361 // Calculate preferred size.
IanBenzMaxim 0:33d4e66780c0 362 string::size_type maxLineLength =
IanBenzMaxim 0:33d4e66780c0 363 std::max_element(m_textLines.begin(), m_textLines.end(), compareStringLength)->length();
IanBenzMaxim 0:33d4e66780c0 364 m_preferredWidth = (maxLineLength > 0) ?
IanBenzMaxim 0:33d4e66780c0 365 (maxLineLength * characterWidth) + ((maxLineLength - 1) * m_charSpacing) : 1;
IanBenzMaxim 0:33d4e66780c0 366 m_preferredHeight =
IanBenzMaxim 0:33d4e66780c0 367 (m_textLines.size() * characterHeight) + ((m_textLines.size() - 1) * m_lineSpacing);
IanBenzMaxim 0:33d4e66780c0 368
IanBenzMaxim 0:33d4e66780c0 369 // Remove clipped text.
IanBenzMaxim 8:a0d75dff3c9b 370 if (m_textLines.size() > static_cast<list<string>::size_type>(numLines))
IanBenzMaxim 0:33d4e66780c0 371 m_textLines.resize(numLines);
IanBenzMaxim 0:33d4e66780c0 372 std::for_each(m_textLines.begin(), m_textLines.end(), TrimString(lineLen));
IanBenzMaxim 0:33d4e66780c0 373 }