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:
Fri Jan 19 10:28:27 2018 -0600
Revision:
15:75404fab3615
Parent:
13:6a6225690c2e
Updated MaximInterface revision.

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 13:6a6225690c2e 51 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // ' '
IanBenzMaxim 13:6a6225690c2e 52 {0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x20}, // '!'
IanBenzMaxim 13:6a6225690c2e 53 {0x50, 0x50, 0x50, 0x00, 0x00, 0x00, 0x00}, // '"'
IanBenzMaxim 13:6a6225690c2e 54 {0x50, 0x50, 0xF8, 0x50, 0xF8, 0x50, 0x50}, // '#'
IanBenzMaxim 13:6a6225690c2e 55 {0x20, 0x78, 0xA0, 0x70, 0x28, 0xF0, 0x20}, // '$'
IanBenzMaxim 13:6a6225690c2e 56 {0xC0, 0xC8, 0x10, 0x20, 0x40, 0x98, 0x18}, // '%'
IanBenzMaxim 13:6a6225690c2e 57 {0x60, 0x90, 0xA0, 0x40, 0xA8, 0x90, 0x68}, // '&'
IanBenzMaxim 13:6a6225690c2e 58 {0x60, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00}, // '''
IanBenzMaxim 13:6a6225690c2e 59 {0x10, 0x20, 0x40, 0x40, 0x40, 0x20, 0x10}, // '('
IanBenzMaxim 13:6a6225690c2e 60 {0x40, 0x20, 0x10, 0x10, 0x10, 0x20, 0x40}, // ')'
IanBenzMaxim 13:6a6225690c2e 61 {0x00, 0x20, 0xA8, 0x70, 0xA8, 0x20, 0x00}, // '*'
IanBenzMaxim 13:6a6225690c2e 62 {0x00, 0x20, 0x20, 0xF8, 0x20, 0x20, 0x00}, // '+'
IanBenzMaxim 13:6a6225690c2e 63 {0x00, 0x00, 0x00, 0x00, 0x60, 0x20, 0x40}, // ','
IanBenzMaxim 13:6a6225690c2e 64 {0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00}, // '-'
IanBenzMaxim 13:6a6225690c2e 65 {0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x60}, // '.'
IanBenzMaxim 13:6a6225690c2e 66 {0x00, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00}, // '/'
IanBenzMaxim 13:6a6225690c2e 67 {0x70, 0x88, 0x98, 0xA8, 0xC8, 0x88, 0x70}, // '0'
IanBenzMaxim 13:6a6225690c2e 68 {0x20, 0x60, 0x20, 0x20, 0x20, 0x20, 0x70}, // '1'
IanBenzMaxim 13:6a6225690c2e 69 {0x70, 0x88, 0x08, 0x10, 0x20, 0x40, 0xF8}, // '2'
IanBenzMaxim 13:6a6225690c2e 70 {0xF8, 0x10, 0x20, 0x10, 0x08, 0x88, 0x70}, // '3'
IanBenzMaxim 13:6a6225690c2e 71 {0x10, 0x30, 0x50, 0x90, 0xF8, 0x10, 0x10}, // '4'
IanBenzMaxim 13:6a6225690c2e 72 {0xF8, 0x80, 0xF0, 0x08, 0x08, 0x88, 0x70}, // '5'
IanBenzMaxim 13:6a6225690c2e 73 {0x30, 0x40, 0x80, 0xF0, 0x88, 0x88, 0x70}, // '6'
IanBenzMaxim 13:6a6225690c2e 74 {0xF8, 0x08, 0x10, 0x20, 0x40, 0x40, 0x40}, // '7'
IanBenzMaxim 13:6a6225690c2e 75 {0x70, 0x88, 0x88, 0x70, 0x88, 0x88, 0x70}, // '8'
IanBenzMaxim 13:6a6225690c2e 76 {0x70, 0x88, 0x88, 0x78, 0x08, 0x10, 0x60}, // '9'
IanBenzMaxim 13:6a6225690c2e 77 {0x00, 0x60, 0x60, 0x00, 0x60, 0x60, 0x00}, // ':'
IanBenzMaxim 13:6a6225690c2e 78 {0x00, 0x60, 0x60, 0x00, 0x60, 0x20, 0x40}, // ';'
IanBenzMaxim 13:6a6225690c2e 79 {0x10, 0x20, 0x40, 0x80, 0x40, 0x20, 0x10}, // '<'
IanBenzMaxim 13:6a6225690c2e 80 {0x00, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0x00}, // '='
IanBenzMaxim 13:6a6225690c2e 81 {0x40, 0x20, 0x10, 0x08, 0x10, 0x20, 0x40}, // '>'
IanBenzMaxim 13:6a6225690c2e 82 {0x70, 0x88, 0x08, 0x10, 0x20, 0x00, 0x20}, // '?'
IanBenzMaxim 13:6a6225690c2e 83 {0x70, 0x88, 0x08, 0x68, 0xA8, 0xA8, 0x70}, // '@'
IanBenzMaxim 13:6a6225690c2e 84 {0x70, 0x88, 0x88, 0x88, 0xF8, 0x88, 0x88}, // 'A'
IanBenzMaxim 13:6a6225690c2e 85 {0xF0, 0x88, 0x88, 0xF0, 0x88, 0x88, 0xF0}, // 'B'
IanBenzMaxim 13:6a6225690c2e 86 {0x70, 0x88, 0x80, 0x80, 0x80, 0x88, 0x70}, // 'C'
IanBenzMaxim 13:6a6225690c2e 87 {0xE0, 0x90, 0x88, 0x88, 0x88, 0x90, 0xE0}, // 'D'
IanBenzMaxim 13:6a6225690c2e 88 {0xF8, 0x80, 0x80, 0xF0, 0x80, 0x80, 0xF8}, // 'E'
IanBenzMaxim 13:6a6225690c2e 89 {0xF8, 0x80, 0x80, 0xF0, 0x80, 0x80, 0x80}, // 'F'
IanBenzMaxim 13:6a6225690c2e 90 {0x70, 0x88, 0x80, 0xB8, 0x88, 0x88, 0x78}, // 'G'
IanBenzMaxim 13:6a6225690c2e 91 {0x88, 0x88, 0x88, 0xF8, 0x88, 0x88, 0x88}, // 'H'
IanBenzMaxim 13:6a6225690c2e 92 {0x70, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70}, // 'I'
IanBenzMaxim 13:6a6225690c2e 93 {0x38, 0x10, 0x10, 0x10, 0x10, 0x90, 0x60}, // 'J'
IanBenzMaxim 13:6a6225690c2e 94 {0x88, 0x90, 0xA0, 0xC0, 0xA0, 0x90, 0x88}, // 'K'
IanBenzMaxim 13:6a6225690c2e 95 {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xF8}, // 'L'
IanBenzMaxim 13:6a6225690c2e 96 {0x88, 0xD8, 0xA8, 0xA8, 0x88, 0x88, 0x88}, // 'M'
IanBenzMaxim 13:6a6225690c2e 97 {0x88, 0x88, 0xC8, 0xA8, 0x98, 0x88, 0x88}, // 'N'
IanBenzMaxim 13:6a6225690c2e 98 {0x70, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70}, // 'O'
IanBenzMaxim 13:6a6225690c2e 99 {0xF0, 0x88, 0x88, 0xF0, 0x80, 0x80, 0x80}, // 'P'
IanBenzMaxim 13:6a6225690c2e 100 {0x70, 0x88, 0x88, 0x88, 0xA8, 0x90, 0x68}, // 'Q'
IanBenzMaxim 13:6a6225690c2e 101 {0xF0, 0x88, 0x88, 0xF0, 0xA0, 0x90, 0x88}, // 'R'
IanBenzMaxim 13:6a6225690c2e 102 {0x78, 0x80, 0x80, 0x70, 0x08, 0x08, 0xF0}, // 'S'
IanBenzMaxim 13:6a6225690c2e 103 {0xF8, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20}, // 'T'
IanBenzMaxim 13:6a6225690c2e 104 {0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x70}, // 'U'
IanBenzMaxim 13:6a6225690c2e 105 {0x88, 0x88, 0x88, 0x88, 0x88, 0x50, 0x20}, // 'V'
IanBenzMaxim 13:6a6225690c2e 106 {0x88, 0x88, 0x88, 0xA8, 0xA8, 0xA8, 0x50}, // 'W'
IanBenzMaxim 13:6a6225690c2e 107 {0x88, 0x88, 0x50, 0x20, 0x50, 0x88, 0x88}, // 'X'
IanBenzMaxim 13:6a6225690c2e 108 {0x88, 0x88, 0x88, 0x50, 0x20, 0x20, 0x20}, // 'Y'
IanBenzMaxim 13:6a6225690c2e 109 {0xF8, 0x08, 0x10, 0x20, 0x40, 0x80, 0xF8}, // 'Z'
IanBenzMaxim 13:6a6225690c2e 110 {0x70, 0x40, 0x40, 0x40, 0x40, 0x40, 0x70}, // '['
IanBenzMaxim 13:6a6225690c2e 111 {0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x00}, // '\'
IanBenzMaxim 13:6a6225690c2e 112 {0x70, 0x10, 0x10, 0x10, 0x10, 0x10, 0x70}, // ']'
IanBenzMaxim 13:6a6225690c2e 113 {0x20, 0x50, 0x88, 0x00, 0x00, 0x00, 0x00}, // '^'
IanBenzMaxim 13:6a6225690c2e 114 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8}, // '_'
IanBenzMaxim 13:6a6225690c2e 115 {0x40, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00}, // '`'
IanBenzMaxim 13:6a6225690c2e 116 {0x00, 0x00, 0x70, 0x08, 0x78, 0x88, 0x78}, // 'a'
IanBenzMaxim 13:6a6225690c2e 117 {0x80, 0x80, 0xB0, 0xC8, 0x88, 0x88, 0xF0}, // 'b'
IanBenzMaxim 13:6a6225690c2e 118 {0x00, 0x00, 0x70, 0x80, 0x80, 0x88, 0x70}, // 'c'
IanBenzMaxim 13:6a6225690c2e 119 {0x08, 0x08, 0x68, 0x98, 0x88, 0x88, 0x78}, // 'd'
IanBenzMaxim 13:6a6225690c2e 120 {0x00, 0x00, 0x70, 0x88, 0xF8, 0x80, 0x70}, // 'e'
IanBenzMaxim 13:6a6225690c2e 121 {0x30, 0x48, 0x40, 0xE0, 0x40, 0x40, 0x40}, // 'f'
IanBenzMaxim 13:6a6225690c2e 122 {0x00, 0x78, 0x88, 0x88, 0x78, 0x08, 0x70}, // 'g'
IanBenzMaxim 13:6a6225690c2e 123 {0x80, 0x80, 0xB0, 0xC8, 0x88, 0x88, 0x88}, // 'h'
IanBenzMaxim 13:6a6225690c2e 124 {0x20, 0x00, 0x60, 0x20, 0x20, 0x20, 0x70}, // 'i'
IanBenzMaxim 13:6a6225690c2e 125 {0x10, 0x00, 0x30, 0x10, 0x10, 0x90, 0x60}, // 'j'
IanBenzMaxim 13:6a6225690c2e 126 {0x80, 0x80, 0x90, 0xA0, 0xC0, 0xA0, 0x90}, // 'k'
IanBenzMaxim 13:6a6225690c2e 127 {0x60, 0x20, 0x20, 0x20, 0x20, 0x20, 0x70}, // 'l'
IanBenzMaxim 13:6a6225690c2e 128 {0x00, 0x00, 0xD0, 0xA8, 0xA8, 0x88, 0x88}, // 'm'
IanBenzMaxim 13:6a6225690c2e 129 {0x00, 0x00, 0xB0, 0xC8, 0x88, 0x88, 0x88}, // 'n'
IanBenzMaxim 13:6a6225690c2e 130 {0x00, 0x00, 0x70, 0x88, 0x88, 0x88, 0x70}, // 'o'
IanBenzMaxim 13:6a6225690c2e 131 {0x00, 0x00, 0xF0, 0x88, 0xF0, 0x80, 0x80}, // 'p'
IanBenzMaxim 13:6a6225690c2e 132 {0x00, 0x00, 0x68, 0x98, 0x78, 0x08, 0x08}, // 'q'
IanBenzMaxim 13:6a6225690c2e 133 {0x00, 0x00, 0xB0, 0xC8, 0x80, 0x80, 0x80}, // 'r'
IanBenzMaxim 13:6a6225690c2e 134 {0x00, 0x00, 0x70, 0x80, 0x70, 0x08, 0xF0}, // 's'
IanBenzMaxim 13:6a6225690c2e 135 {0x40, 0x40, 0xE0, 0x40, 0x40, 0x48, 0x30}, // 't'
IanBenzMaxim 13:6a6225690c2e 136 {0x00, 0x00, 0x88, 0x88, 0x88, 0x98, 0x68}, // 'u'
IanBenzMaxim 13:6a6225690c2e 137 {0x00, 0x00, 0x88, 0x88, 0x88, 0x41, 0x20}, // 'v'
IanBenzMaxim 13:6a6225690c2e 138 {0x00, 0x00, 0x88, 0x88, 0xA8, 0xA8, 0x50}, // 'w'
IanBenzMaxim 13:6a6225690c2e 139 {0x00, 0x00, 0x88, 0x50, 0x20, 0x50, 0x88}, // 'x'
IanBenzMaxim 13:6a6225690c2e 140 {0x00, 0x00, 0x88, 0x88, 0x78, 0x08, 0x70}, // 'y'
IanBenzMaxim 13:6a6225690c2e 141 {0x00, 0x00, 0xF8, 0x10, 0x20, 0x40, 0xF8}, // 'z'
IanBenzMaxim 13:6a6225690c2e 142 {0x10, 0x20, 0x20, 0x40, 0x20, 0x20, 0x10}, // '{'
IanBenzMaxim 13:6a6225690c2e 143 {0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20}, // '|'
IanBenzMaxim 13:6a6225690c2e 144 {0x40, 0x20, 0x20, 0x10, 0x20, 0x20, 0x40}, // '}'
IanBenzMaxim 13:6a6225690c2e 145 {0x00, 0x00, 0x40, 0xA8, 0x10, 0x00, 0x00} // '~'
IanBenzMaxim 0:33d4e66780c0 146 };
IanBenzMaxim 0:33d4e66780c0 147
IanBenzMaxim 13:6a6225690c2e 148 static bool charPrintable(unsigned char c) {
IanBenzMaxim 13:6a6225690c2e 149 return (c >= printableCharBegin) && (c <= printableCharEnd);
IanBenzMaxim 0:33d4e66780c0 150 }
IanBenzMaxim 0:33d4e66780c0 151
IanBenzMaxim 13:6a6225690c2e 152 static void removeNonprintableChars(string & s) {
IanBenzMaxim 13:6a6225690c2e 153 s.erase(std::remove_if(s.begin(), s.end(),
IanBenzMaxim 13:6a6225690c2e 154 std::not1(std::ptr_fun(charPrintable))),
IanBenzMaxim 13:6a6225690c2e 155 s.end());
IanBenzMaxim 0:33d4e66780c0 156 }
IanBenzMaxim 0:33d4e66780c0 157
IanBenzMaxim 13:6a6225690c2e 158 static bool compareStringLength(const string & a, const string & b) {
IanBenzMaxim 13:6a6225690c2e 159 return a.length() < b.length();
IanBenzMaxim 0:33d4e66780c0 160 }
IanBenzMaxim 0:33d4e66780c0 161
IanBenzMaxim 13:6a6225690c2e 162 namespace {
IanBenzMaxim 13:6a6225690c2e 163
IanBenzMaxim 0:33d4e66780c0 164 // Functor trims string if it exceeds a certain length.
IanBenzMaxim 13:6a6225690c2e 165 class TrimString {
IanBenzMaxim 0:33d4e66780c0 166 public:
IanBenzMaxim 13:6a6225690c2e 167 TrimString(string::size_type maxSize) : maxSize(maxSize) {}
IanBenzMaxim 13:6a6225690c2e 168
IanBenzMaxim 13:6a6225690c2e 169 void operator()(string & s) {
IanBenzMaxim 13:6a6225690c2e 170 if (s.size() > maxSize) {
IanBenzMaxim 13:6a6225690c2e 171 s.resize(maxSize);
IanBenzMaxim 0:33d4e66780c0 172 }
IanBenzMaxim 13:6a6225690c2e 173 }
IanBenzMaxim 13:6a6225690c2e 174
IanBenzMaxim 0:33d4e66780c0 175 private:
IanBenzMaxim 13:6a6225690c2e 176 string::size_type maxSize;
IanBenzMaxim 0:33d4e66780c0 177 };
IanBenzMaxim 0:33d4e66780c0 178
IanBenzMaxim 13:6a6225690c2e 179 } // namespace
IanBenzMaxim 13:6a6225690c2e 180
IanBenzMaxim 0:33d4e66780c0 181 // Split a string based on a character token. Token will be removed.
IanBenzMaxim 13:6a6225690c2e 182 static std::list<string> tokenizeString(const string & toSplit, char token) {
IanBenzMaxim 13:6a6225690c2e 183 std::list<string> toSplitLines;
IanBenzMaxim 13:6a6225690c2e 184 string::size_type beginIdx = 0, endIdx;
IanBenzMaxim 13:6a6225690c2e 185 do {
IanBenzMaxim 13:6a6225690c2e 186 endIdx = toSplit.find(token, beginIdx);
IanBenzMaxim 13:6a6225690c2e 187 toSplitLines.push_back(toSplit.substr(
IanBenzMaxim 13:6a6225690c2e 188 beginIdx, endIdx == string::npos ? string::npos : endIdx - beginIdx));
IanBenzMaxim 13:6a6225690c2e 189 beginIdx = endIdx + 1;
IanBenzMaxim 13:6a6225690c2e 190 } while (endIdx != string::npos);
IanBenzMaxim 13:6a6225690c2e 191 return toSplitLines;
IanBenzMaxim 0:33d4e66780c0 192 }
IanBenzMaxim 0:33d4e66780c0 193
IanBenzMaxim 0:33d4e66780c0 194 // Word wrap string into lines based on a specified line length.
IanBenzMaxim 13:6a6225690c2e 195 static std::list<string> wrapLines(const string & toSplit,
IanBenzMaxim 13:6a6225690c2e 196 const string::size_type lineLen) {
IanBenzMaxim 13:6a6225690c2e 197 std::list<string> toSplitLines;
IanBenzMaxim 13:6a6225690c2e 198 string::size_type beginIdx = 0;
IanBenzMaxim 13:6a6225690c2e 199 if (lineLen > 0) {
IanBenzMaxim 13:6a6225690c2e 200 // Split lines as much as necessary.
IanBenzMaxim 13:6a6225690c2e 201 string::size_type endIdx = lineLen;
IanBenzMaxim 13:6a6225690c2e 202 while (((toSplit.length() - beginIdx) > lineLen) &&
IanBenzMaxim 13:6a6225690c2e 203 (endIdx != string::npos)) {
IanBenzMaxim 13:6a6225690c2e 204 endIdx = toSplit.rfind(' ', endIdx);
IanBenzMaxim 13:6a6225690c2e 205 if ((endIdx == string::npos) || (endIdx <= beginIdx)) {
IanBenzMaxim 13:6a6225690c2e 206 // Current word is too long to split. Find end of current word.
IanBenzMaxim 13:6a6225690c2e 207 endIdx = toSplit.find(' ', beginIdx);
IanBenzMaxim 13:6a6225690c2e 208 }
IanBenzMaxim 13:6a6225690c2e 209 if (endIdx != string::npos) {
IanBenzMaxim 13:6a6225690c2e 210 toSplitLines.push_back(toSplit.substr(beginIdx, endIdx - beginIdx));
IanBenzMaxim 13:6a6225690c2e 211 beginIdx = endIdx + 1;
IanBenzMaxim 13:6a6225690c2e 212 endIdx = beginIdx + lineLen;
IanBenzMaxim 13:6a6225690c2e 213 }
IanBenzMaxim 0:33d4e66780c0 214 }
IanBenzMaxim 13:6a6225690c2e 215 }
IanBenzMaxim 13:6a6225690c2e 216 // Last line is any remaining characters.
IanBenzMaxim 13:6a6225690c2e 217 toSplitLines.push_back(toSplit.substr(beginIdx, toSplit.length() - beginIdx));
IanBenzMaxim 13:6a6225690c2e 218 return toSplitLines;
IanBenzMaxim 0:33d4e66780c0 219 }
IanBenzMaxim 0:33d4e66780c0 220
IanBenzMaxim 13:6a6225690c2e 221 Text::Text()
IanBenzMaxim 13:6a6225690c2e 222 : m_text(), m_wordWrap(false), m_charSpacing(1), m_lineSpacing(1),
IanBenzMaxim 13:6a6225690c2e 223 m_textLines(), m_preferredWidth(invalidWidthHeight),
IanBenzMaxim 13:6a6225690c2e 224 m_preferredHeight(invalidWidthHeight) {}
IanBenzMaxim 0:33d4e66780c0 225
IanBenzMaxim 13:6a6225690c2e 226 void Text::setText(const string & text) {
IanBenzMaxim 13:6a6225690c2e 227 if (m_text != text) {
IanBenzMaxim 13:6a6225690c2e 228 m_text = text;
IanBenzMaxim 13:6a6225690c2e 229 invalidate();
IanBenzMaxim 13:6a6225690c2e 230 m_preferredWidth = m_preferredHeight = invalidWidthHeight;
IanBenzMaxim 13:6a6225690c2e 231 }
IanBenzMaxim 0:33d4e66780c0 232 }
IanBenzMaxim 0:33d4e66780c0 233
IanBenzMaxim 13:6a6225690c2e 234 void Text::setWordWrap(bool wordWrap) {
IanBenzMaxim 13:6a6225690c2e 235 if (m_wordWrap != wordWrap) {
IanBenzMaxim 13:6a6225690c2e 236 m_wordWrap = wordWrap;
IanBenzMaxim 13:6a6225690c2e 237 invalidate();
IanBenzMaxim 13:6a6225690c2e 238 m_preferredWidth = m_preferredHeight = invalidWidthHeight;
IanBenzMaxim 13:6a6225690c2e 239 }
IanBenzMaxim 0:33d4e66780c0 240 }
IanBenzMaxim 0:33d4e66780c0 241
IanBenzMaxim 13:6a6225690c2e 242 void Text::setLineSpacing(int lineSpacing) {
IanBenzMaxim 13:6a6225690c2e 243 if (lineSpacing > 0 && m_lineSpacing != lineSpacing) {
IanBenzMaxim 13:6a6225690c2e 244 m_lineSpacing = lineSpacing;
IanBenzMaxim 13:6a6225690c2e 245 invalidate();
IanBenzMaxim 13:6a6225690c2e 246 m_preferredHeight = invalidWidthHeight;
IanBenzMaxim 13:6a6225690c2e 247 }
IanBenzMaxim 8:a0d75dff3c9b 248 }
IanBenzMaxim 8:a0d75dff3c9b 249
IanBenzMaxim 13:6a6225690c2e 250 void Text::setCharSpacing(int charSpacing) {
IanBenzMaxim 13:6a6225690c2e 251 if (charSpacing > 0 && m_charSpacing != charSpacing) {
IanBenzMaxim 13:6a6225690c2e 252 m_charSpacing = charSpacing;
IanBenzMaxim 13:6a6225690c2e 253 invalidate();
IanBenzMaxim 13:6a6225690c2e 254 m_preferredWidth = invalidWidthHeight;
IanBenzMaxim 13:6a6225690c2e 255 if (wordWrap()) {
IanBenzMaxim 13:6a6225690c2e 256 m_preferredHeight = invalidWidthHeight;
IanBenzMaxim 0:33d4e66780c0 257 }
IanBenzMaxim 13:6a6225690c2e 258 }
IanBenzMaxim 0:33d4e66780c0 259 }
IanBenzMaxim 0:33d4e66780c0 260
IanBenzMaxim 13:6a6225690c2e 261 int Text::preferredWidth() const {
IanBenzMaxim 13:6a6225690c2e 262 if (m_preferredWidth == invalidWidthHeight) {
IanBenzMaxim 13:6a6225690c2e 263 calculateLayout();
IanBenzMaxim 13:6a6225690c2e 264 }
IanBenzMaxim 13:6a6225690c2e 265 return m_preferredWidth;
IanBenzMaxim 13:6a6225690c2e 266 }
IanBenzMaxim 13:6a6225690c2e 267
IanBenzMaxim 13:6a6225690c2e 268 int Text::preferredHeight() const {
IanBenzMaxim 13:6a6225690c2e 269 if (m_preferredHeight == invalidWidthHeight) {
IanBenzMaxim 13:6a6225690c2e 270 calculateLayout();
IanBenzMaxim 13:6a6225690c2e 271 }
IanBenzMaxim 13:6a6225690c2e 272 return m_preferredHeight;
IanBenzMaxim 8:a0d75dff3c9b 273 }
IanBenzMaxim 8:a0d75dff3c9b 274
IanBenzMaxim 13:6a6225690c2e 275 void Text::resized() {
IanBenzMaxim 13:6a6225690c2e 276 m_preferredWidth = invalidWidthHeight;
IanBenzMaxim 13:6a6225690c2e 277 if (wordWrap()) {
IanBenzMaxim 13:6a6225690c2e 278 m_preferredHeight = invalidWidthHeight;
IanBenzMaxim 13:6a6225690c2e 279 }
IanBenzMaxim 0:33d4e66780c0 280 }
IanBenzMaxim 8:a0d75dff3c9b 281
IanBenzMaxim 13:6a6225690c2e 282 void Text::doRender(Bitmap & bitmap, int xOffset, int yOffset) const {
IanBenzMaxim 13:6a6225690c2e 283 using std::list;
IanBenzMaxim 13:6a6225690c2e 284
IanBenzMaxim 13:6a6225690c2e 285 // Ensure layout is up to date.
IanBenzMaxim 13:6a6225690c2e 286 if (m_preferredWidth == invalidWidthHeight ||
IanBenzMaxim 13:6a6225690c2e 287 m_preferredHeight == invalidWidthHeight) {
IanBenzMaxim 13:6a6225690c2e 288 calculateLayout();
IanBenzMaxim 13:6a6225690c2e 289 }
IanBenzMaxim 13:6a6225690c2e 290
IanBenzMaxim 13:6a6225690c2e 291 // Render each line.
IanBenzMaxim 13:6a6225690c2e 292 int lineNum = 0;
IanBenzMaxim 13:6a6225690c2e 293 for (list<string>::const_iterator lineIt = m_textLines.begin();
IanBenzMaxim 13:6a6225690c2e 294 lineIt != m_textLines.end(); lineIt++) {
IanBenzMaxim 13:6a6225690c2e 295 // Render each character.
IanBenzMaxim 13:6a6225690c2e 296 for (string::size_type charNum = 0; charNum < lineIt->length(); charNum++) {
IanBenzMaxim 13:6a6225690c2e 297 bitmap.overlay(xOffset + x() + charNum * (characterWidth + m_charSpacing),
IanBenzMaxim 13:6a6225690c2e 298 yOffset + y() +
IanBenzMaxim 13:6a6225690c2e 299 lineNum * (characterHeight + m_lineSpacing),
IanBenzMaxim 13:6a6225690c2e 300 &characterMap[(*lineIt)[charNum] - printableCharBegin][0],
IanBenzMaxim 13:6a6225690c2e 301 characterHeight, characterWidth);
IanBenzMaxim 8:a0d75dff3c9b 302 }
IanBenzMaxim 13:6a6225690c2e 303 lineNum++;
IanBenzMaxim 13:6a6225690c2e 304 }
IanBenzMaxim 8:a0d75dff3c9b 305 }
IanBenzMaxim 8:a0d75dff3c9b 306
IanBenzMaxim 13:6a6225690c2e 307 void Text::calculateLayout() const {
IanBenzMaxim 13:6a6225690c2e 308 using std::list;
IanBenzMaxim 13:6a6225690c2e 309
IanBenzMaxim 13:6a6225690c2e 310 // Split string into lines.
IanBenzMaxim 13:6a6225690c2e 311 m_textLines = tokenizeString(m_text, '\n');
IanBenzMaxim 13:6a6225690c2e 312
IanBenzMaxim 13:6a6225690c2e 313 // Remove non-printable characters.
IanBenzMaxim 13:6a6225690c2e 314 std::for_each(m_textLines.begin(), m_textLines.end(),
IanBenzMaxim 13:6a6225690c2e 315 removeNonprintableChars);
IanBenzMaxim 13:6a6225690c2e 316
IanBenzMaxim 13:6a6225690c2e 317 const int lineLen =
IanBenzMaxim 13:6a6225690c2e 318 (width() / (characterWidth + m_charSpacing)) +
IanBenzMaxim 13:6a6225690c2e 319 (((width() % (characterWidth + m_charSpacing)) >= characterWidth) ? 1
IanBenzMaxim 13:6a6225690c2e 320 : 0);
IanBenzMaxim 13:6a6225690c2e 321 const int numLines =
IanBenzMaxim 13:6a6225690c2e 322 (height() / (characterHeight + m_lineSpacing)) +
IanBenzMaxim 13:6a6225690c2e 323 (((height() % (characterHeight + m_lineSpacing)) >= characterHeight) ? 1
IanBenzMaxim 13:6a6225690c2e 324 : 0);
IanBenzMaxim 13:6a6225690c2e 325
IanBenzMaxim 13:6a6225690c2e 326 // Word wrap lines if enabled.
IanBenzMaxim 13:6a6225690c2e 327 if (m_wordWrap) {
IanBenzMaxim 13:6a6225690c2e 328 list<string>::iterator lineIt = m_textLines.begin();
IanBenzMaxim 13:6a6225690c2e 329 while (lineIt != m_textLines.end()) {
IanBenzMaxim 13:6a6225690c2e 330 list<string>::iterator nextLineIt = lineIt;
IanBenzMaxim 13:6a6225690c2e 331 nextLineIt++;
IanBenzMaxim 0:33d4e66780c0 332
IanBenzMaxim 13:6a6225690c2e 333 // Wrap current line.
IanBenzMaxim 13:6a6225690c2e 334 list<string> wrappedLines = wrapLines(*lineIt, lineLen);
IanBenzMaxim 13:6a6225690c2e 335 m_textLines.splice(lineIt, wrappedLines);
IanBenzMaxim 13:6a6225690c2e 336 // Remove old line.
IanBenzMaxim 13:6a6225690c2e 337 m_textLines.erase(lineIt);
IanBenzMaxim 13:6a6225690c2e 338
IanBenzMaxim 13:6a6225690c2e 339 lineIt = nextLineIt;
IanBenzMaxim 0:33d4e66780c0 340 }
IanBenzMaxim 13:6a6225690c2e 341 }
IanBenzMaxim 13:6a6225690c2e 342
IanBenzMaxim 13:6a6225690c2e 343 // Calculate preferred size.
IanBenzMaxim 13:6a6225690c2e 344 string::size_type maxLineLength =
IanBenzMaxim 13:6a6225690c2e 345 std::max_element(m_textLines.begin(), m_textLines.end(),
IanBenzMaxim 13:6a6225690c2e 346 compareStringLength)->length();
IanBenzMaxim 13:6a6225690c2e 347 m_preferredWidth = (maxLineLength > 0)
IanBenzMaxim 13:6a6225690c2e 348 ? (maxLineLength * characterWidth) +
IanBenzMaxim 13:6a6225690c2e 349 ((maxLineLength - 1) * m_charSpacing)
IanBenzMaxim 13:6a6225690c2e 350 : 1;
IanBenzMaxim 13:6a6225690c2e 351 m_preferredHeight = (m_textLines.size() * characterHeight) +
IanBenzMaxim 13:6a6225690c2e 352 ((m_textLines.size() - 1) * m_lineSpacing);
IanBenzMaxim 13:6a6225690c2e 353
IanBenzMaxim 13:6a6225690c2e 354 // Remove clipped text.
IanBenzMaxim 13:6a6225690c2e 355 if (m_textLines.size() > static_cast<list<string>::size_type>(numLines))
IanBenzMaxim 13:6a6225690c2e 356 m_textLines.resize(numLines);
IanBenzMaxim 13:6a6225690c2e 357 std::for_each(m_textLines.begin(), m_textLines.end(), TrimString(lineLen));
IanBenzMaxim 0:33d4e66780c0 358 }