├── DOCS ├── IMG_2487.png └── IMG_2488.png ├── README.md ├── SmartResponseXEmt.cpp ├── SmartResponseXEmt.h └── sketch_jul16a.ino /DOCS/IMG_2487.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chmod775/SMARTResponseTerminal/595ff4c39b27c1388e57f7e419baf5df23342d37/DOCS/IMG_2487.png -------------------------------------------------------------------------------- /DOCS/IMG_2488.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chmod775/SMARTResponseTerminal/595ff4c39b27c1388e57f7e419baf5df23342d37/DOCS/IMG_2488.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Programming 2 | To flash your SMART Response XE you have 2 options: 3 | 1) Teardown the unit and access the ICSP standard pins (shown in the top left of the photo A) 4 | 2) Use POGO Pins and the hidden JTAG interface. You can follow this [link](https://www.hackster.io/news/run-basic-on-your-smart-response-xe-2041f035529d) for the details; 5 | 6 | ## Serial interface with Single Board Computer 7 | The SMART Response XE (or, to be precise, the microcontroller ATMega1284P) does have 2 UART ports. 8 | Unfortunately RX0 and TX0 cannot be used because are used by the Keyboard Matrix. (As we can see from this very useful [Schematic](https://github.com/fdufnews/SMART-Response-XE-schematics/blob/master/Smart_Response_XE.pdf) ). 9 | So the only solution (if we don't want to lose any keys on the keyboard) is to use RX1 and TX1. 10 | 11 | This choose come with it's own drawbacks. 12 | TX1 is connected to the CS line of the onboard SPI EEPROM. 13 | 14 | But for this specific application we don't need that, so we proceed by removing R3 and connecting our TX Line to the left pad of R3 (yellow wire in photo B). 15 | For the RX Line we solder it to the left pad of R1 (which goes to the On/Off push buttons). 16 | 17 | In my precise application I've mounted an after market power-bank inside the case. So, to turn the power bank On / Off, I've used the already present push button. 18 | To avoid turning off the SMART Response XE, the component named Z1 was removed. 19 | 20 | ## Photo A 21 | ![IMG_2487.png](./DOCS/IMG_2487.png) 22 | 23 | ## Photo B 24 | ![IMG_2488.png](./DOCS/IMG_2488.png) 25 | 26 | ## Special thanks to 27 | - 28 | - 29 | - -------------------------------------------------------------------------------- /SmartResponseXEmt.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // SMART Response XE library 3 | // 4 | // LCD and keyboard routines for the SRXE handheld classroom communicator 5 | // 6 | // Copyright (c) 2018 BitBank Software, Inc. 7 | // written by Larry Bank 8 | // email: bitbank@pobox.com 9 | // Project started 8/4/2018 10 | // 11 | // Modified by Dan Geiger (Port to SMART Response XE) 12 | // 13 | // This program is free software: you can redistribute it and/or modify 14 | // it under the terms of the GNU General Public License as published by 15 | // the Free Software Foundation, either version 3 of the License, or 16 | // (at your option) any later version. 17 | // 18 | // This program is distributed in the hope that it will be useful, 19 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 20 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 | // GNU General Public License for more details. 22 | // 23 | // You should have received a copy of the GNU General Public License 24 | // along with this program. If not, see . 25 | // 26 | 27 | // 18/11/2019 fdufnews keyboard map modification 28 | // DEL --> enter (0x0D) (more intuitive position) 29 | // shift + DEL --> backspace (0x08) 30 | // SYM + I --> ; 31 | // SYM + Z --> * 32 | // SYM + X --> / 33 | // square root --> ESC 34 | // 8/12/2019 fdufnews added function to define scroll area 35 | // 36 | #include 37 | #include 38 | #include 39 | #include "SmartResponseXEmt.h" 40 | //#include 41 | 42 | // Mapping of keyboard to GPIO pins 43 | //static byte rowPins[ROWS] = {6,35,34,8,9,0}; 44 | //static byte colPins[COLS] = {4,A1,A3,2,1,25,16,19,23,22}; 45 | const uint8_t rowPins[ROWS] = {0xe6, 0xb7, 0xb6, 0xb5, 0xb4, 0xe0}; 46 | const uint8_t colPins[COLS] = {0xe4, 0xf1, 0xf3, 0xe2, 0xe1, 0xd7, 0xa0, 0xa5, 0xd5, 0xd4}; 47 | //extern static byte bKeyMap[COLS]; // bits indicating pressed keys 48 | static byte bOldKeyMap[COLS]; // previous map to look for pressed/released keys 49 | static byte bColorToByte[4] = {0, 0x49, 0x92, 0xff}; 50 | static byte iCSPin, iDCPin, iResetPin; 51 | 52 | static int iScrollOffset; 53 | static int scrollArea=LCD_HEIGHT; 54 | void SRXEFill(byte ucData); 55 | static void SRXEWriteCommand(unsigned char c); 56 | 57 | typedef enum 58 | { 59 | MODE_DATA = 0, 60 | MODE_COMMAND 61 | } DC_MODE; 62 | 63 | #ifndef HIGH 64 | #define HIGH 1 65 | #define LOW 0 66 | #define INPUT 0 67 | #define INPUT_PULLUP 1 68 | #define OUTPUT 2 69 | #endif 70 | 71 | // Chip select for the external 1Mb flash module 72 | #define CS_FLASH 0xd3 73 | 74 | //Keyboard 75 | //Logical Layout (SK# are screen keys: top to bottom 1-5 on left, 6-10 on right): 76 | // ROW1|ROW2|ROW3|ROW4|ROW5|ROW6|ROW7|ROW8|ROW9|ROW10 77 | // COL1 1| 2| 3| 4| 5| 6| 7| 8| 9| 0 78 | // COL2 Q| W| E| R| T| Y| U| I| O| P 79 | // COL3 A| S| D| F| G| H| J| K| L| Bksp 80 | // COL4 Shft| Z| X| C| V| B| N|Down|Entr| Up 81 | // COL5 Sym|Frac|Root| Exp| Spc| ,| .| M|Left|Right 82 | // COL6 SK1| SK2| SK3| SK4| SK5| SK6| SK7| SK8| SK9| SK10 83 | byte OriginalKeys[] = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 84 | 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 85 | 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', '\b', // enter (now del needs a shift) 86 | 0 , 'z', 'x', 'c', 'v', 'b', 'n', 0xe1, 0, 0xe0, // 5 = down, 4 = up 87 | 0 , '\t', '\e', 0, ' ', ',', '.', 'm', 0xe3, 0xe2, // 2 = left, 3 = right, root = ESC 88 | 0xf0, 0xf1, 0xf2, 0xf3, 0, 0xf5, 0xf6, 0xf7, 0xf8, '\n' 89 | }; 90 | byte ShiftedKeys[] = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 91 | 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', 92 | 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', '\b', 93 | 0 , 'Z', 'X', 'C', 'V', 'B', 'N', 0x5, 0, 0x4, // 5 = down 94 | 0 , '\t', '\e', 0, '_', ',', '.', 'M', 2, 3, 95 | 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, '\n' 96 | }; 97 | 98 | byte SymKeys[] = {'!', '#', '@', '$', '%', '^', '\'', '\"', '(', ')', 99 | '&', '~', '|', '`', '£', '¬', 'u', ';', '[', ']', // i = ; 100 | '=', '+', '-', 'f', 'g', 'h', 'j', ':', '?', '\b', 101 | 0 , '*', '/', 'c', 'v', 'b', 'n', 0x5, 0, 0x4, // z = *, x = / 102 | 0 , '\t', '\e' , 0 , 0x1, '<', '>', 'm', 2, 3, // 1 = menu 103 | 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, '\n' 104 | }; 105 | byte SymShiftKeys[] = {'!', '2', '3', '$', '%', '6', '\'', '\"', '{', '}', 106 | 'q', 'w', 'e', 'r', 't', 'y', 'u', ';', '[', ']', // i = ; 107 | '=', '+', '-', 'f', 'g', 'h', 'j', ':', '?', '\b', 108 | 0 , '*', '\\', 'c', 'v', 'b', 'n', 0x5, 0, 0x4, // z = *, x = / 109 | 0 , '\t', '\e' , 0 , 0x1, '<', '>', 'm', 2, 3, // 1 = menu 110 | 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, '\n' 111 | }; 112 | 113 | // 114 | // Power on the LCD 115 | // 116 | const char powerup[] PROGMEM = { 117 | 1, 0x01, // soft reset 118 | 99, 120, // 120ms delay 119 | 1, 0x11, // sleep out 120 | 1, 0x28, // display off 121 | 99, 50, // 50ms delay 122 | 3, 0xc0, 0xf8, 0x00, // Vop = 0xF0 123 | 2, 0xc3, 0x04, // BIAS = 1/14 124 | 2, 0xc4, 0x05, // Booster = x8 125 | 2, 0xd0, 0x1d, // Enable analog circuit 126 | 2, 0xb3, 0x00, // Set FOSC divider 127 | 2, 0xb5, 0x8b, // N-Line = 0 128 | 1, 0x38, // Set grayscale mode (0x39 = monochrome mode) 129 | 2, 0x3a, 0x02, // Enable DDRAM interface 130 | 2, 0x36, 0x00, // Scan direction setting 131 | 2, 0xB0, 0x9f, // Duty setting (0x87?) 132 | 5, 0xf0, 0x12, 0x12, 0x12, 0x12, // 77Hz frame rate in all temperatures 133 | 1, 0x20, // Display inversion off 134 | 1, 0x29, // Display ON 135 | 0 136 | }; 137 | 138 | // small font 139 | const byte ucFont[]PROGMEM = { 140 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x5f, 0x5f, 0x06, 0x00, 0x00, 141 | 0x00, 0x07, 0x07, 0x00, 0x07, 0x07, 0x00, 0x00, 0x14, 0x7f, 0x7f, 0x14, 0x7f, 0x7f, 0x14, 0x00, 142 | 0x24, 0x2e, 0x2a, 0x6b, 0x6b, 0x3a, 0x12, 0x00, 0x46, 0x66, 0x30, 0x18, 0x0c, 0x66, 0x62, 0x00, 143 | 0x30, 0x7a, 0x4f, 0x5d, 0x37, 0x7a, 0x48, 0x00, 0x00, 0x04, 0x07, 0x03, 0x00, 0x00, 0x00, 0x00, 144 | 0x00, 0x1c, 0x3e, 0x63, 0x41, 0x00, 0x00, 0x00, 0x00, 0x41, 0x63, 0x3e, 0x1c, 0x00, 0x00, 0x00, 145 | 0x08, 0x2a, 0x3e, 0x1c, 0x1c, 0x3e, 0x2a, 0x08, 0x00, 0x08, 0x08, 0x3e, 0x3e, 0x08, 0x08, 0x00, 146 | 0x00, 0x00, 0x80, 0xe0, 0x60, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 147 | 0x00, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x03, 0x01, 0x00, 148 | 0x3e, 0x7f, 0x59, 0x4d, 0x47, 0x7f, 0x3e, 0x00, 0x40, 0x42, 0x7f, 0x7f, 0x40, 0x40, 0x00, 0x00, 149 | 0x62, 0x73, 0x59, 0x49, 0x6f, 0x66, 0x00, 0x00, 0x22, 0x63, 0x49, 0x49, 0x7f, 0x36, 0x00, 0x00, 150 | 0x18, 0x1c, 0x16, 0x53, 0x7f, 0x7f, 0x50, 0x00, 0x27, 0x67, 0x45, 0x45, 0x7d, 0x39, 0x00, 0x00, 151 | 0x3c, 0x7e, 0x4b, 0x49, 0x79, 0x30, 0x00, 0x00, 0x03, 0x03, 0x71, 0x79, 0x0f, 0x07, 0x00, 0x00, 152 | 0x36, 0x7f, 0x49, 0x49, 0x7f, 0x36, 0x00, 0x00, 0x06, 0x4f, 0x49, 0x69, 0x3f, 0x1e, 0x00, 0x00, 153 | 0x00, 0x00, 0x00, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xe6, 0x66, 0x00, 0x00, 0x00, 154 | 0x08, 0x1c, 0x36, 0x63, 0x41, 0x00, 0x00, 0x00, 0x00, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x00, 155 | 0x00, 0x41, 0x63, 0x36, 0x1c, 0x08, 0x00, 0x00, 0x00, 0x02, 0x03, 0x59, 0x5d, 0x07, 0x02, 0x00, 156 | 0x3e, 0x7f, 0x41, 0x5d, 0x5d, 0x5f, 0x0e, 0x00, 0x7c, 0x7e, 0x13, 0x13, 0x7e, 0x7c, 0x00, 0x00, 157 | 0x41, 0x7f, 0x7f, 0x49, 0x49, 0x7f, 0x36, 0x00, 0x1c, 0x3e, 0x63, 0x41, 0x41, 0x63, 0x22, 0x00, 158 | 0x41, 0x7f, 0x7f, 0x41, 0x63, 0x3e, 0x1c, 0x00, 0x41, 0x7f, 0x7f, 0x49, 0x5d, 0x41, 0x63, 0x00, 159 | 0x41, 0x7f, 0x7f, 0x49, 0x1d, 0x01, 0x03, 0x00, 0x1c, 0x3e, 0x63, 0x41, 0x51, 0x33, 0x72, 0x00, 160 | 0x7f, 0x7f, 0x08, 0x08, 0x7f, 0x7f, 0x00, 0x00, 0x00, 0x41, 0x7f, 0x7f, 0x41, 0x00, 0x00, 0x00, 161 | 0x30, 0x70, 0x40, 0x41, 0x7f, 0x3f, 0x01, 0x00, 0x41, 0x7f, 0x7f, 0x08, 0x1c, 0x77, 0x63, 0x00, 162 | 0x41, 0x7f, 0x7f, 0x41, 0x40, 0x60, 0x70, 0x00, 0x7f, 0x7f, 0x0e, 0x1c, 0x0e, 0x7f, 0x7f, 0x00, 163 | 0x7f, 0x7f, 0x06, 0x0c, 0x18, 0x7f, 0x7f, 0x00, 0x1c, 0x3e, 0x63, 0x41, 0x63, 0x3e, 0x1c, 0x00, 164 | 0x41, 0x7f, 0x7f, 0x49, 0x09, 0x0f, 0x06, 0x00, 0x1e, 0x3f, 0x21, 0x31, 0x61, 0x7f, 0x5e, 0x00, 165 | 0x41, 0x7f, 0x7f, 0x09, 0x19, 0x7f, 0x66, 0x00, 0x26, 0x6f, 0x4d, 0x49, 0x59, 0x73, 0x32, 0x00, 166 | 0x03, 0x41, 0x7f, 0x7f, 0x41, 0x03, 0x00, 0x00, 0x7f, 0x7f, 0x40, 0x40, 0x7f, 0x7f, 0x00, 0x00, 167 | 0x1f, 0x3f, 0x60, 0x60, 0x3f, 0x1f, 0x00, 0x00, 0x3f, 0x7f, 0x60, 0x30, 0x60, 0x7f, 0x3f, 0x00, 168 | 0x63, 0x77, 0x1c, 0x08, 0x1c, 0x77, 0x63, 0x00, 0x07, 0x4f, 0x78, 0x78, 0x4f, 0x07, 0x00, 0x00, 169 | 0x47, 0x63, 0x71, 0x59, 0x4d, 0x67, 0x73, 0x00, 0x00, 0x7f, 0x7f, 0x41, 0x41, 0x00, 0x00, 0x00, 170 | 0x01, 0x03, 0x06, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x00, 0x41, 0x41, 0x7f, 0x7f, 0x00, 0x00, 0x00, 171 | 0x08, 0x0c, 0x06, 0x03, 0x06, 0x0c, 0x08, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 172 | 0x00, 0x00, 0x03, 0x07, 0x04, 0x00, 0x00, 0x00, 0x20, 0x74, 0x54, 0x54, 0x3c, 0x78, 0x40, 0x00, 173 | 0x41, 0x7f, 0x3f, 0x48, 0x48, 0x78, 0x30, 0x00, 0x38, 0x7c, 0x44, 0x44, 0x6c, 0x28, 0x00, 0x00, 174 | 0x30, 0x78, 0x48, 0x49, 0x3f, 0x7f, 0x40, 0x00, 0x38, 0x7c, 0x54, 0x54, 0x5c, 0x18, 0x00, 0x00, 175 | 0x48, 0x7e, 0x7f, 0x49, 0x03, 0x06, 0x00, 0x00, 0x98, 0xbc, 0xa4, 0xa4, 0xf8, 0x7c, 0x04, 0x00, 176 | 0x41, 0x7f, 0x7f, 0x08, 0x04, 0x7c, 0x78, 0x00, 0x00, 0x44, 0x7d, 0x7d, 0x40, 0x00, 0x00, 0x00, 177 | 0x60, 0xe0, 0x80, 0x84, 0xfd, 0x7d, 0x00, 0x00, 0x41, 0x7f, 0x7f, 0x10, 0x38, 0x6c, 0x44, 0x00, 178 | 0x00, 0x41, 0x7f, 0x7f, 0x40, 0x00, 0x00, 0x00, 0x7c, 0x7c, 0x18, 0x78, 0x1c, 0x7c, 0x78, 0x00, 179 | 0x7c, 0x78, 0x04, 0x04, 0x7c, 0x78, 0x00, 0x00, 0x38, 0x7c, 0x44, 0x44, 0x7c, 0x38, 0x00, 0x00, 180 | 0x84, 0xfc, 0xf8, 0xa4, 0x24, 0x3c, 0x18, 0x00, 0x18, 0x3c, 0x24, 0xa4, 0xf8, 0xfc, 0x84, 0x00, 181 | 0x44, 0x7c, 0x78, 0x4c, 0x04, 0x0c, 0x18, 0x00, 0x48, 0x5c, 0x54, 0x74, 0x64, 0x24, 0x00, 0x00, 182 | 0x04, 0x04, 0x3e, 0x7f, 0x44, 0x24, 0x00, 0x00, 0x3c, 0x7c, 0x40, 0x40, 0x3c, 0x7c, 0x40, 0x00, 183 | 0x1c, 0x3c, 0x60, 0x60, 0x3c, 0x1c, 0x00, 0x00, 0x3c, 0x7c, 0x60, 0x30, 0x60, 0x7c, 0x3c, 0x00, 184 | 0x44, 0x6c, 0x38, 0x10, 0x38, 0x6c, 0x44, 0x00, 0x9c, 0xbc, 0xa0, 0xa0, 0xfc, 0x7c, 0x00, 0x00, 185 | 0x4c, 0x64, 0x74, 0x5c, 0x4c, 0x64, 0x00, 0x00, 0x08, 0x08, 0x3e, 0x77, 0x41, 0x41, 0x00, 0x00, 186 | 0x00, 0x00, 0x00, 0x77, 0x77, 0x00, 0x00, 0x00, 0x41, 0x41, 0x77, 0x3e, 0x08, 0x08, 0x00, 0x00, 187 | 0x02, 0x03, 0x01, 0x03, 0x02, 0x03, 0x01, 0x00, 0x70, 0x78, 0x4c, 0x46, 0x4c, 0x78, 0x70, 0x00 188 | }; 189 | 190 | // 5x7 font (in 6x8 cell) 191 | const unsigned char ucSmallFont[]PROGMEM = { 192 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x5f, 0x06, 0x00, 0x00, 0x07, 0x03, 0x00, 193 | 0x07, 0x03, 0x00, 0x24, 0x7e, 0x24, 0x7e, 0x24, 0x00, 0x24, 0x2b, 0x6a, 0x12, 0x00, 0x00, 0x63, 194 | 0x13, 0x08, 0x64, 0x63, 0x00, 0x36, 0x49, 0x56, 0x20, 0x50, 0x00, 0x00, 0x07, 0x03, 0x00, 0x00, 195 | 0x00, 0x00, 0x3e, 0x41, 0x00, 0x00, 0x00, 0x00, 0x41, 0x3e, 0x00, 0x00, 0x00, 0x08, 0x3e, 0x1c, 196 | 0x3e, 0x08, 0x00, 0x08, 0x08, 0x3e, 0x08, 0x08, 0x00, 0x00, 0xe0, 0x60, 0x00, 0x00, 0x00, 0x08, 197 | 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 198 | 0x00, 0x3e, 0x51, 0x49, 0x45, 0x3e, 0x00, 0x00, 0x42, 0x7f, 0x40, 0x00, 0x00, 0x62, 0x51, 0x49, 199 | 0x49, 0x46, 0x00, 0x22, 0x49, 0x49, 0x49, 0x36, 0x00, 0x18, 0x14, 0x12, 0x7f, 0x10, 0x00, 0x2f, 200 | 0x49, 0x49, 0x49, 0x31, 0x00, 0x3c, 0x4a, 0x49, 0x49, 0x30, 0x00, 0x01, 0x71, 0x09, 0x05, 0x03, 201 | 0x00, 0x36, 0x49, 0x49, 0x49, 0x36, 0x00, 0x06, 0x49, 0x49, 0x29, 0x1e, 0x00, 0x00, 0x6c, 0x6c, 202 | 0x00, 0x00, 0x00, 0x00, 0xec, 0x6c, 0x00, 0x00, 0x00, 0x08, 0x14, 0x22, 0x41, 0x00, 0x00, 0x24, 203 | 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x41, 0x22, 0x14, 0x08, 0x00, 0x02, 0x01, 0x59, 0x09, 0x06, 204 | 0x00, 0x3e, 0x41, 0x5d, 0x55, 0x1e, 0x00, 0x7e, 0x11, 0x11, 0x11, 0x7e, 0x00, 0x7f, 0x49, 0x49, 205 | 0x49, 0x36, 0x00, 0x3e, 0x41, 0x41, 0x41, 0x22, 0x00, 0x7f, 0x41, 0x41, 0x41, 0x3e, 0x00, 0x7f, 206 | 0x49, 0x49, 0x49, 0x41, 0x00, 0x7f, 0x09, 0x09, 0x09, 0x01, 0x00, 0x3e, 0x41, 0x49, 0x49, 0x7a, 207 | 0x00, 0x7f, 0x08, 0x08, 0x08, 0x7f, 0x00, 0x00, 0x41, 0x7f, 0x41, 0x00, 0x00, 0x30, 0x40, 0x40, 208 | 0x40, 0x3f, 0x00, 0x7f, 0x08, 0x14, 0x22, 0x41, 0x00, 0x7f, 0x40, 0x40, 0x40, 0x40, 0x00, 0x7f, 209 | 0x02, 0x04, 0x02, 0x7f, 0x00, 0x7f, 0x02, 0x04, 0x08, 0x7f, 0x00, 0x3e, 0x41, 0x41, 0x41, 0x3e, 210 | 0x00, 0x7f, 0x09, 0x09, 0x09, 0x06, 0x00, 0x3e, 0x41, 0x51, 0x21, 0x5e, 0x00, 0x7f, 0x09, 0x09, 211 | 0x19, 0x66, 0x00, 0x26, 0x49, 0x49, 0x49, 0x32, 0x00, 0x01, 0x01, 0x7f, 0x01, 0x01, 0x00, 0x3f, 212 | 0x40, 0x40, 0x40, 0x3f, 0x00, 0x1f, 0x20, 0x40, 0x20, 0x1f, 0x00, 0x3f, 0x40, 0x3c, 0x40, 0x3f, 213 | 0x00, 0x63, 0x14, 0x08, 0x14, 0x63, 0x00, 0x07, 0x08, 0x70, 0x08, 0x07, 0x00, 0x71, 0x49, 0x45, 214 | 0x43, 0x00, 0x00, 0x00, 0x7f, 0x41, 0x41, 0x00, 0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00, 215 | 0x41, 0x41, 0x7f, 0x00, 0x00, 0x04, 0x02, 0x01, 0x02, 0x04, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 216 | 0x00, 0x00, 0x03, 0x07, 0x00, 0x00, 0x00, 0x20, 0x54, 0x54, 0x54, 0x78, 0x00, 0x7f, 0x44, 0x44, 217 | 0x44, 0x38, 0x00, 0x38, 0x44, 0x44, 0x44, 0x28, 0x00, 0x38, 0x44, 0x44, 0x44, 0x7f, 0x00, 0x38, 218 | 0x54, 0x54, 0x54, 0x08, 0x00, 0x08, 0x7e, 0x09, 0x09, 0x00, 0x00, 0x18, 0xa4, 0xa4, 0xa4, 0x7c, 219 | 0x00, 0x7f, 0x04, 0x04, 0x78, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x40, 0x00, 0x00, 0x40, 0x80, 0x84, 220 | 0x7d, 0x00, 0x00, 0x7f, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x40, 0x00, 0x00, 0x7c, 221 | 0x04, 0x18, 0x04, 0x78, 0x00, 0x7c, 0x04, 0x04, 0x78, 0x00, 0x00, 0x38, 0x44, 0x44, 0x44, 0x38, 222 | 0x00, 0xfc, 0x44, 0x44, 0x44, 0x38, 0x00, 0x38, 0x44, 0x44, 0x44, 0xfc, 0x00, 0x44, 0x78, 0x44, 223 | 0x04, 0x08, 0x00, 0x08, 0x54, 0x54, 0x54, 0x20, 0x00, 0x04, 0x3e, 0x44, 0x24, 0x00, 0x00, 0x3c, 224 | 0x40, 0x20, 0x7c, 0x00, 0x00, 0x1c, 0x20, 0x40, 0x20, 0x1c, 0x00, 0x3c, 0x60, 0x30, 0x60, 0x3c, 225 | 0x00, 0x6c, 0x10, 0x10, 0x6c, 0x00, 0x00, 0x9c, 0xa0, 0x60, 0x3c, 0x00, 0x00, 0x64, 0x54, 0x54, 226 | 0x4c, 0x00, 0x00, 0x08, 0x3e, 0x41, 0x41, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x00, 227 | 0x41, 0x41, 0x3e, 0x08, 0x00, 0x02, 0x01, 0x02, 0x01, 0x00, 0x00, 0x3c, 0x26, 0x23, 0x26, 0x3c 228 | }; 229 | 230 | uint8_t getPinInfo(uint8_t pin, volatile uint8_t **iDDR, volatile uint8_t **iPort, int bInput) 231 | { 232 | uint8_t port, bit; 233 | 234 | port = (pin & 0xf0); // hex port (A,B,D,E,F) 235 | bit = pin & 0x7; 236 | switch (port) 237 | { 238 | case 0xA0: // really port G 239 | *iPort = (bInput) ? &PING : &PORTG; 240 | *iDDR = &DDRG; 241 | break; 242 | case 0xB0: 243 | *iPort = (bInput) ? &PINB : &PORTB; 244 | *iDDR = &DDRB; 245 | break; 246 | case 0xD0: 247 | *iPort = (bInput) ? &PIND : &PORTD; 248 | *iDDR = &DDRD; 249 | break; 250 | case 0xE0: 251 | *iPort = (bInput) ? &PINE : &PORTE; 252 | *iDDR = &DDRE; 253 | break; 254 | case 0xF0: 255 | *iPort = (bInput) ? &PINF : &PORTF; 256 | *iDDR = &DDRF; 257 | break; 258 | } 259 | return bit; 260 | } /* getPinInfo() */ 261 | 262 | 263 | // 264 | // Simplified pin numbering scheme uses a hex number to specify the port number 265 | // and bit. Top 4 bits = port (B/D/E/F/G), bottom 3 bits specify the bit of the port 266 | // e.g. 0xB4 = PORTB, bit 4, 0Ax is for port G 267 | // 268 | void mypinMode(uint8_t pin, uint8_t mode) 269 | { 270 | uint8_t bit; 271 | volatile uint8_t *iPort, *iDDR; 272 | 273 | bit = getPinInfo(pin, &iDDR, &iPort, 0); 274 | switch (mode) 275 | { 276 | case INPUT: 277 | *iDDR &= ~(1 << bit); 278 | break; 279 | case INPUT_PULLUP: 280 | *iDDR |= (1 << bit); 281 | *iPort |= (1 << bit); // set the output high, then set it as an input 282 | *iDDR &= ~(1 << bit); 283 | break; 284 | case OUTPUT: 285 | *iDDR |= (1 << bit); 286 | break; 287 | } 288 | } /* mypinMode() */ 289 | 290 | 291 | void mydigitalWrite(uint8_t pin, uint8_t value) 292 | { 293 | uint8_t bit; 294 | volatile uint8_t *iPort, *iDDR; 295 | 296 | bit = getPinInfo(pin, &iDDR, &iPort, 0); 297 | if (value == LOW) 298 | { 299 | *iPort &= ~(1 << bit); 300 | } 301 | else 302 | { 303 | *iPort |= (1 << bit); 304 | } 305 | } /* mydigitalWrite() */ 306 | 307 | 308 | uint8_t mydigitalRead(uint8_t pin) 309 | { 310 | uint8_t bit; 311 | volatile uint8_t *iPort, *iDDR; 312 | 313 | bit = getPinInfo(pin, &iDDR, &iPort, 1); 314 | if (*iPort & (1 << bit)) 315 | return HIGH; 316 | else 317 | return LOW; 318 | } /* mydigitalRead() */ 319 | 320 | 321 | 322 | // 323 | // Put the device in a deep sleep to save power 324 | // Wakes up when pressing the "power" button 325 | // 326 | void SRXESleep(void) 327 | { 328 | // Turn off the LCD 329 | SRXEPowerDown(); 330 | 331 | //TRXPR = 1 << SLPTR; // send transceiver to sleep 332 | 333 | // disable ADC 334 | ADCSRA = 0; 335 | DDRD &= ~(1 << PORTD2); //PIN INT2 as input 336 | PORTD |= (1 << PORTD2); // pull-up resistor, the pin is forced to 1 if nothing is connected 337 | EIMSK &= ~(1 << INT2); //disabling interrupt on INT2 338 | EICRA &= ~((1 << ISC21) | (1 << ISC20)); // low level triggers interrupt 339 | EIFR |= (1 << INTF2); //clear interrupt flag 340 | EIMSK |= (1 << INT2); //enabling interrupt flag on INT2 341 | 342 | set_sleep_mode (SLEEP_MODE_PWR_DOWN); 343 | sleep_enable(); 344 | 345 | // turn off brown-out enable in software 346 | // BODS must be set to one and BODSE must be set to zero within four clock cycles 347 | // MCUCR = bit (BODS) | bit (BODSE); 348 | // The BODS bit is automatically cleared after three clock cycles 349 | // MCUCR = bit (BODS); 350 | 351 | // We are guaranteed that the sleep_cpu call will be done 352 | // as the processor executes the next instruction after 353 | // interrupts are turned on. 354 | sleep_cpu (); // one cycle 355 | SRXEPowerUp(); 356 | } /* SRXESleep() */ 357 | 358 | 359 | // 360 | // Initialize SPI using direct register access 361 | // 362 | void SPI_Init(void) 363 | { 364 | uint8_t temp; 365 | // Initialize SPI 366 | // Set SS to high so a connected chip will be "deselected" by default 367 | // digitalWrite(SS, HIGH); 368 | mydigitalWrite(0xb0, HIGH); 369 | 370 | // When the SS pin is set as OUTPUT, it can be used as 371 | // a general purpose output port (it doesn't influence 372 | // SPI operations). 373 | // pinMode(SS, OUTPUT); 374 | mypinMode(0xb0, OUTPUT); 375 | 376 | // SPCR = 01010000 377 | //interrupt disabled,spi enabled,msb 1st,master,clk low when idle, 378 | //*fdufnews 11/2019 **************** modification to speed SPI transfert ********************* 379 | //sample on leading edge of clk,system clock/2 rate 380 | SPCR = (1 << SPE) | (1 << MSTR); 381 | SPSR = (1 << SPI2X); 382 | temp = SPSR; // clear old data 383 | temp = SPDR; 384 | if (temp != 0) {}; // suppress compiler warning 385 | // Set SCK as output 386 | //pinMode(13, OUTPUT); 387 | mypinMode(0xb1, OUTPUT); 388 | // set MOSI as output 389 | //pinMode(11, OUTPUT); 390 | mypinMode(0xb2, OUTPUT); 391 | 392 | } /* SPI_Init() */ 393 | 394 | 395 | uint8_t SPI_transfer(volatile char data) 396 | { 397 | SPDR = data; // Start the transmission 398 | /* trick from arduboy code 399 | The following NOP introduces a small delay that can prevent the wait 400 | loop from iterating when running at the maximum speed. This gives 401 | about 10% more speed, even if it seems counter-intuitive. At lower 402 | speeds it is unnoticed. 403 | */ 404 | asm volatile("nop"); 405 | while (!(SPSR & (1 << SPIF))) // Wait for the end of the transmission 406 | { 407 | }; 408 | return SPDR; // return the received byte 409 | } /* SPI_transfer() */ 410 | 411 | // Sets the D/C pin to data or command mode 412 | static void SRXESetMode(int iMode) 413 | { 414 | mydigitalWrite(iDCPin, (iMode == MODE_DATA)); 415 | } /* SRXESetMode() */ 416 | 417 | 418 | // Write a block of pixel data to the LCD 419 | // Length can be anything from 1 to 17404 (whole display) 420 | void SRXEWriteDataBlock(unsigned char *ucBuf, int iLen) 421 | { 422 | int i; 423 | 424 | mydigitalWrite(iCSPin, LOW); 425 | for (i = 0; i < iLen; i++) 426 | SPI_transfer(ucBuf[i]); 427 | mydigitalWrite(iCSPin, HIGH); 428 | } 429 | 430 | 431 | // 432 | // Command sequence to power up the LCD controller 433 | // 434 | void SRXEPowerUp(void) 435 | { 436 | uint8_t ucTemp[4]; 437 | const char *pList = powerup; 438 | uint8_t val, count, len = 1; 439 | 440 | while (len != 0) 441 | { 442 | len = pgm_read_byte(pList++); 443 | if (len == 99) // delay 444 | { 445 | val = pgm_read_byte(pList++); 446 | delay(val); 447 | } 448 | else if (len != 0) // send command with optional data 449 | { 450 | val = pgm_read_byte(pList++); // command 451 | SRXEWriteCommand(val); 452 | count = len - 1; 453 | if (count != 0) 454 | { 455 | memcpy_P(ucTemp, pList, count); 456 | pList += count; 457 | SRXEWriteDataBlock(ucTemp, count); 458 | } 459 | } 460 | } 461 | } /* SRXEPowerUp() */ 462 | 463 | 464 | // 465 | // Initializes the LCD controller 466 | // Parameters: GPIO pin numbers used for the CS/DC/RST control lines 467 | // 468 | int SRXEInit(int iCS, int iDC, int iReset) 469 | { 470 | byte uc, ucTemp[8]; 471 | 472 | iCSPin = iCS; 473 | iDCPin = iDC; 474 | iResetPin = iReset; 475 | 476 | SPI_Init(); 477 | mypinMode(iCSPin, OUTPUT); 478 | mypinMode(CS_FLASH, OUTPUT); // in case we want to use the SPI flash 479 | mydigitalWrite(iCSPin, HIGH); 480 | 481 | mypinMode(iDCPin, OUTPUT); 482 | mypinMode(iResetPin, OUTPUT); 483 | 484 | // Start by reseting the LCD controller 485 | mydigitalWrite(iResetPin, HIGH); 486 | delay(50); 487 | mydigitalWrite(iResetPin, LOW); 488 | delay(5); 489 | mydigitalWrite(iResetPin, HIGH); // take it out of reset 490 | delay(150); // datasheet says it must be at least 120ms 491 | 492 | // mydigitalWrite(iCSPin, LOW); // leave CS low forever 493 | 494 | SRXEPowerUp(); // turn on and initialize the display 495 | 496 | SRXEFill(0); // erase memory (it's already cleared by resetting it) 497 | return 0; 498 | 499 | } /* SRXEInit() */ 500 | 501 | 502 | // 503 | // Turn off the LCD display (lowest power mode) 504 | // 505 | void SRXEPowerDown() 506 | { 507 | //SRXEFill(0); // fill memory with zeros to go to lowest power mode 508 | SRXEWriteCommand(0x28); // Display OFF 509 | SRXEWriteCommand(0x10); // Sleep in 510 | } /* SRXEPowerDown() */ 511 | 512 | 513 | // 514 | // Write a 1 byte command to the LCD controller 515 | // 516 | static void SRXEWriteCommand(unsigned char c) 517 | { 518 | mydigitalWrite(iCSPin, LOW); 519 | SRXESetMode(MODE_COMMAND); 520 | SPI_transfer(c); 521 | SRXESetMode(MODE_DATA); 522 | mydigitalWrite(iCSPin, HIGH); 523 | } /* SRXEWriteCommand() */ 524 | 525 | 526 | // 527 | // Send commands to position the "cursor" to the given 528 | // row and column 529 | // Opens a window in the display RAM 530 | // the windows starts @ x, y and it is cx wide and cy tall 531 | // all the subsequent write cycles will be done in that window 532 | // 533 | void SRXESetPosition(int x, int y, int cx, int cy) 534 | { 535 | byte ucTemp[4]; 536 | 537 | if (x > 383 || y > 159 || cx > 384 || cy > 160) 538 | return; // invalid 539 | SRXEWriteCommand(0x2a); // set column address 540 | ucTemp[0] = 0; // start column high byte 541 | ucTemp[1] = x / 3; // start column low byte 542 | ucTemp[2] = 0; // end col high byte 543 | ucTemp[3] = (x + cx - 1) / 3; // end col low byte 544 | SRXEWriteDataBlock(ucTemp, 4); 545 | SRXEWriteCommand(0x2b); // set row address 546 | ucTemp[0] = 0; // start row high byte 547 | ucTemp[1] = y; // start row low byte 548 | ucTemp[2] = 0; // end row high byte 549 | ucTemp[3] = y + cy - 1; // end row low byte 550 | SRXEWriteDataBlock(ucTemp, 4); 551 | SRXEWriteCommand(0x2c); // write RAM 552 | } /* SRXESetPosition() */ 553 | 554 | 555 | // SRXELoadBitmapRLE 556 | // load a bitmap in the display RAM 557 | // input 558 | // x, y coordinate of top left in the display 559 | // btmp array containing the bitmap compressed with RLE 560 | // 561 | void SRXELoadBitmapRLE(int x, int y, const uint8_t *btmp){ 562 | int width, height, index=0; 563 | unsigned char length, value; 564 | 565 | width = pgm_read_byte_near(btmp+index++) + (pgm_read_byte_near(btmp+index++) <<8); 566 | height = pgm_read_byte_near(btmp+index++) + (pgm_read_byte_near(btmp+index++) <<8); 567 | SRXESetPosition(x, y, width, height); 568 | mydigitalWrite(iCSPin, LOW); 569 | while(length = pgm_read_byte_near(btmp+index++) ){ 570 | value = pgm_read_byte_near(btmp+index++) ; 571 | for(unsigned char count=0; count 127 || y < 0 || y > 135) return; 675 | if (x + cx > 127 || y + cy > 135) return; 676 | if (bFilled) 677 | { 678 | SRXESetPosition(x * 3, y, cx * 3, cy); 679 | for (y = 0; y < cy; y++) 680 | { 681 | memset(bTemp, bColorToByte[color], cx); 682 | SRXEWriteDataBlock(bTemp, cx); 683 | } 684 | } // filled 685 | else // outline 686 | { 687 | // Draw top part 688 | SRXESetPosition(x * 3, y, cx * 3, 1); 689 | memset(bTemp, bColorToByte[color], cx); 690 | SRXEWriteDataBlock(bTemp, cx); 691 | // Bottom 692 | SRXESetPosition(x * 3, y + cy - 1, cx * 3, 1); 693 | memset(bTemp, bColorToByte[color], cx); 694 | SRXEWriteDataBlock(bTemp, cx); 695 | // Left 696 | SRXESetPosition(x * 3, y, 3, cy); 697 | memset(bTemp, bColorToByte[color], cy); 698 | SRXEWriteDataBlock(bTemp, cy); 699 | // Right 700 | SRXESetPosition((x + cx - 1) * 3, y, 3, cy); 701 | memset(bTemp, bColorToByte[color], cy); 702 | SRXEWriteDataBlock(bTemp, cy); 703 | } 704 | } /* SRXERectangle() */ 705 | 706 | 707 | int SRXEWriteChar(int x, int y, char ch) { 708 | int i, j, iLen; 709 | unsigned char ucTemp[8], *s; 710 | byte fgColor0, fgColor1, fgColor2, bgColor; 711 | 712 | fgColor0 = 0xe0; fgColor1 = 0x1c; fgColor2 = 0x3; 713 | bgColor = 0x00; 714 | 715 | int tx, ty; 716 | byte bTemp[16], bMask, bOut, *d; 717 | s = (unsigned char *)&ucSmallFont[(ch - 32) * 6]; 718 | memcpy_P(ucTemp, s, 6); // copy from FLASH memory 719 | // convert from 1-bpp to 2/3-bpp 720 | d = bTemp; 721 | for (ty = 0; ty < 8; ty++) 722 | { 723 | bMask = 1 << ty; 724 | for (tx = 0; tx < 6; tx += 3) // 2 sets of 3 pixels 725 | { 726 | bOut = bgColor; 727 | if (ucTemp[tx] & bMask) 728 | { 729 | bOut &= 0x1f; // clear top 3 bits 730 | bOut |= fgColor0; // first pixel (3 bits) 731 | } 732 | if (ucTemp[tx + 1] & bMask) 733 | { 734 | bOut &= 0xe3; // clear middle 3 bits 735 | bOut |= fgColor1; // second pixel (3 bits) 736 | } 737 | if (ucTemp[tx + 2] & bMask) 738 | { 739 | bOut &= 0xfc; // clear lower 2 bits 740 | bOut |= fgColor2; // third pixel (2 bits) 741 | } 742 | *d++ = bOut; 743 | } // for tx 744 | } // for ty 745 | SRXESetPosition(x, y, 6, 8); 746 | x += 6; 747 | SRXEWriteDataBlock(bTemp, 16); // write character pattern 748 | 749 | return 0; 750 | } 751 | 752 | // 753 | // Draw a string of normal (8x8), small (6x8) or large (16x24) characters 754 | // At the given col+row 755 | // 756 | int SRXEWriteString(int x, int y, char *szMsg, int iSize, int iFGColor, int iBGColor) 757 | { 758 | int i, j, iLen; 759 | unsigned char ucTemp[8], *s; 760 | byte fgColor0, fgColor1, fgColor2, bgColor; 761 | 762 | if (iFGColor > 3) iFGColor = 3; 763 | if (iBGColor > 3) iBGColor = 3; 764 | if (iFGColor == 3) 765 | { 766 | fgColor0 = 0xe0; fgColor1 = 0x1c; fgColor2 = 0x3; 767 | } 768 | else 769 | { 770 | fgColor0 = (byte)iFGColor << 6; // first pixel 3-bit version of the color 771 | fgColor1 = (byte)iFGColor << 3; // second pixel 772 | fgColor2 = (byte)iFGColor; // 3rd pixel 773 | } 774 | bgColor = bColorToByte[iBGColor]; 775 | 776 | iLen = strlen(szMsg); 777 | if (iSize == FONT_LARGE || iSize == FONT_MEDIUM) // draw 12x16 or 15x16 font 778 | { 779 | int iWidth, iDelta; 780 | iWidth = (iSize == FONT_LARGE) ? 15 : 12; 781 | iDelta = (iSize == FONT_LARGE) ? 5 : 4; 782 | if ((iWidth * iLen) + x > 384) iLen = (384 - x) / iWidth; // can't display it all 783 | if (iLen < 0)return -1; 784 | for (i = 0; i < iLen; i++) 785 | { 786 | int tx, ty; 787 | byte bTemp[84], bMask, bOut, bOut2, *d; 788 | if (iSize == FONT_LARGE) 789 | { 790 | s = (unsigned char *)&ucFont[((unsigned char)szMsg[i] - 32) * 8]; 791 | memcpy_P(ucTemp, s, 8); // copy from FLASH memory 792 | } 793 | else 794 | { 795 | s = (unsigned char *)&ucSmallFont[((unsigned char)szMsg[i] - 32) * 6]; 796 | memcpy_P(ucTemp, s, 6); 797 | } 798 | // convert from 1-bpp to 2/3-bpp 799 | d = bTemp; 800 | s = ucTemp; 801 | bMask = 1; 802 | for (ty = 0; ty < 8; ty++) 803 | { 804 | for (tx = 0; tx < iWidth - 6; tx += 3) // 3 sets of 3 pixels 805 | { 806 | bOut = bOut2 = bgColor; 807 | if (s[tx] & bMask) 808 | { 809 | bOut &= 0x3; // clear top 6 bits 810 | bOut |= fgColor0 | fgColor1; // first 2 pixels (6 bits) 811 | } 812 | if (s[tx + 1] & bMask) 813 | { 814 | bOut &= 0xfc; // clear bottom 2 bits 815 | bOut2 &= 0x1f; // clear top 3 bits 816 | bOut |= fgColor2; // third pixel (2 bits) 817 | bOut2 |= fgColor0; 818 | } 819 | if (s[tx + 2] & bMask) 820 | { 821 | bOut2 &= 0xe0; // clear lower 5 bits 822 | bOut2 |= fgColor1 | fgColor2; // 2nd & 3rd pixel2 of second byte 823 | } 824 | d[0] = d[iDelta] = bOut; 825 | if (tx != 6) 826 | d[1] = d[iDelta + 1] = bOut2; 827 | d += 2; 828 | } // for tx 829 | d += 4; // skip extra line (add 4 since we incremented by 6 already) 830 | bMask <<= 1; 831 | } // for ty 832 | SRXESetPosition(x, y, iWidth, 16); 833 | SRXEWriteDataBlock(bTemp, 16 * iDelta); // write character pattern 834 | x += iWidth; 835 | } // for each character 836 | } // large+medium 837 | else if (iSize == FONT_NORMAL)// draw 8x8 font 838 | { 839 | if ((9 * iLen) + x > 384) iLen = (384 - x) / 9; // can't display it all 840 | if (iLen < 0)return -1; 841 | 842 | for (i = 0; i < iLen; i++) 843 | { 844 | int tx, ty; 845 | byte bTemp[24], bMask, bOut, *d; 846 | s = (unsigned char *)&ucFont[((unsigned char)szMsg[i] - 32) * 8]; 847 | memcpy_P(ucTemp, s, 8); // copy from FLASH memory 848 | // convert from 1-bpp to 2/3-bpp 849 | d = bTemp; 850 | for (ty = 0; ty < 8; ty++) 851 | { 852 | bMask = 1 << ty; 853 | for (tx = 0; tx < 9; tx += 3) // 3 sets of 3 pixels 854 | { 855 | bOut = bgColor; 856 | if (ucTemp[tx] & bMask) 857 | { 858 | bOut &= 0x1f; // clear top 3 bits 859 | bOut |= fgColor0; // first pixel (3 bits) 860 | } 861 | if (ucTemp[tx + 1] & bMask) 862 | { 863 | bOut &= 0xe3; // clear middle 3 bits 864 | bOut |= fgColor1; // second pixel (3 bits) 865 | } 866 | if (tx != 6 && 867 | ucTemp[tx + 2] & bMask) 868 | { 869 | bOut &= 0xfc; // clear lower 2 bits 870 | bOut |= fgColor2; // third pixel (2 bits) 871 | } 872 | *d++ = bOut; 873 | } // for tx 874 | } // for ty 875 | SRXESetPosition(x, y, 9, 8); 876 | x += 9; 877 | SRXEWriteDataBlock(bTemp, 24); // write character pattern 878 | } 879 | } // normal 880 | else // 6x8 881 | { 882 | if ((6 * iLen) + x > 384) iLen = (384 - x) / 6; // can't display it all 883 | if (iLen < 0)return -1; 884 | 885 | for (i = 0; i < iLen; i++) 886 | { 887 | int tx, ty; 888 | byte bTemp[16], bMask, bOut, *d; 889 | s = (unsigned char *)&ucSmallFont[((unsigned char)szMsg[i] - 32) * 6]; 890 | memcpy_P(ucTemp, s, 6); // copy from FLASH memory 891 | // convert from 1-bpp to 2/3-bpp 892 | d = bTemp; 893 | for (ty = 0; ty < 8; ty++) 894 | { 895 | bMask = 1 << ty; 896 | for (tx = 0; tx < 6; tx += 3) // 2 sets of 3 pixels 897 | { 898 | bOut = bgColor; 899 | if (ucTemp[tx] & bMask) 900 | { 901 | bOut &= 0x1f; // clear top 3 bits 902 | bOut |= fgColor0; // first pixel (3 bits) 903 | } 904 | if (ucTemp[tx + 1] & bMask) 905 | { 906 | bOut &= 0xe3; // clear middle 3 bits 907 | bOut |= fgColor1; // second pixel (3 bits) 908 | } 909 | if (ucTemp[tx + 2] & bMask) 910 | { 911 | bOut &= 0xfc; // clear lower 2 bits 912 | bOut |= fgColor2; // third pixel (2 bits) 913 | } 914 | *d++ = bOut; 915 | } // for tx 916 | } // for ty 917 | SRXESetPosition(x, y, 6, 8); 918 | x += 6; 919 | SRXEWriteDataBlock(bTemp, 16); // write character pattern 920 | } 921 | } // small 922 | return 0; 923 | } /* SRXEWriteString() */ 924 | 925 | 926 | // Fill the frame buffer with a byte pattern 927 | // e.g. all off (0x00) or all on (0xff) 928 | void SRXEFill(byte ucData) 929 | { 930 | int y; 931 | byte temp[128]; 932 | 933 | SRXESetPosition(0, 0, 384, 160); 934 | for (y = 0; y < 160; y++) 935 | { 936 | memset(temp, ucData, 128); // have to do this because the bytes get overwritten 937 | SRXEWriteDataBlock(temp, 128); // fill with data byte 938 | } 939 | } /* SRXEFill() */ 940 | 941 | 942 | // 943 | // External SPI flash functions (MX25L1005C - Macronix 1Mb/128KB serial flash memory) 944 | // Data sheet here: http://www1.futureelectronics.com/doc/MACRONIX/MX25L1005CZUI-12GTR.pdf 945 | // The CS line must be set low before each command and then set high after 946 | // If you try to send 2 commands with the CS line left low, they won't execute 947 | // 948 | // ------------------ 949 | // 950 | // Erase a 4k sector 951 | // This is the smallest area that can be erased 952 | // It can take around 60ms 953 | // This function optionally waits until it completes 954 | // returns 1 for success, 0 for failure 955 | // 956 | int SRXEFlashEraseSector(uint32_t ulAddr, int bWait) 957 | { 958 | uint8_t rc; 959 | int timeout; 960 | if (ulAddr & 4095L) // invalid address 961 | return 0; 962 | mydigitalWrite(CS_FLASH, LOW); 963 | SPI_transfer(0x05); // read status register 964 | rc = SPI_transfer(0); 965 | mydigitalWrite(CS_FLASH, HIGH); 966 | if (rc & 1) // indicates the chip is busy in a write operation 967 | { 968 | return 0; // fail 969 | } 970 | mydigitalWrite(CS_FLASH, LOW); 971 | SPI_transfer(0x06); // WREN - Write enable 972 | mydigitalWrite(CS_FLASH, HIGH); 973 | 974 | mydigitalWrite(CS_FLASH, LOW); 975 | SPI_transfer(0x20); // Sector Erase 976 | // send 3-byte address (big-endian order) 977 | SPI_transfer((uint8_t)(ulAddr >> 16)); // AD1 978 | SPI_transfer((uint8_t)(ulAddr >> 8)); // AD2 979 | SPI_transfer((uint8_t)ulAddr); // AD3 980 | mydigitalWrite(CS_FLASH, HIGH); 981 | 982 | // wait for the erase to complete 983 | if (bWait) 984 | { 985 | rc = 1; 986 | timeout = 0; 987 | mydigitalWrite(CS_FLASH, LOW); 988 | while (rc & 1) 989 | { 990 | SPI_transfer(0x05); // read status register 991 | rc = SPI_transfer(0); 992 | delay(1); 993 | timeout++; 994 | if (timeout >= 120) // took too long, bail out 995 | { 996 | mydigitalWrite(CS_FLASH, HIGH); 997 | return 0; 998 | } 999 | } 1000 | mydigitalWrite(CS_FLASH, HIGH); 1001 | } // if asked to wait 1002 | return 1; 1003 | } /* SRXEFlashEraseSector() */ 1004 | 1005 | // 1006 | // Write a 256-byte flash page 1007 | // Address must be on a page boundary 1008 | // returns 1 for success, 0 for failure 1009 | // 1010 | int SRXEFlashWritePage(uint32_t ulAddr, uint8_t *pSrc) 1011 | { 1012 | int i, timeout; 1013 | uint8_t rc; 1014 | if (ulAddr & 255L) // invalid address 1015 | return 0; 1016 | mydigitalWrite(CS_FLASH, LOW); 1017 | SPI_transfer(0x05); // read status register 1018 | rc = SPI_transfer(0); 1019 | mydigitalWrite(CS_FLASH, HIGH); 1020 | if (rc & 1) // indicates the chip is busy in a write operation 1021 | { 1022 | return 0; // fail 1023 | } 1024 | // Disable write protect by clearing the status bits 1025 | mydigitalWrite(CS_FLASH, LOW); 1026 | SPI_transfer(0x01); // WRSR - write status register 1027 | SPI_transfer(0x00); // set all bits to 0 1028 | mydigitalWrite(CS_FLASH, HIGH); 1029 | 1030 | mydigitalWrite(CS_FLASH, LOW); 1031 | SPI_transfer(0x06); // WREN - Write enable 1032 | mydigitalWrite(CS_FLASH, HIGH); 1033 | 1034 | mydigitalWrite(CS_FLASH, LOW); 1035 | SPI_transfer(0x02); // PP - page program 1036 | // send 3-byte address (big-endian order) 1037 | SPI_transfer((uint8_t)(ulAddr >> 16)); // AD1 1038 | SPI_transfer((uint8_t)(ulAddr >> 8)); // AD2 1039 | SPI_transfer((uint8_t)ulAddr); // AD3 1040 | for (i = 0; i < 256; i++) 1041 | { 1042 | SPI_transfer(pSrc[i]); // write the 256 data bytes 1043 | } 1044 | mydigitalWrite(CS_FLASH, HIGH); // this executes the command internally 1045 | // wait for the write to complete 1046 | rc = 1; 1047 | timeout = 0; 1048 | mydigitalWrite(CS_FLASH, LOW); 1049 | while (rc & 1) 1050 | { 1051 | SPI_transfer(0x05); // read status register 1052 | rc = SPI_transfer(0); 1053 | delay(1); 1054 | timeout++; 1055 | if (timeout >= 20) // took too long, bail out 1056 | { 1057 | mydigitalWrite(CS_FLASH, HIGH); 1058 | return 0; 1059 | } 1060 | } 1061 | mydigitalWrite(CS_FLASH, HIGH); 1062 | return 1; 1063 | } /* SRXEFlashWritePage() */ 1064 | 1065 | // 1066 | // Read N bytes from SPI flash 1067 | // 1068 | int SRXEFlashRead(uint32_t ulAddr, uint8_t *pDest, int iLen) 1069 | { 1070 | int i; 1071 | 1072 | mydigitalWrite(CS_FLASH, LOW); 1073 | SPI_transfer(0x03); // issue read instruction 1074 | // send 3-byte address (big-endian order) 1075 | SPI_transfer((uint8_t)(ulAddr >> 16)); // AD1 1076 | SPI_transfer((uint8_t)(ulAddr >> 8)); // AD2 1077 | SPI_transfer((uint8_t)ulAddr); // AD3 1078 | for (i = 0; i < iLen; i++) // read the bytes out 1079 | { 1080 | *pDest++ = SPI_transfer(0); // need to write something to read from SPI 1081 | } 1082 | mydigitalWrite(CS_FLASH, HIGH); // de-activate 1083 | return 1; 1084 | } /* SRXEFlashRead() */ 1085 | 1086 | uint8_t SRXEFlashReadByte(uint32_t ulAddr) 1087 | { 1088 | uint8_t i; 1089 | 1090 | mydigitalWrite(CS_FLASH, LOW); 1091 | SPI_transfer(0x03); // issue read instruction 1092 | // send 3-byte address (big-endian order) 1093 | SPI_transfer((uint8_t)(ulAddr >> 16)); // AD1 1094 | SPI_transfer((uint8_t)(ulAddr >> 8)); // AD2 1095 | SPI_transfer((uint8_t)ulAddr); // AD3 1096 | i = SPI_transfer(0); // need to write something to read from SPI 1097 | mydigitalWrite(CS_FLASH, HIGH); // de-activate 1098 | return i; 1099 | } /* SRXEFlashReadByte() */ 1100 | // 1101 | // Scan the rows and columns and store the results in the key map 1102 | // 1103 | void SRXEScanKeyboard(void) 1104 | { 1105 | byte r, c; 1106 | 1107 | for (r = 0; r < ROWS; r++) 1108 | { 1109 | mypinMode(rowPins[r], INPUT_PULLUP); 1110 | } 1111 | // save current keymap to compare for pressed/released keys 1112 | memcpy(bOldKeyMap, bKeyMap, sizeof(bKeyMap)); 1113 | 1114 | for (c = 0; c < COLS; c++) 1115 | { 1116 | bKeyMap[c] = 0; 1117 | mypinMode(colPins[c], OUTPUT); 1118 | mydigitalWrite(colPins[c], LOW); // test this column 1119 | for (r = 0; r < ROWS; r++) 1120 | { 1121 | if (mydigitalRead(rowPins[r]) == LOW) 1122 | bKeyMap[c] |= (1 << r); // set a bit for each pressed key 1123 | } // for r 1124 | mydigitalWrite(colPins[c], HIGH); // leave pin in high impedance state 1125 | mypinMode(colPins[c], INPUT); 1126 | } // for c 1127 | } /* SRXEScanKeyboard() */ 1128 | // 1129 | // Return a pointer to the internal key map 1130 | // (10 bytes with 6 bits each) 1131 | // 1132 | byte *SRXEGetKeyMap(void) 1133 | { 1134 | return bKeyMap; 1135 | } 1136 | // 1137 | // Return the current key pressed 1138 | // includes code to provide shift + sym adjusted output 1139 | // 1140 | byte SRXEGetKey(void) 1141 | { 1142 | byte bShift, bSym,bCtrl, *pKeys; 1143 | byte iCol, iRow; 1144 | byte bMask; 1145 | byte bKey = 0; 1146 | 1147 | SRXEScanKeyboard(); 1148 | bShift = bKeyMap[0] & 0x08; 1149 | bSym = bKeyMap[0] & 0x10; 1150 | bCtrl = bKeyMap[4] & 0x20; 1151 | for (iCol = 0; iCol < COLS; iCol++) 1152 | { 1153 | bMask = 1; 1154 | for (iRow = 0; iRow < ROWS; iRow++, bMask <<= 1) 1155 | { 1156 | if ((bKeyMap[iCol] & bMask) == bMask && (bOldKeyMap[iCol] & bMask) == 0) 1157 | { 1158 | // make sure it's not shift/sym 1159 | if (iCol == 0 && (iRow == 3 || iRow == 4)) // shift/sym, ignore 1160 | continue; 1161 | if (iCol == 4 && (iRow == 5)) // ctrl, ignore 1162 | continue; 1163 | // valid key, adjust it and return 1164 | pKeys = OriginalKeys; 1165 | if (bShift && bSym) pKeys = SymShiftKeys; 1166 | else if (bShift) pKeys = ShiftedKeys; 1167 | else if (bSym) pKeys = SymKeys; 1168 | bKey = pKeys[(iRow * COLS) + iCol]; 1169 | if (bCtrl) bKey = bKey - 'a' + 1; 1170 | } 1171 | } // for iRow 1172 | } // for iCol 1173 | return bKey; // 0 if no keys pressed 1174 | } /* SRXEGetKey() */ 1175 | -------------------------------------------------------------------------------- /SmartResponseXEmt.h: -------------------------------------------------------------------------------- 1 | // 2 | // SMART Response XE support library 3 | // written by Larry Bank 4 | // Copyright (C) 2018 BitBank Software, Inc. 5 | // Project started 8/4/2018 6 | // 7 | // Modified by Dan Geiger (Port to SMART Response XE) 8 | // 9 | #ifndef __SMART_RESPONSE_XE__ 10 | #define __SMART_RESPONSE_XE__ 11 | 12 | // Font sizes (9x8, 6x8, 12x16, 15x16) 13 | #define FONT_NORMAL 0 14 | #define FONT_SMALL 1 15 | #define FONT_MEDIUM 2 16 | #define FONT_LARGE 3 17 | 18 | // Keyboard info 19 | #define ROWS 6 20 | #define COLS 10 21 | 22 | // Display info 23 | #define LCD_WIDTH 384 24 | #define LCD_HEIGHT 144 25 | 26 | // keyboard special keys 27 | #define KEY_MENU 1 28 | #define KEY_LEFT 2 29 | #define KEY_RIGHT 3 30 | #define KEY_UP 4 31 | #define KEY_DOWN 5 32 | 33 | static byte bKeyMap[COLS]; 34 | 35 | // 36 | // Simplified pin numbering scheme uses a hex number to specify the port number 37 | // and bit. Top 4 bits = port (B/D/E/F/G), bottom 3 bits specify the bit of the port 38 | // e.g. 0xB4 = PORTB, bit 4, 0Ax is for port G 39 | // 40 | void mypinMode(uint8_t pin, uint8_t mode); 41 | void mydigitalWrite(uint8_t pin, uint8_t value); 42 | uint8_t mydigitalRead(uint8_t pin); 43 | 44 | // 45 | // Power Sleep (low power mode to save battery) 46 | // Wakes up when the "power" button is pressed 47 | // 48 | void SRXESleep(void); 49 | 50 | // 51 | // Power on the LCD 52 | // 53 | void SRXEPowerUp(void); 54 | 55 | // 56 | // Power off the LCD 57 | // 58 | void SRXEPowerDown(void); 59 | // 60 | // Initializes the LCD controller 61 | // Parameters: GPIO pin numbers used for the CS/DC/RST control lines 62 | // 63 | int SRXEInit(int iCS, int iDC, int iReset); 64 | // 65 | // Send commands to position the "cursor" to the given 66 | // row and column and width and height of the memory window 67 | // 68 | void SRXESetPosition(int x, int y, int cx, int cy); 69 | // 70 | // Write a block of pixel data to the LCD 71 | // Length can be anything from 1 to 17408 (whole display) 72 | // 73 | void SRXEWriteDataBlock(unsigned char *ucBuf, int iLen); 74 | 75 | void SRXELoadBitmapRLE(int x, int y, const uint8_t *btmp); 76 | 77 | // 78 | // Set Scroll Area 79 | // inputs: 80 | // TA: top fixed area 81 | // SA: scroll area 82 | // BA: bottom fixed area 83 | // TA + SA + BA = 160 84 | // 85 | // fdufnews 12/2019 86 | // 87 | void SRXEScrollArea(int TA, int SA, int BA); 88 | // 89 | // Scroll the screen N lines vertically (positive or negative) 90 | // The value given represents a delta which affects the current scroll offset 91 | // 92 | void SRXEScroll(int iLines); 93 | // 94 | // Reset the scroll position to 0 95 | // 96 | void SRXEScrollReset(void); 97 | 98 | void SRXEHorizontalLine(int x, int y, int length,byte color,int thickness); 99 | void SRXEVerticalLine(int x, int y, int height,byte color); 100 | 101 | // 102 | // Draw an outline or filled rectangle 103 | // Only draws on byte boundaries (3 pixels wide) 104 | // (display is treated as 128x136) 105 | // 106 | void SRXERectangle(int x, int y, int cx, int cy, byte color, byte bFilled); 107 | // 108 | // Draw a string of normal (9x8), small (6x8) or large (15x16) characters 109 | // At the given col+row 110 | // 111 | int SRXEWriteString(int x, int y, char *szMsg, int iSize, int iFGColor, int iBGColor); 112 | int SRXEWriteChar(int x, int y, char ch); 113 | 114 | // Fill the frame buffer with a byte pattern 115 | // e.g. all off (0x00) or all on (0xff) 116 | void SRXEFill(byte ucData); 117 | // 118 | // Scan the rows and columns and store the results in the key map 119 | // 120 | void SRXEScanKeyboard(void); 121 | // 122 | // Return a pointer to the internal key map 123 | // (10 bytes with 6 bits each) 124 | // 125 | byte *SRXEGetKeyMap(void); 126 | // 127 | // Return the current key pressed 128 | // includes code to provide shift + sym adjusted output 129 | // internally calls SRXEScanKeyboard() 130 | // 131 | byte SRXEGetKey(void); 132 | 133 | // 134 | // Erase a 4k sector 135 | // This is the smallest area that can be erased 136 | // It can take around 60ms 137 | // This function optionally waits until it completes 138 | // returns 1 for success, 0 for failure 139 | // 140 | int SRXEFlashEraseSector(uint32_t ulAddr, int bWait); 141 | // 142 | // Write a 256-byte flash page 143 | // Address must be on a page boundary 144 | // returns 1 for success, 0 for failure 145 | // 146 | int SRXEFlashWritePage(uint32_t ulAddr, uint8_t *pSrc); 147 | // 148 | // Read N bytes from SPI flash 149 | // 150 | int SRXEFlashRead(uint32_t ulAddr, uint8_t *pDest, int iLen); 151 | uint8_t SRXEFlashReadByte(uint32_t ulAddr); 152 | 153 | #endif // __SMART_RESPONSE_XE__ 154 | -------------------------------------------------------------------------------- /sketch_jul16a.ino: -------------------------------------------------------------------------------- 1 | 2 | #include "SmartResponseXEmt.h" 3 | #include 4 | 5 | // Select the timers you're using, here ITimer1 6 | #define USE_TIMER_1 true 7 | #define USE_TIMER_2 true 8 | #define USE_TIMER_3 false 9 | #define USE_TIMER_4 false 10 | #define USE_TIMER_5 false 11 | 12 | #include "TimerInterrupt.h" 13 | 14 | int row; 15 | int col; 16 | int scrollRow; 17 | char buf[17][70]; 18 | char draw[5]; 19 | char incomingByte = 0; // for incoming serial data 20 | void setup() 21 | { 22 | Serial1.begin(9600); // opens serial port, sets data rate to 9600 bps 23 | 24 | pinMode(INT2, INPUT_PULLUP); 25 | TRXPR = 1 << SLPTR; // send transceiver to sleep 26 | 27 | SRXEInit(0xe7, 0xd6, 0xa2); // initialize display 28 | SRXEFill(0); 29 | SRXEScrollArea(0, 136, 24); // Visible screen area 30 | 31 | SRXEWriteString(0, 0, "Pocket terminal by Michele Trombetta", FONT_NORMAL, 3, 0); 32 | SRXEWriteString(0, 9, " www.github.com/chmod775 ", FONT_NORMAL, 3, 0); 33 | 34 | row = 2; 35 | col = 0; 36 | scrollRow = 0; 37 | 38 | // Init timer ITimer1 39 | ITimer1.init(); 40 | ITimer1.attachInterrupt(1000, KeyBoard_Handler); 41 | // Init timer ITimer2 42 | //ITimer2.init(); 43 | //ITimer2.attachInterrupt(2, Cursor_Handler); 44 | } 45 | 46 | void loop() {} 47 | 48 | /* ##### SERIAL MANAGEMENT ##### */ 49 | void serialEvent1() { 50 | if (Serial1.available() > 0) { 51 | incomingByte = Serial1.read(); 52 | PutChar(incomingByte); 53 | } 54 | } 55 | 56 | char Serial1_BlockingRead(){ 57 | while(!Serial1.available()); 58 | return Serial1.read(); 59 | } 60 | /* ############################# */ 61 | 62 | /* ##### KEYBOARD + CURSOR MANAGEMENT ##### */ 63 | byte cursorVisible = 0; 64 | byte typing = 0; 65 | int CursorHandler_Cnt = 0; 66 | 67 | void Cursor_Handler() { 68 | if (!typing) { 69 | cursorVisible = cursorVisible > 0 ? 0 : 1; 70 | DrawCursor(cursorVisible); 71 | } 72 | typing = false; 73 | } 74 | 75 | void KeyBoard_Handler() { 76 | int key = SRXEGetKey(); 77 | if (key) { 78 | if ((key >= 0xe0) && (key <= 0xef)) { 79 | Serial1.write('\e'); 80 | Serial1.write('['); 81 | switch (key) { 82 | case 0xe0: 83 | Serial1.write('A'); 84 | break; 85 | case 0xe1: 86 | Serial1.write('B'); 87 | break; 88 | case 0xe2: 89 | Serial1.write('C'); 90 | break; 91 | case 0xe3: 92 | Serial1.write('D'); 93 | break; 94 | } 95 | } 96 | else 97 | Serial1.write(key); 98 | } 99 | 100 | CursorHandler_Cnt++; 101 | if (CursorHandler_Cnt >= 500) { 102 | CursorHandler_Cnt = 0; 103 | Cursor_Handler(); 104 | } 105 | } 106 | 107 | void DrawCursor(bool visible) { 108 | cursorVisible = visible; 109 | if (visible) { 110 | SRXEVerticalLine(6 * col, 8 * ((row + scrollRow) % 17), 8, 3); 111 | } else { 112 | int tRow = (row + scrollRow) % 17; 113 | SRXEVerticalLine(6 * col, 8 * tRow, 8, 0); 114 | SRXEWriteChar(6 * col, 8 * tRow, buf[tRow][col]); 115 | } 116 | } 117 | /* ############################################### */ 118 | 119 | /* ##### TERMINAL EMULATOR ##### */ 120 | void PutChar(char ch) { 121 | if (cursorVisible) DrawCursor(false); 122 | 123 | if (ch == '\n') { NewLine(); return; } 124 | if (ch == '\r') { CarriageReturn(); return; } 125 | if (ch == '\b') { Backspace(); return; } 126 | if (ch == '\t') { Tab(); return; } 127 | if (ch == '\e') { Escape(); return; } 128 | 129 | typing = true; 130 | 131 | int tRow = (row + scrollRow) % 17; 132 | 133 | buf[tRow][col] = ch; 134 | 135 | SRXEWriteChar(6 * col, 8 * tRow, ch); 136 | 137 | if (col < 70) 138 | col++; 139 | } 140 | 141 | void ScrollUp() { 142 | scrollRow++; 143 | if (scrollRow >= 17) scrollRow = 0; 144 | 145 | memset(buf[row], ' ', 70); 146 | buf[row][69] = 0x00; 147 | SRXEWriteString(0, 8 * ((row + scrollRow) % 17), buf[row], FONT_SMALL, 3, 0); 148 | SRXEScroll(8); 149 | } 150 | 151 | void NewLine() { 152 | if (row >= 16) { 153 | row = 16; 154 | ScrollUp(); 155 | } else 156 | row++; 157 | } 158 | 159 | void Tab() { 160 | if (col < 70) 161 | col += 4; 162 | } 163 | 164 | void Backspace(){ 165 | if (col > 0); 166 | col--; 167 | } 168 | 169 | void CarriageReturn() { 170 | col = 0; 171 | } 172 | 173 | void Clear() { 174 | col = 0; 175 | row = 0; 176 | } 177 | 178 | unsigned char c; 179 | void Escape(){ 180 | c = Serial1_BlockingRead(); 181 | byte x,y,val; 182 | if(c == 'D'){ 183 | NewLine(); 184 | } 185 | if(c == 'M'){ 186 | row--; 187 | if(row < 0){row = 0;} 188 | } 189 | if(c == 'E'){ 190 | NewLine(); 191 | CarriageReturn(); 192 | } 193 | if(c == '['){ 194 | c = Serial1_BlockingRead(); 195 | 196 | if (c == '[') 197 | c = Serial1_BlockingRead(); 198 | 199 | val = 255; 200 | if(isdigit(c)){ 201 | val = c - '0'; 202 | c = Serial1_BlockingRead(); 203 | if(isdigit(c)){ 204 | val*=10; 205 | val+=c-'0'; 206 | c = Serial1_BlockingRead(); 207 | } 208 | } 209 | switch(c){ 210 | case ';': 211 | int val2; 212 | val2 = Serial1_BlockingRead() - '0'; 213 | c = Serial1_BlockingRead(); 214 | if(isdigit(c)){ 215 | val2 *= 10; 216 | val2 += c-'0'; 217 | c = Serial1_BlockingRead(); 218 | } 219 | if(c == 'f' || c == 'H'){ 220 | row = val-1; col = val2-1; 221 | if(col > 70){col = 70;} 222 | if(col < 0){col = 0;} 223 | if(row >= 16){row = 16;} 224 | if(row < 0){row = 0;} 225 | } 226 | break; 227 | case 'A':case 'a': row-=(val==255)?1:val; if(row < 0){row = 0;} break; 228 | case 'B':case 'b': row+=(val==255)?1:val; if(row >= 16){row = 16;} break; 229 | case 'C':case 'c': col+=(val==255)?1:val; if(col > 70){col = col - 70;} break; 230 | case 'D':case 'd': col-=(val==255)?1:val; if(col < 0){col = 0;} break; 231 | case 'H':col = 0; row =0 ; break; 232 | 233 | case 'K': 234 | if(val == 0 || val == 255){ // Cursor to end 235 | memset(buf[row], ' ', 70); 236 | buf[row][69] = 0x00; 237 | SRXEWriteString(6 * col, 8 * ((row + scrollRow) % 17), buf[row], FONT_SMALL, 3, 0); 238 | } 239 | if(val == 1){ // Cursor to begin 240 | memset(buf[row], ' ', col + 1); 241 | buf[row][col] = 0x00; 242 | SRXEWriteString(0, 8 * ((row + scrollRow) % 17), buf[row], FONT_SMALL, 3, 0); 243 | } 244 | if(val == 2){ // Entire line 245 | memset(buf[row], ' ', 70); 246 | buf[row][69] = 0x00; 247 | SRXEWriteString(0, 8 * ((row + scrollRow) % 17), buf[row], FONT_SMALL, 3, 0); 248 | } 249 | break; 250 | case 'J': 251 | if(val == 0 || val == 255){ // Cursor to end 252 | memset(buf[row], ' ', 70); 253 | buf[row][69] = 0x00; 254 | SRXEWriteString(6 * col, 8 * ((row + scrollRow) % 17), buf[row], FONT_SMALL, 3, 0); 255 | if (row > 16) { 256 | for (int r = row + 1; r < 17; r++) { 257 | memset(buf[r], ' ', 70); 258 | buf[r][69] = 0x00; 259 | SRXEWriteString(0, 8 * ((r + scrollRow) % 17), buf[r], FONT_SMALL, 3, 0); 260 | } 261 | } 262 | } 263 | if(val == 1){ // Cursor to begin 264 | memset(buf[row], ' ', col + 1); 265 | buf[row][col] = 0x00; 266 | SRXEWriteString(0, 8 * ((row + scrollRow) % 17), buf[row], FONT_SMALL, 3, 0); 267 | if (row > 0) { 268 | for (int r = row - 1; r > 0; r--) { 269 | memset(buf[r], ' ', 70); 270 | buf[r][69] = 0x00; 271 | SRXEWriteString(0, 8 * ((r + scrollRow) % 17), buf[r], FONT_SMALL, 3, 0); 272 | } 273 | } 274 | } 275 | if(val == 2){ // Entire screen 276 | SRXEFill(0); 277 | } 278 | break; 279 | case 'n':/* 280 | if(val == 5){ 281 | s.write(27); 282 | s.write("[0n"); 283 | } 284 | if(val == 6){ 285 | s.write(27); 286 | s.write("["); 287 | s.print((int)cx); 288 | s.write(";"); 289 | s.print((int)cy); 290 | s.write("n"); 291 | }*/ 292 | break; 293 | case 'm':/* 294 | if(val == 0 || val == 255){ 295 | cur_atr = 0; 296 | } 297 | if(val == 4){ 298 | cur_atr |= UNDERLINE; 299 | } 300 | #ifdef ENABLE_INVERSE 301 | if(val == 7){ 302 | cur_atr |= INVERSE; 303 | } 304 | #endif 305 | if(val == 5){ 306 | cur_atr |= BLINK; 307 | }*/ 308 | break; 309 | case 'Z':/* 310 | s.write(27); 311 | s.write("[?1;0c");*/ 312 | break; 313 | 314 | } 315 | } 316 | } 317 | --------------------------------------------------------------------------------