A library with drivers for different peripherals on the LPC4088 QuickStart Board or related add-on boards.
Dependents: LPC4088test LPC4088test_ledonly LPC4088test_deleteall LPC4088_RAMtest ... more
EaLcdBoard.cpp@13:d868b74fd08e, 2014-04-09 (annotated)
- Committer:
- embeddedartists
- Date:
- Wed Apr 09 09:36:00 2014 +0000
- Revision:
- 13:d868b74fd08e
- Parent:
- 12:15597e45eea0
Updated to work with the new gpio_init()
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
embeddedartists | 12:15597e45eea0 | 1 | /* |
embeddedartists | 12:15597e45eea0 | 2 | * Copyright 2013 Embedded Artists AB |
embeddedartists | 12:15597e45eea0 | 3 | * |
embeddedartists | 12:15597e45eea0 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
embeddedartists | 12:15597e45eea0 | 5 | * you may not use this file except in compliance with the License. |
embeddedartists | 12:15597e45eea0 | 6 | * You may obtain a copy of the License at |
embeddedartists | 12:15597e45eea0 | 7 | * |
embeddedartists | 12:15597e45eea0 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
embeddedartists | 12:15597e45eea0 | 9 | * |
embeddedartists | 12:15597e45eea0 | 10 | * Unless required by applicable law or agreed to in writing, software |
embeddedartists | 12:15597e45eea0 | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
embeddedartists | 12:15597e45eea0 | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
embeddedartists | 12:15597e45eea0 | 13 | * See the License for the specific language governing permissions and |
embeddedartists | 12:15597e45eea0 | 14 | * limitations under the License. |
embeddedartists | 12:15597e45eea0 | 15 | */ |
embeddedartists | 4:b32cf4ef45c5 | 16 | |
embeddedartists | 4:b32cf4ef45c5 | 17 | /****************************************************************************** |
embeddedartists | 4:b32cf4ef45c5 | 18 | * Includes |
embeddedartists | 4:b32cf4ef45c5 | 19 | *****************************************************************************/ |
embeddedartists | 0:0fdadbc3d852 | 20 | |
embeddedartists | 0:0fdadbc3d852 | 21 | #include "mbed.h" |
embeddedartists | 0:0fdadbc3d852 | 22 | #include "EaLcdBoard.h" |
embeddedartists | 0:0fdadbc3d852 | 23 | |
embeddedartists | 4:b32cf4ef45c5 | 24 | /****************************************************************************** |
embeddedartists | 4:b32cf4ef45c5 | 25 | * Defines and typedefs |
embeddedartists | 4:b32cf4ef45c5 | 26 | *****************************************************************************/ |
embeddedartists | 4:b32cf4ef45c5 | 27 | |
embeddedartists | 4:b32cf4ef45c5 | 28 | #define PORT_PIN_BUG_IN_MBED_SDK |
embeddedartists | 4:b32cf4ef45c5 | 29 | |
embeddedartists | 0:0fdadbc3d852 | 30 | #define LCDB_MAGIC 0xEA01CDAE |
embeddedartists | 0:0fdadbc3d852 | 31 | |
embeddedartists | 0:0fdadbc3d852 | 32 | |
embeddedartists | 0:0fdadbc3d852 | 33 | #define LCDB_PCA9532_I2C_ADDR (0x64 << 1) |
embeddedartists | 0:0fdadbc3d852 | 34 | |
embeddedartists | 0:0fdadbc3d852 | 35 | /* PCA9532 registers*/ |
embeddedartists | 0:0fdadbc3d852 | 36 | #define LCDB_PCA9532_INPUT0 0x00 |
embeddedartists | 0:0fdadbc3d852 | 37 | #define LCDB_PCA9532_INPUT1 0x01 |
embeddedartists | 0:0fdadbc3d852 | 38 | #define LCDB_PCA9532_PSC0 0x02 |
embeddedartists | 0:0fdadbc3d852 | 39 | #define LCDB_PCA9532_PWM0 0x03 |
embeddedartists | 0:0fdadbc3d852 | 40 | #define LCDB_PCA9532_PSC1 0x04 |
embeddedartists | 0:0fdadbc3d852 | 41 | #define LCDB_PCA9532_PWM1 0x05 |
embeddedartists | 0:0fdadbc3d852 | 42 | #define LCDB_PCA9532_LS0 0x06 |
embeddedartists | 0:0fdadbc3d852 | 43 | #define LCDB_PCA9532_LS1 0x07 |
embeddedartists | 0:0fdadbc3d852 | 44 | #define LCDB_PCA9532_LS2 0x08 |
embeddedartists | 0:0fdadbc3d852 | 45 | #define LCDB_PCA9532_LS3 0x09 |
embeddedartists | 0:0fdadbc3d852 | 46 | #define LCDB_PCA9532_AUTO_INC 0x10 |
embeddedartists | 0:0fdadbc3d852 | 47 | |
embeddedartists | 0:0fdadbc3d852 | 48 | #define LCDB_LS_MODE_ON 0x01 |
embeddedartists | 0:0fdadbc3d852 | 49 | #define LCDB_LS_MODE_BLINK0 0x02 |
embeddedartists | 0:0fdadbc3d852 | 50 | #define LCDB_LS_MODE_BLINK1 0x03 |
embeddedartists | 0:0fdadbc3d852 | 51 | |
embeddedartists | 0:0fdadbc3d852 | 52 | #define LCDB_CTRL_3V3 0x0001 |
embeddedartists | 0:0fdadbc3d852 | 53 | #define LCDB_CTRL_5V 0x0002 |
embeddedartists | 0:0fdadbc3d852 | 54 | #define LCDB_CTRL_DISP_EN 0x0010 |
embeddedartists | 0:0fdadbc3d852 | 55 | #define LCDB_CTRL_BL_EN 0x0080 |
embeddedartists | 0:0fdadbc3d852 | 56 | #define LCDB_CTRL_BL_C 0x0100 |
embeddedartists | 0:0fdadbc3d852 | 57 | #define LCDB_EEPROM_WP 0x8000 |
embeddedartists | 0:0fdadbc3d852 | 58 | |
embeddedartists | 0:0fdadbc3d852 | 59 | #define LCDB_EEPROM_I2C_ADDR (0x56 << 1) |
embeddedartists | 0:0fdadbc3d852 | 60 | #define LCDB_EEPROM_PAGE_SIZE 32 |
embeddedartists | 0:0fdadbc3d852 | 61 | #define LCDB_EEPROM_TOTAL_SIZE 8192 |
embeddedartists | 0:0fdadbc3d852 | 62 | |
embeddedartists | 0:0fdadbc3d852 | 63 | /* |
embeddedartists | 0:0fdadbc3d852 | 64 | * Set which sequence string version that is supported |
embeddedartists | 0:0fdadbc3d852 | 65 | */ |
embeddedartists | 4:b32cf4ef45c5 | 66 | #define LCDB_SEQ_VER 2 |
embeddedartists | 0:0fdadbc3d852 | 67 | |
embeddedartists | 0:0fdadbc3d852 | 68 | #ifndef MIN |
embeddedartists | 0:0fdadbc3d852 | 69 | #define MIN(x, y) (((x)<(y))?(x):(y)) |
embeddedartists | 0:0fdadbc3d852 | 70 | #endif |
embeddedartists | 0:0fdadbc3d852 | 71 | |
embeddedartists | 0:0fdadbc3d852 | 72 | #define EA_LCD_TMP_BUFFER_SZ 256 |
embeddedartists | 0:0fdadbc3d852 | 73 | static char* eaLcdTmpBuffer[EA_LCD_TMP_BUFFER_SZ]; |
embeddedartists | 0:0fdadbc3d852 | 74 | |
embeddedartists | 0:0fdadbc3d852 | 75 | |
embeddedartists | 0:0fdadbc3d852 | 76 | /* Structure containing the parameters for the LCD panel as stored on LCD Board */ |
embeddedartists | 0:0fdadbc3d852 | 77 | |
embeddedartists | 0:0fdadbc3d852 | 78 | /* LCD display types */ |
embeddedartists | 0:0fdadbc3d852 | 79 | typedef enum { |
embeddedartists | 0:0fdadbc3d852 | 80 | TFT = 0, /* standard TFT */ |
embeddedartists | 0:0fdadbc3d852 | 81 | ADTFT, /* advanced TFT */ |
embeddedartists | 0:0fdadbc3d852 | 82 | HRTFT, /* highly reflective TFT */ |
embeddedartists | 0:0fdadbc3d852 | 83 | MONO_4BIT, /* 4-bit mono */ |
embeddedartists | 0:0fdadbc3d852 | 84 | MONO_8BIT, /* 8-bit mono */ |
embeddedartists | 0:0fdadbc3d852 | 85 | CSTN /* color STN */ |
embeddedartists | 0:0fdadbc3d852 | 86 | } nxp_lcd_panel_t; |
embeddedartists | 0:0fdadbc3d852 | 87 | |
embeddedartists | 0:0fdadbc3d852 | 88 | typedef struct { |
embeddedartists | 0:0fdadbc3d852 | 89 | uint8_t h_back_porch; /* Horizontal back porch in clocks */ |
embeddedartists | 0:0fdadbc3d852 | 90 | uint8_t h_front_porch; /* Horizontal front porch in clocks */ |
embeddedartists | 0:0fdadbc3d852 | 91 | uint8_t h_sync_pulse_width; /* HSYNC pulse width in clocks */ |
embeddedartists | 0:0fdadbc3d852 | 92 | uint16_t pixels_per_line; /* Pixels per line (horizontal resolution) */ |
embeddedartists | 0:0fdadbc3d852 | 93 | uint8_t v_back_porch; /* Vertical back porch in clocks */ |
embeddedartists | 0:0fdadbc3d852 | 94 | uint8_t v_front_porch; /* Vertical front porch in clocks */ |
embeddedartists | 0:0fdadbc3d852 | 95 | uint8_t v_sync_pulse_width; /* VSYNC pulse width in clocks */ |
embeddedartists | 0:0fdadbc3d852 | 96 | uint16_t lines_per_panel; /* Lines per panel (vertical resolution) */ |
embeddedartists | 0:0fdadbc3d852 | 97 | uint8_t invert_output_enable; /* Invert output enable, 1 = invert*/ |
embeddedartists | 0:0fdadbc3d852 | 98 | uint8_t invert_panel_clock; /* Invert panel clock, 1 = invert*/ |
embeddedartists | 0:0fdadbc3d852 | 99 | uint8_t invert_hsync; /* Invert HSYNC, 1 = invert */ |
embeddedartists | 0:0fdadbc3d852 | 100 | uint8_t invert_vsync; /* Invert VSYNC, 1 = invert */ |
embeddedartists | 0:0fdadbc3d852 | 101 | uint8_t ac_bias_frequency; /* AC bias frequency in clocks */ |
embeddedartists | 0:0fdadbc3d852 | 102 | uint8_t bits_per_pixel; /* Maximum bits per pixel the display supports */ |
embeddedartists | 0:0fdadbc3d852 | 103 | uint32_t optimal_clock; /* Optimal clock rate (Hz) */ |
embeddedartists | 0:0fdadbc3d852 | 104 | nxp_lcd_panel_t lcd_panel_type; /* LCD panel type */ |
embeddedartists | 0:0fdadbc3d852 | 105 | uint8_t dual_panel; /* Dual panel, 1 = dual panel display */ |
embeddedartists | 0:0fdadbc3d852 | 106 | } nxp_lcd_param_t; |
embeddedartists | 0:0fdadbc3d852 | 107 | |
embeddedartists | 0:0fdadbc3d852 | 108 | static uint32_t str_to_uint(char* str, uint32_t len); |
embeddedartists | 0:0fdadbc3d852 | 109 | |
embeddedartists | 0:0fdadbc3d852 | 110 | EaLcdBoard::EaLcdBoard(PinName sda, PinName scl) : _i2c(sda, scl) { |
embeddedartists | 0:0fdadbc3d852 | 111 | _blink0Shadow = 0; |
embeddedartists | 0:0fdadbc3d852 | 112 | _blink1Shadow = 0; |
embeddedartists | 0:0fdadbc3d852 | 113 | _ledStateShadow = 0; |
embeddedartists | 0:0fdadbc3d852 | 114 | _lcdPwrOn = false; |
embeddedartists | 0:0fdadbc3d852 | 115 | } |
embeddedartists | 0:0fdadbc3d852 | 116 | |
embeddedartists | 0:0fdadbc3d852 | 117 | EaLcdBoard::Result EaLcdBoard::open(LcdController::Config* cfg, char* initSeq) { |
embeddedartists | 0:0fdadbc3d852 | 118 | |
embeddedartists | 0:0fdadbc3d852 | 119 | EaLcdBoard::Result result = Ok; |
embeddedartists | 0:0fdadbc3d852 | 120 | |
embeddedartists | 0:0fdadbc3d852 | 121 | // load LCD configuration from storage |
embeddedartists | 0:0fdadbc3d852 | 122 | if (cfg == NULL) { |
embeddedartists | 0:0fdadbc3d852 | 123 | result = getLcdConfig(&_cfg); |
embeddedartists | 0:0fdadbc3d852 | 124 | cfg = &_cfg; |
embeddedartists | 0:0fdadbc3d852 | 125 | } |
embeddedartists | 0:0fdadbc3d852 | 126 | |
embeddedartists | 0:0fdadbc3d852 | 127 | // load init sequence from storage |
embeddedartists | 0:0fdadbc3d852 | 128 | if (result == Ok && initSeq == NULL) { |
embeddedartists | 0:0fdadbc3d852 | 129 | result = getInitSeq((char*)eaLcdTmpBuffer, EA_LCD_TMP_BUFFER_SZ); |
embeddedartists | 0:0fdadbc3d852 | 130 | initSeq = (char*)eaLcdTmpBuffer; |
embeddedartists | 0:0fdadbc3d852 | 131 | } |
embeddedartists | 0:0fdadbc3d852 | 132 | |
embeddedartists | 0:0fdadbc3d852 | 133 | if (result != Ok) { |
embeddedartists | 0:0fdadbc3d852 | 134 | return result; |
embeddedartists | 0:0fdadbc3d852 | 135 | } |
embeddedartists | 0:0fdadbc3d852 | 136 | |
embeddedartists | 0:0fdadbc3d852 | 137 | return parseInitString(initSeq, cfg); |
embeddedartists | 0:0fdadbc3d852 | 138 | } |
embeddedartists | 0:0fdadbc3d852 | 139 | |
embeddedartists | 0:0fdadbc3d852 | 140 | EaLcdBoard::Result EaLcdBoard::close() { |
embeddedartists | 0:0fdadbc3d852 | 141 | int r = 0; |
embeddedartists | 0:0fdadbc3d852 | 142 | |
embeddedartists | 0:0fdadbc3d852 | 143 | do { |
embeddedartists | 0:0fdadbc3d852 | 144 | r = lcdCtrl.setPower(false); |
embeddedartists | 0:0fdadbc3d852 | 145 | if (r != 0) break; |
embeddedartists | 0:0fdadbc3d852 | 146 | |
embeddedartists | 0:0fdadbc3d852 | 147 | _lcdPwrOn = false; |
embeddedartists | 0:0fdadbc3d852 | 148 | |
embeddedartists | 0:0fdadbc3d852 | 149 | r = lcdCtrl.close(); |
embeddedartists | 0:0fdadbc3d852 | 150 | } while(0); |
embeddedartists | 0:0fdadbc3d852 | 151 | |
embeddedartists | 0:0fdadbc3d852 | 152 | if (r != 0) { |
embeddedartists | 0:0fdadbc3d852 | 153 | return LcdAccessError; |
embeddedartists | 0:0fdadbc3d852 | 154 | } |
embeddedartists | 0:0fdadbc3d852 | 155 | |
embeddedartists | 0:0fdadbc3d852 | 156 | return Ok; |
embeddedartists | 0:0fdadbc3d852 | 157 | } |
embeddedartists | 0:0fdadbc3d852 | 158 | |
embeddedartists | 0:0fdadbc3d852 | 159 | EaLcdBoard::Result EaLcdBoard::setFrameBuffer(uint32_t address) { |
embeddedartists | 0:0fdadbc3d852 | 160 | int r = 0; |
embeddedartists | 0:0fdadbc3d852 | 161 | |
embeddedartists | 0:0fdadbc3d852 | 162 | do { |
embeddedartists | 0:0fdadbc3d852 | 163 | |
embeddedartists | 0:0fdadbc3d852 | 164 | // begin by powering on the display |
embeddedartists | 0:0fdadbc3d852 | 165 | if (!_lcdPwrOn) { |
embeddedartists | 0:0fdadbc3d852 | 166 | r = lcdCtrl.setPower(true); |
embeddedartists | 0:0fdadbc3d852 | 167 | if (r != 0) break; |
embeddedartists | 0:0fdadbc3d852 | 168 | |
embeddedartists | 0:0fdadbc3d852 | 169 | _lcdPwrOn = true; |
embeddedartists | 0:0fdadbc3d852 | 170 | } |
embeddedartists | 0:0fdadbc3d852 | 171 | |
embeddedartists | 0:0fdadbc3d852 | 172 | // activate specified frame buffer |
embeddedartists | 0:0fdadbc3d852 | 173 | r = lcdCtrl.setFrameBuffer(address); |
embeddedartists | 0:0fdadbc3d852 | 174 | if (r != 0) break; |
embeddedartists | 0:0fdadbc3d852 | 175 | |
embeddedartists | 0:0fdadbc3d852 | 176 | } while(0); |
embeddedartists | 0:0fdadbc3d852 | 177 | |
embeddedartists | 0:0fdadbc3d852 | 178 | if (r != 0) { |
embeddedartists | 0:0fdadbc3d852 | 179 | return LcdAccessError; |
embeddedartists | 0:0fdadbc3d852 | 180 | } |
embeddedartists | 0:0fdadbc3d852 | 181 | |
embeddedartists | 0:0fdadbc3d852 | 182 | |
embeddedartists | 0:0fdadbc3d852 | 183 | return Ok; |
embeddedartists | 0:0fdadbc3d852 | 184 | } |
embeddedartists | 0:0fdadbc3d852 | 185 | |
embeddedartists | 0:0fdadbc3d852 | 186 | EaLcdBoard::Result EaLcdBoard::getLcdConfig(LcdController::Config* cfg) { |
embeddedartists | 0:0fdadbc3d852 | 187 | store_t h; |
embeddedartists | 0:0fdadbc3d852 | 188 | |
embeddedartists | 0:0fdadbc3d852 | 189 | nxp_lcd_param_t lcdParam; |
embeddedartists | 0:0fdadbc3d852 | 190 | |
embeddedartists | 4:b32cf4ef45c5 | 191 | if (cfg == NULL) { |
embeddedartists | 4:b32cf4ef45c5 | 192 | return InvalidArgument; |
embeddedartists | 4:b32cf4ef45c5 | 193 | } |
embeddedartists | 4:b32cf4ef45c5 | 194 | |
embeddedartists | 0:0fdadbc3d852 | 195 | getStore(&h); |
embeddedartists | 0:0fdadbc3d852 | 196 | |
embeddedartists | 0:0fdadbc3d852 | 197 | if (h.magic != LCDB_MAGIC) { |
embeddedartists | 0:0fdadbc3d852 | 198 | return InvalidStorage; |
embeddedartists | 0:0fdadbc3d852 | 199 | } |
embeddedartists | 0:0fdadbc3d852 | 200 | |
embeddedartists | 0:0fdadbc3d852 | 201 | eepromRead((uint8_t*)&lcdParam, h.lcdParamOff, |
embeddedartists | 0:0fdadbc3d852 | 202 | (h.initOff-h.lcdParamOff)); |
embeddedartists | 0:0fdadbc3d852 | 203 | |
embeddedartists | 0:0fdadbc3d852 | 204 | cfg->horizontalBackPorch = lcdParam.h_back_porch; |
embeddedartists | 0:0fdadbc3d852 | 205 | cfg->horizontalFrontPorch = lcdParam.h_front_porch; |
embeddedartists | 0:0fdadbc3d852 | 206 | cfg->hsync = lcdParam.h_sync_pulse_width; |
embeddedartists | 0:0fdadbc3d852 | 207 | cfg->width = lcdParam.pixels_per_line; |
embeddedartists | 0:0fdadbc3d852 | 208 | cfg->verticalBackPorch = lcdParam.v_back_porch; |
embeddedartists | 0:0fdadbc3d852 | 209 | cfg->verticalFrontPorch = lcdParam.v_front_porch; |
embeddedartists | 0:0fdadbc3d852 | 210 | cfg->vsync = lcdParam.v_sync_pulse_width; |
embeddedartists | 0:0fdadbc3d852 | 211 | cfg->height = lcdParam.lines_per_panel; |
embeddedartists | 0:0fdadbc3d852 | 212 | cfg->invertOutputEnable = (lcdParam.invert_output_enable == 1); |
embeddedartists | 0:0fdadbc3d852 | 213 | cfg->invertPanelClock = (lcdParam.invert_panel_clock == 1); |
embeddedartists | 0:0fdadbc3d852 | 214 | cfg->invertHsync = (lcdParam.invert_hsync == 1); |
embeddedartists | 0:0fdadbc3d852 | 215 | cfg->invertVsync = (lcdParam.invert_vsync == 1); |
embeddedartists | 0:0fdadbc3d852 | 216 | cfg->acBias = lcdParam.ac_bias_frequency; |
embeddedartists | 0:0fdadbc3d852 | 217 | cfg->bpp = LcdController::Bpp_16_565; |
embeddedartists | 0:0fdadbc3d852 | 218 | cfg->optimalClock = lcdParam.optimal_clock; |
embeddedartists | 0:0fdadbc3d852 | 219 | cfg->panelType = (LcdController::LcdPanel)lcdParam.lcd_panel_type; |
embeddedartists | 0:0fdadbc3d852 | 220 | cfg->dualPanel = (lcdParam.dual_panel == 1); |
embeddedartists | 0:0fdadbc3d852 | 221 | |
embeddedartists | 0:0fdadbc3d852 | 222 | return Ok; |
embeddedartists | 0:0fdadbc3d852 | 223 | } |
embeddedartists | 0:0fdadbc3d852 | 224 | |
embeddedartists | 0:0fdadbc3d852 | 225 | EaLcdBoard::Result EaLcdBoard::getDisplayName(char* buf, int len) { |
embeddedartists | 0:0fdadbc3d852 | 226 | store_t h; |
embeddedartists | 0:0fdadbc3d852 | 227 | |
embeddedartists | 4:b32cf4ef45c5 | 228 | if (buf == NULL) { |
embeddedartists | 4:b32cf4ef45c5 | 229 | return InvalidArgument; |
embeddedartists | 4:b32cf4ef45c5 | 230 | } |
embeddedartists | 4:b32cf4ef45c5 | 231 | |
embeddedartists | 0:0fdadbc3d852 | 232 | getStore(&h); |
embeddedartists | 0:0fdadbc3d852 | 233 | |
embeddedartists | 0:0fdadbc3d852 | 234 | if (h.magic != LCDB_MAGIC) { |
embeddedartists | 0:0fdadbc3d852 | 235 | return InvalidStorage; |
embeddedartists | 0:0fdadbc3d852 | 236 | } |
embeddedartists | 0:0fdadbc3d852 | 237 | |
embeddedartists | 0:0fdadbc3d852 | 238 | if (len < NameBufferSize) { |
embeddedartists | 0:0fdadbc3d852 | 239 | return BufferTooSmall; |
embeddedartists | 0:0fdadbc3d852 | 240 | } |
embeddedartists | 0:0fdadbc3d852 | 241 | |
embeddedartists | 0:0fdadbc3d852 | 242 | strncpy(buf, (char*)h.lcd_name, NameBufferSize); |
embeddedartists | 0:0fdadbc3d852 | 243 | |
embeddedartists | 0:0fdadbc3d852 | 244 | return Ok; |
embeddedartists | 0:0fdadbc3d852 | 245 | } |
embeddedartists | 0:0fdadbc3d852 | 246 | |
embeddedartists | 0:0fdadbc3d852 | 247 | EaLcdBoard::Result EaLcdBoard::getDisplayMfg(char* buf, int len) { |
embeddedartists | 0:0fdadbc3d852 | 248 | store_t h; |
embeddedartists | 0:0fdadbc3d852 | 249 | |
embeddedartists | 4:b32cf4ef45c5 | 250 | if (buf == NULL) { |
embeddedartists | 4:b32cf4ef45c5 | 251 | return InvalidArgument; |
embeddedartists | 4:b32cf4ef45c5 | 252 | } |
embeddedartists | 4:b32cf4ef45c5 | 253 | |
embeddedartists | 0:0fdadbc3d852 | 254 | getStore(&h); |
embeddedartists | 0:0fdadbc3d852 | 255 | |
embeddedartists | 0:0fdadbc3d852 | 256 | if (h.magic != LCDB_MAGIC) { |
embeddedartists | 0:0fdadbc3d852 | 257 | return InvalidStorage; |
embeddedartists | 0:0fdadbc3d852 | 258 | } |
embeddedartists | 0:0fdadbc3d852 | 259 | |
embeddedartists | 0:0fdadbc3d852 | 260 | if (len < NameBufferSize) { |
embeddedartists | 0:0fdadbc3d852 | 261 | return BufferTooSmall; |
embeddedartists | 0:0fdadbc3d852 | 262 | } |
embeddedartists | 0:0fdadbc3d852 | 263 | |
embeddedartists | 0:0fdadbc3d852 | 264 | strncpy(buf, (char*)h.lcd_mfg, NameBufferSize); |
embeddedartists | 0:0fdadbc3d852 | 265 | |
embeddedartists | 0:0fdadbc3d852 | 266 | return Ok; |
embeddedartists | 0:0fdadbc3d852 | 267 | } |
embeddedartists | 0:0fdadbc3d852 | 268 | |
embeddedartists | 0:0fdadbc3d852 | 269 | EaLcdBoard::Result EaLcdBoard::getInitSeq(char* buf, int len) { |
embeddedartists | 0:0fdadbc3d852 | 270 | store_t h; |
embeddedartists | 0:0fdadbc3d852 | 271 | |
embeddedartists | 4:b32cf4ef45c5 | 272 | if (buf == NULL) { |
embeddedartists | 4:b32cf4ef45c5 | 273 | return InvalidArgument; |
embeddedartists | 4:b32cf4ef45c5 | 274 | } |
embeddedartists | 4:b32cf4ef45c5 | 275 | |
embeddedartists | 0:0fdadbc3d852 | 276 | getStore(&h); |
embeddedartists | 0:0fdadbc3d852 | 277 | |
embeddedartists | 0:0fdadbc3d852 | 278 | if (h.magic != LCDB_MAGIC) { |
embeddedartists | 0:0fdadbc3d852 | 279 | return InvalidStorage; |
embeddedartists | 0:0fdadbc3d852 | 280 | } |
embeddedartists | 0:0fdadbc3d852 | 281 | |
embeddedartists | 0:0fdadbc3d852 | 282 | if ((h.pdOff-h.initOff) > len) { |
embeddedartists | 0:0fdadbc3d852 | 283 | return BufferTooSmall; |
embeddedartists | 0:0fdadbc3d852 | 284 | } |
embeddedartists | 0:0fdadbc3d852 | 285 | |
embeddedartists | 0:0fdadbc3d852 | 286 | eepromRead((uint8_t*)buf, h.initOff, |
embeddedartists | 0:0fdadbc3d852 | 287 | (h.pdOff-h.initOff)); |
embeddedartists | 0:0fdadbc3d852 | 288 | |
embeddedartists | 0:0fdadbc3d852 | 289 | return Ok; |
embeddedartists | 0:0fdadbc3d852 | 290 | } |
embeddedartists | 0:0fdadbc3d852 | 291 | |
embeddedartists | 0:0fdadbc3d852 | 292 | EaLcdBoard::Result EaLcdBoard::getPowerDownSeq(char* buf, int len) { |
embeddedartists | 0:0fdadbc3d852 | 293 | store_t h; |
embeddedartists | 0:0fdadbc3d852 | 294 | |
embeddedartists | 4:b32cf4ef45c5 | 295 | if (buf == NULL) { |
embeddedartists | 4:b32cf4ef45c5 | 296 | return InvalidArgument; |
embeddedartists | 4:b32cf4ef45c5 | 297 | } |
embeddedartists | 4:b32cf4ef45c5 | 298 | |
embeddedartists | 0:0fdadbc3d852 | 299 | getStore(&h); |
embeddedartists | 0:0fdadbc3d852 | 300 | |
embeddedartists | 0:0fdadbc3d852 | 301 | if (h.magic != LCDB_MAGIC) { |
embeddedartists | 0:0fdadbc3d852 | 302 | return InvalidStorage; |
embeddedartists | 0:0fdadbc3d852 | 303 | } |
embeddedartists | 0:0fdadbc3d852 | 304 | |
embeddedartists | 0:0fdadbc3d852 | 305 | if ((h.tsOff-h.pdOff) > len) { |
embeddedartists | 0:0fdadbc3d852 | 306 | return BufferTooSmall; |
embeddedartists | 0:0fdadbc3d852 | 307 | } |
embeddedartists | 0:0fdadbc3d852 | 308 | |
embeddedartists | 0:0fdadbc3d852 | 309 | eepromRead((uint8_t*)buf, h.pdOff, |
embeddedartists | 0:0fdadbc3d852 | 310 | (h.tsOff-h.pdOff)); |
embeddedartists | 0:0fdadbc3d852 | 311 | |
embeddedartists | 0:0fdadbc3d852 | 312 | return Ok; |
embeddedartists | 0:0fdadbc3d852 | 313 | } |
embeddedartists | 0:0fdadbc3d852 | 314 | |
embeddedartists | 4:b32cf4ef45c5 | 315 | EaLcdBoard::Result EaLcdBoard::getTouchParameters(TouchParams_t* params) { |
embeddedartists | 4:b32cf4ef45c5 | 316 | store_t h; |
embeddedartists | 4:b32cf4ef45c5 | 317 | |
embeddedartists | 4:b32cf4ef45c5 | 318 | if (params == NULL) { |
embeddedartists | 4:b32cf4ef45c5 | 319 | return InvalidArgument; |
embeddedartists | 4:b32cf4ef45c5 | 320 | } |
embeddedartists | 4:b32cf4ef45c5 | 321 | |
embeddedartists | 4:b32cf4ef45c5 | 322 | getStore(&h); |
embeddedartists | 4:b32cf4ef45c5 | 323 | |
embeddedartists | 4:b32cf4ef45c5 | 324 | if (h.magic != LCDB_MAGIC) { |
embeddedartists | 4:b32cf4ef45c5 | 325 | return InvalidStorage; |
embeddedartists | 4:b32cf4ef45c5 | 326 | } |
embeddedartists | 4:b32cf4ef45c5 | 327 | |
embeddedartists | 4:b32cf4ef45c5 | 328 | |
embeddedartists | 4:b32cf4ef45c5 | 329 | if (eepromRead((uint8_t*)params, h.tsOff, |
embeddedartists | 4:b32cf4ef45c5 | 330 | (h.end-h.tsOff)) == -1) { |
embeddedartists | 4:b32cf4ef45c5 | 331 | return InvalidStorage; |
embeddedartists | 4:b32cf4ef45c5 | 332 | } |
embeddedartists | 4:b32cf4ef45c5 | 333 | |
embeddedartists | 4:b32cf4ef45c5 | 334 | |
embeddedartists | 4:b32cf4ef45c5 | 335 | if (params->panelId <= TouchPanelInvalidFirst |
embeddedartists | 4:b32cf4ef45c5 | 336 | || params->panelId >= TouchPanelInvalidLast) { |
embeddedartists | 4:b32cf4ef45c5 | 337 | params->panelId = TouchPanelUnknown; |
embeddedartists | 4:b32cf4ef45c5 | 338 | } |
embeddedartists | 4:b32cf4ef45c5 | 339 | |
embeddedartists | 4:b32cf4ef45c5 | 340 | |
embeddedartists | 4:b32cf4ef45c5 | 341 | return Ok; |
embeddedartists | 4:b32cf4ef45c5 | 342 | } |
embeddedartists | 4:b32cf4ef45c5 | 343 | |
embeddedartists | 4:b32cf4ef45c5 | 344 | EaLcdBoard::Result EaLcdBoard::storeParameters( |
embeddedartists | 4:b32cf4ef45c5 | 345 | const char* lcdName, |
embeddedartists | 4:b32cf4ef45c5 | 346 | const char* lcdMfg, |
embeddedartists | 4:b32cf4ef45c5 | 347 | LcdController::Config* cfg, |
embeddedartists | 4:b32cf4ef45c5 | 348 | const char* initSeqStr, |
embeddedartists | 4:b32cf4ef45c5 | 349 | const char* pdSeqStr, |
embeddedartists | 4:b32cf4ef45c5 | 350 | TouchParams_t* touch, |
embeddedartists | 4:b32cf4ef45c5 | 351 | bool controlWp) |
embeddedartists | 4:b32cf4ef45c5 | 352 | { |
embeddedartists | 4:b32cf4ef45c5 | 353 | store_t h; |
embeddedartists | 4:b32cf4ef45c5 | 354 | nxp_lcd_param_t lcdParam; |
embeddedartists | 4:b32cf4ef45c5 | 355 | |
embeddedartists | 4:b32cf4ef45c5 | 356 | if (lcdName == NULL || lcdMfg == NULL || cfg == NULL |
embeddedartists | 4:b32cf4ef45c5 | 357 | || initSeqStr == NULL || pdSeqStr == NULL) { |
embeddedartists | 4:b32cf4ef45c5 | 358 | return InvalidArgument; |
embeddedartists | 4:b32cf4ef45c5 | 359 | |
embeddedartists | 4:b32cf4ef45c5 | 360 | } |
embeddedartists | 4:b32cf4ef45c5 | 361 | |
embeddedartists | 4:b32cf4ef45c5 | 362 | |
embeddedartists | 4:b32cf4ef45c5 | 363 | lcdParam.h_back_porch = cfg->horizontalBackPorch; |
embeddedartists | 4:b32cf4ef45c5 | 364 | lcdParam.h_front_porch = cfg->horizontalFrontPorch; |
embeddedartists | 4:b32cf4ef45c5 | 365 | lcdParam.h_sync_pulse_width = cfg->hsync; |
embeddedartists | 4:b32cf4ef45c5 | 366 | lcdParam.pixels_per_line = cfg->width; |
embeddedartists | 4:b32cf4ef45c5 | 367 | lcdParam.v_back_porch = cfg->verticalBackPorch; |
embeddedartists | 4:b32cf4ef45c5 | 368 | lcdParam.v_front_porch = cfg->verticalFrontPorch; |
embeddedartists | 4:b32cf4ef45c5 | 369 | lcdParam.v_sync_pulse_width = cfg->vsync; |
embeddedartists | 4:b32cf4ef45c5 | 370 | lcdParam.lines_per_panel = cfg->height; |
embeddedartists | 4:b32cf4ef45c5 | 371 | lcdParam.invert_output_enable = (cfg->invertOutputEnable ? 1 : 0); |
embeddedartists | 4:b32cf4ef45c5 | 372 | lcdParam.invert_panel_clock = (cfg->invertPanelClock ? 1 : 0); |
embeddedartists | 4:b32cf4ef45c5 | 373 | lcdParam.invert_hsync = (cfg->invertHsync ? 1 : 0); |
embeddedartists | 4:b32cf4ef45c5 | 374 | lcdParam.invert_vsync = (cfg->invertVsync ? 1 : 0); |
embeddedartists | 4:b32cf4ef45c5 | 375 | lcdParam.ac_bias_frequency = cfg->acBias; |
embeddedartists | 4:b32cf4ef45c5 | 376 | lcdParam.optimal_clock = cfg->optimalClock; |
embeddedartists | 4:b32cf4ef45c5 | 377 | lcdParam.lcd_panel_type = (nxp_lcd_panel_t)cfg->panelType; |
embeddedartists | 4:b32cf4ef45c5 | 378 | lcdParam.dual_panel = (cfg->dualPanel ? 1 : 0); |
embeddedartists | 4:b32cf4ef45c5 | 379 | |
embeddedartists | 4:b32cf4ef45c5 | 380 | |
embeddedartists | 4:b32cf4ef45c5 | 381 | h.magic = LCDB_MAGIC; |
embeddedartists | 4:b32cf4ef45c5 | 382 | strncpy((char*)h.lcd_name, lcdName, 30); |
embeddedartists | 4:b32cf4ef45c5 | 383 | strncpy((char*)h.lcd_mfg, lcdMfg, 30); |
embeddedartists | 4:b32cf4ef45c5 | 384 | |
embeddedartists | 4:b32cf4ef45c5 | 385 | h.lcdParamOff = sizeof(store_t); |
embeddedartists | 4:b32cf4ef45c5 | 386 | h.initOff = h.lcdParamOff + sizeof(nxp_lcd_param_t); |
embeddedartists | 4:b32cf4ef45c5 | 387 | h.pdOff = h.initOff + strlen(initSeqStr)+1; |
embeddedartists | 4:b32cf4ef45c5 | 388 | h.tsOff = h.pdOff + strlen(pdSeqStr)+1; |
embeddedartists | 4:b32cf4ef45c5 | 389 | h.end = h.tsOff + sizeof(TouchParams_t); |
embeddedartists | 4:b32cf4ef45c5 | 390 | |
embeddedartists | 4:b32cf4ef45c5 | 391 | if (controlWp) setWriteProtect(false); |
embeddedartists | 4:b32cf4ef45c5 | 392 | eepromWrite((uint8_t*)&h, 0, h.lcdParamOff); |
embeddedartists | 4:b32cf4ef45c5 | 393 | eepromWrite((uint8_t*)&lcdParam, h.lcdParamOff, (h.initOff-h.lcdParamOff)); |
embeddedartists | 4:b32cf4ef45c5 | 394 | eepromWrite((uint8_t*)initSeqStr, h.initOff, (h.pdOff-h.initOff)); |
embeddedartists | 4:b32cf4ef45c5 | 395 | eepromWrite((uint8_t*)pdSeqStr, h.pdOff, (h.tsOff-h.pdOff)); |
embeddedartists | 4:b32cf4ef45c5 | 396 | eepromWrite((uint8_t*)touch, h.tsOff, (h.end-h.tsOff)); |
embeddedartists | 4:b32cf4ef45c5 | 397 | if (controlWp) setWriteProtect(true); |
embeddedartists | 4:b32cf4ef45c5 | 398 | |
embeddedartists | 4:b32cf4ef45c5 | 399 | return Ok; |
embeddedartists | 4:b32cf4ef45c5 | 400 | } |
embeddedartists | 4:b32cf4ef45c5 | 401 | |
embeddedartists | 0:0fdadbc3d852 | 402 | EaLcdBoard::Result EaLcdBoard::getStore(store_t* store) { |
embeddedartists | 0:0fdadbc3d852 | 403 | int num = 0; |
embeddedartists | 0:0fdadbc3d852 | 404 | |
embeddedartists | 0:0fdadbc3d852 | 405 | if (store == NULL) return InvalidArgument; |
embeddedartists | 0:0fdadbc3d852 | 406 | |
embeddedartists | 0:0fdadbc3d852 | 407 | num = eepromRead((uint8_t*)store, 0, sizeof(store_t)); |
embeddedartists | 0:0fdadbc3d852 | 408 | if (num < (int)sizeof(store_t)) { |
embeddedartists | 0:0fdadbc3d852 | 409 | return InvalidStorage; |
embeddedartists | 0:0fdadbc3d852 | 410 | } |
embeddedartists | 0:0fdadbc3d852 | 411 | |
embeddedartists | 0:0fdadbc3d852 | 412 | return Ok; |
embeddedartists | 0:0fdadbc3d852 | 413 | } |
embeddedartists | 0:0fdadbc3d852 | 414 | |
embeddedartists | 0:0fdadbc3d852 | 415 | // ########################### |
embeddedartists | 0:0fdadbc3d852 | 416 | // An EEPROM is used for persistent storage |
embeddedartists | 0:0fdadbc3d852 | 417 | // ########################### |
embeddedartists | 0:0fdadbc3d852 | 418 | |
embeddedartists | 0:0fdadbc3d852 | 419 | int EaLcdBoard::eepromRead(uint8_t* buf, uint16_t offset, uint16_t len) { |
embeddedartists | 0:0fdadbc3d852 | 420 | int i = 0; |
embeddedartists | 0:0fdadbc3d852 | 421 | char off[2]; |
embeddedartists | 4:b32cf4ef45c5 | 422 | uint16_t retLen = 0; |
embeddedartists | 0:0fdadbc3d852 | 423 | |
embeddedartists | 0:0fdadbc3d852 | 424 | if (len > LCDB_EEPROM_TOTAL_SIZE || offset+len > LCDB_EEPROM_TOTAL_SIZE) { |
embeddedartists | 0:0fdadbc3d852 | 425 | return -1; |
embeddedartists | 0:0fdadbc3d852 | 426 | } |
embeddedartists | 0:0fdadbc3d852 | 427 | |
embeddedartists | 4:b32cf4ef45c5 | 428 | wait_ms(10); |
embeddedartists | 4:b32cf4ef45c5 | 429 | |
embeddedartists | 0:0fdadbc3d852 | 430 | off[0] = ((offset >> 8) & 0xff); |
embeddedartists | 0:0fdadbc3d852 | 431 | off[1] = (offset & 0xff); |
embeddedartists | 0:0fdadbc3d852 | 432 | |
embeddedartists | 4:b32cf4ef45c5 | 433 | do { |
embeddedartists | 4:b32cf4ef45c5 | 434 | if (_i2c.write(LCDB_EEPROM_I2C_ADDR, (char*)off, 2) != 0) break; |
embeddedartists | 4:b32cf4ef45c5 | 435 | for ( i = 0; i < 0x2000; i++); |
embeddedartists | 4:b32cf4ef45c5 | 436 | if (_i2c.read(LCDB_EEPROM_I2C_ADDR, (char*)buf, len) != 0) break; |
embeddedartists | 0:0fdadbc3d852 | 437 | |
embeddedartists | 4:b32cf4ef45c5 | 438 | retLen = len; |
embeddedartists | 4:b32cf4ef45c5 | 439 | } while(0); |
embeddedartists | 4:b32cf4ef45c5 | 440 | |
embeddedartists | 4:b32cf4ef45c5 | 441 | return retLen; |
embeddedartists | 0:0fdadbc3d852 | 442 | } |
embeddedartists | 0:0fdadbc3d852 | 443 | |
embeddedartists | 0:0fdadbc3d852 | 444 | int EaLcdBoard::eepromWrite(uint8_t* buf, uint16_t offset, uint16_t len) { |
embeddedartists | 0:0fdadbc3d852 | 445 | int16_t written = 0; |
embeddedartists | 0:0fdadbc3d852 | 446 | uint16_t wLen = 0; |
embeddedartists | 0:0fdadbc3d852 | 447 | uint16_t off = offset; |
embeddedartists | 0:0fdadbc3d852 | 448 | uint8_t tmp[LCDB_EEPROM_PAGE_SIZE+2]; |
embeddedartists | 0:0fdadbc3d852 | 449 | |
embeddedartists | 0:0fdadbc3d852 | 450 | if (len > LCDB_EEPROM_TOTAL_SIZE || offset+len > LCDB_EEPROM_TOTAL_SIZE) { |
embeddedartists | 0:0fdadbc3d852 | 451 | return -1; |
embeddedartists | 0:0fdadbc3d852 | 452 | } |
embeddedartists | 0:0fdadbc3d852 | 453 | |
embeddedartists | 4:b32cf4ef45c5 | 454 | wait_ms(1); |
embeddedartists | 4:b32cf4ef45c5 | 455 | |
embeddedartists | 0:0fdadbc3d852 | 456 | wLen = LCDB_EEPROM_PAGE_SIZE - (off % LCDB_EEPROM_PAGE_SIZE); |
embeddedartists | 0:0fdadbc3d852 | 457 | wLen = MIN(wLen, len); |
embeddedartists | 0:0fdadbc3d852 | 458 | |
embeddedartists | 0:0fdadbc3d852 | 459 | while (len) { |
embeddedartists | 0:0fdadbc3d852 | 460 | tmp[0] = ((off >> 8) & 0xff); |
embeddedartists | 0:0fdadbc3d852 | 461 | tmp[1] = (off & 0xff); |
embeddedartists | 0:0fdadbc3d852 | 462 | memcpy(&tmp[2], (void*)&buf[written], wLen); |
embeddedartists | 4:b32cf4ef45c5 | 463 | if (_i2c.write(LCDB_EEPROM_I2C_ADDR, (char*)tmp, wLen+2) != 0) break; |
embeddedartists | 0:0fdadbc3d852 | 464 | |
embeddedartists | 0:0fdadbc3d852 | 465 | // delay to wait for a write cycle |
embeddedartists | 0:0fdadbc3d852 | 466 | //eepromDelay(); |
embeddedartists | 4:b32cf4ef45c5 | 467 | wait_ms(10); |
embeddedartists | 0:0fdadbc3d852 | 468 | |
embeddedartists | 0:0fdadbc3d852 | 469 | len -= wLen; |
embeddedartists | 0:0fdadbc3d852 | 470 | written += wLen; |
embeddedartists | 0:0fdadbc3d852 | 471 | off += wLen; |
embeddedartists | 0:0fdadbc3d852 | 472 | |
embeddedartists | 0:0fdadbc3d852 | 473 | wLen = MIN(LCDB_EEPROM_PAGE_SIZE, len); |
embeddedartists | 0:0fdadbc3d852 | 474 | } |
embeddedartists | 0:0fdadbc3d852 | 475 | |
embeddedartists | 0:0fdadbc3d852 | 476 | return written; |
embeddedartists | 0:0fdadbc3d852 | 477 | } |
embeddedartists | 0:0fdadbc3d852 | 478 | |
embeddedartists | 0:0fdadbc3d852 | 479 | // ########################### |
embeddedartists | 0:0fdadbc3d852 | 480 | // string parsing (initialization and power down strings) |
embeddedartists | 0:0fdadbc3d852 | 481 | // ########################### |
embeddedartists | 0:0fdadbc3d852 | 482 | |
embeddedartists | 0:0fdadbc3d852 | 483 | EaLcdBoard::Result EaLcdBoard::parseInitString(char* str, LcdController::Config* cfg) { |
embeddedartists | 0:0fdadbc3d852 | 484 | char* c = NULL; |
embeddedartists | 0:0fdadbc3d852 | 485 | uint32_t len = 0; |
embeddedartists | 0:0fdadbc3d852 | 486 | Result result = Ok; |
embeddedartists | 0:0fdadbc3d852 | 487 | |
embeddedartists | 0:0fdadbc3d852 | 488 | if (str == NULL) { |
embeddedartists | 0:0fdadbc3d852 | 489 | return InvalidCommandString; |
embeddedartists | 0:0fdadbc3d852 | 490 | } |
embeddedartists | 0:0fdadbc3d852 | 491 | |
embeddedartists | 0:0fdadbc3d852 | 492 | while(*str != '\0') { |
embeddedartists | 0:0fdadbc3d852 | 493 | |
embeddedartists | 0:0fdadbc3d852 | 494 | // skip whitespaces |
embeddedartists | 0:0fdadbc3d852 | 495 | while(*str == ' ') { |
embeddedartists | 0:0fdadbc3d852 | 496 | str++; |
embeddedartists | 0:0fdadbc3d852 | 497 | } |
embeddedartists | 0:0fdadbc3d852 | 498 | |
embeddedartists | 0:0fdadbc3d852 | 499 | c = str; |
embeddedartists | 0:0fdadbc3d852 | 500 | |
embeddedartists | 0:0fdadbc3d852 | 501 | // find end of command |
embeddedartists | 0:0fdadbc3d852 | 502 | while(*str != ',' && *str != '\0') { |
embeddedartists | 0:0fdadbc3d852 | 503 | str++; |
embeddedartists | 0:0fdadbc3d852 | 504 | } |
embeddedartists | 0:0fdadbc3d852 | 505 | |
embeddedartists | 0:0fdadbc3d852 | 506 | len = (str-c); |
embeddedartists | 0:0fdadbc3d852 | 507 | |
embeddedartists | 0:0fdadbc3d852 | 508 | if (*str == ',') { |
embeddedartists | 0:0fdadbc3d852 | 509 | str++; |
embeddedartists | 0:0fdadbc3d852 | 510 | } |
embeddedartists | 0:0fdadbc3d852 | 511 | |
embeddedartists | 0:0fdadbc3d852 | 512 | switch (*c++) { |
embeddedartists | 0:0fdadbc3d852 | 513 | |
embeddedartists | 0:0fdadbc3d852 | 514 | case 'v': |
embeddedartists | 0:0fdadbc3d852 | 515 | result = checkVersion(c, len-1); |
embeddedartists | 0:0fdadbc3d852 | 516 | break; |
embeddedartists | 0:0fdadbc3d852 | 517 | |
embeddedartists | 0:0fdadbc3d852 | 518 | // sequence control command (pca9532) |
embeddedartists | 0:0fdadbc3d852 | 519 | case 'c': |
embeddedartists | 0:0fdadbc3d852 | 520 | execSeqCtrl(c, len-1); |
embeddedartists | 0:0fdadbc3d852 | 521 | break; |
embeddedartists | 0:0fdadbc3d852 | 522 | |
embeddedartists | 0:0fdadbc3d852 | 523 | // delay |
embeddedartists | 0:0fdadbc3d852 | 524 | case 'd': |
embeddedartists | 0:0fdadbc3d852 | 525 | execDelay(c, len-1); |
embeddedartists | 0:0fdadbc3d852 | 526 | break; |
embeddedartists | 0:0fdadbc3d852 | 527 | |
embeddedartists | 0:0fdadbc3d852 | 528 | // open lcd (init LCD controller) |
embeddedartists | 0:0fdadbc3d852 | 529 | case 'o': |
embeddedartists | 0:0fdadbc3d852 | 530 | |
embeddedartists | 0:0fdadbc3d852 | 531 | if (cfg != NULL) { |
embeddedartists | 0:0fdadbc3d852 | 532 | |
embeddedartists | 0:0fdadbc3d852 | 533 | if (lcdCtrl.open(cfg) != 0) { |
embeddedartists | 0:0fdadbc3d852 | 534 | result = LcdAccessError; |
embeddedartists | 0:0fdadbc3d852 | 535 | } |
embeddedartists | 0:0fdadbc3d852 | 536 | } |
embeddedartists | 0:0fdadbc3d852 | 537 | |
embeddedartists | 0:0fdadbc3d852 | 538 | else { |
embeddedartists | 0:0fdadbc3d852 | 539 | result = InvalidArgument; |
embeddedartists | 0:0fdadbc3d852 | 540 | } |
embeddedartists | 0:0fdadbc3d852 | 541 | |
embeddedartists | 0:0fdadbc3d852 | 542 | break; |
embeddedartists | 0:0fdadbc3d852 | 543 | |
embeddedartists | 4:b32cf4ef45c5 | 544 | // exec pin set |
embeddedartists | 4:b32cf4ef45c5 | 545 | case 'p': |
embeddedartists | 4:b32cf4ef45c5 | 546 | execPinSet(c, len-1); |
embeddedartists | 4:b32cf4ef45c5 | 547 | break; |
embeddedartists | 4:b32cf4ef45c5 | 548 | |
embeddedartists | 0:0fdadbc3d852 | 549 | } |
embeddedartists | 0:0fdadbc3d852 | 550 | |
embeddedartists | 0:0fdadbc3d852 | 551 | if (result != Ok) { |
embeddedartists | 0:0fdadbc3d852 | 552 | break; |
embeddedartists | 0:0fdadbc3d852 | 553 | } |
embeddedartists | 0:0fdadbc3d852 | 554 | |
embeddedartists | 0:0fdadbc3d852 | 555 | |
embeddedartists | 0:0fdadbc3d852 | 556 | } |
embeddedartists | 0:0fdadbc3d852 | 557 | |
embeddedartists | 0:0fdadbc3d852 | 558 | |
embeddedartists | 0:0fdadbc3d852 | 559 | return result; |
embeddedartists | 0:0fdadbc3d852 | 560 | } |
embeddedartists | 0:0fdadbc3d852 | 561 | |
embeddedartists | 0:0fdadbc3d852 | 562 | EaLcdBoard::Result EaLcdBoard::checkVersion(char* v, uint32_t len) { |
embeddedartists | 0:0fdadbc3d852 | 563 | uint32_t ver = str_to_uint(v, len); |
embeddedartists | 0:0fdadbc3d852 | 564 | |
embeddedartists | 0:0fdadbc3d852 | 565 | if (ver > LCDB_SEQ_VER) { |
embeddedartists | 0:0fdadbc3d852 | 566 | return VersionNotSupported; |
embeddedartists | 0:0fdadbc3d852 | 567 | } |
embeddedartists | 0:0fdadbc3d852 | 568 | |
embeddedartists | 0:0fdadbc3d852 | 569 | return Ok; |
embeddedartists | 0:0fdadbc3d852 | 570 | } |
embeddedartists | 0:0fdadbc3d852 | 571 | |
embeddedartists | 0:0fdadbc3d852 | 572 | EaLcdBoard::Result EaLcdBoard::execDelay(char* del, uint32_t len) { |
embeddedartists | 0:0fdadbc3d852 | 573 | wait_ms(str_to_uint(del, len)); |
embeddedartists | 0:0fdadbc3d852 | 574 | |
embeddedartists | 0:0fdadbc3d852 | 575 | return Ok; |
embeddedartists | 0:0fdadbc3d852 | 576 | } |
embeddedartists | 0:0fdadbc3d852 | 577 | |
embeddedartists | 0:0fdadbc3d852 | 578 | EaLcdBoard::Result EaLcdBoard::execSeqCtrl(char* cmd, uint32_t len) { |
embeddedartists | 0:0fdadbc3d852 | 579 | |
embeddedartists | 0:0fdadbc3d852 | 580 | switch (*cmd++) { |
embeddedartists | 0:0fdadbc3d852 | 581 | |
embeddedartists | 0:0fdadbc3d852 | 582 | // display enable |
embeddedartists | 0:0fdadbc3d852 | 583 | case 'd': |
embeddedartists | 0:0fdadbc3d852 | 584 | setDisplayEnableSignal(*cmd == '1'); |
embeddedartists | 0:0fdadbc3d852 | 585 | break; |
embeddedartists | 0:0fdadbc3d852 | 586 | |
embeddedartists | 0:0fdadbc3d852 | 587 | // backlight contrast |
embeddedartists | 0:0fdadbc3d852 | 588 | case 'c': |
embeddedartists | 0:0fdadbc3d852 | 589 | setBacklightContrast(str_to_uint(cmd, len)); |
embeddedartists | 0:0fdadbc3d852 | 590 | break; |
embeddedartists | 0:0fdadbc3d852 | 591 | |
embeddedartists | 0:0fdadbc3d852 | 592 | // 3v3 enable |
embeddedartists | 0:0fdadbc3d852 | 593 | case '3': |
embeddedartists | 0:0fdadbc3d852 | 594 | set3V3Signal(*cmd == '1'); |
embeddedartists | 0:0fdadbc3d852 | 595 | break; |
embeddedartists | 0:0fdadbc3d852 | 596 | |
embeddedartists | 0:0fdadbc3d852 | 597 | // 5v enable |
embeddedartists | 0:0fdadbc3d852 | 598 | case '5': |
embeddedartists | 0:0fdadbc3d852 | 599 | set5VSignal(*cmd == '1'); |
embeddedartists | 0:0fdadbc3d852 | 600 | break; |
embeddedartists | 0:0fdadbc3d852 | 601 | } |
embeddedartists | 0:0fdadbc3d852 | 602 | |
embeddedartists | 0:0fdadbc3d852 | 603 | return Ok; |
embeddedartists | 0:0fdadbc3d852 | 604 | } |
embeddedartists | 0:0fdadbc3d852 | 605 | |
embeddedartists | 4:b32cf4ef45c5 | 606 | #ifdef PORT_PIN_BUG_IN_MBED_SDK |
embeddedartists | 4:b32cf4ef45c5 | 607 | static PinName port_pin2(PortName port, int pin_n) { |
embeddedartists | 4:b32cf4ef45c5 | 608 | return (PinName)(((port << 5) | pin_n)); |
embeddedartists | 4:b32cf4ef45c5 | 609 | } |
embeddedartists | 4:b32cf4ef45c5 | 610 | #endif |
embeddedartists | 4:b32cf4ef45c5 | 611 | |
embeddedartists | 4:b32cf4ef45c5 | 612 | |
embeddedartists | 4:b32cf4ef45c5 | 613 | EaLcdBoard::Result EaLcdBoard::execPinSet(char* cmd, uint32_t len) { |
embeddedartists | 4:b32cf4ef45c5 | 614 | |
embeddedartists | 4:b32cf4ef45c5 | 615 | PortName port; |
embeddedartists | 4:b32cf4ef45c5 | 616 | |
embeddedartists | 4:b32cf4ef45c5 | 617 | do { |
embeddedartists | 4:b32cf4ef45c5 | 618 | // cmd: 0_02=1 means p0.2 = 1 |
embeddedartists | 4:b32cf4ef45c5 | 619 | if (len < 6) break; |
embeddedartists | 4:b32cf4ef45c5 | 620 | if (cmd[1] != '_' || cmd[4] != '=') break; |
embeddedartists | 4:b32cf4ef45c5 | 621 | |
embeddedartists | 4:b32cf4ef45c5 | 622 | // port |
embeddedartists | 4:b32cf4ef45c5 | 623 | int portnum = cmd[0] - '0'; |
embeddedartists | 4:b32cf4ef45c5 | 624 | if (portnum < 0 || portnum > 5) break; |
embeddedartists | 4:b32cf4ef45c5 | 625 | port = (PortName)portnum; |
embeddedartists | 4:b32cf4ef45c5 | 626 | |
embeddedartists | 4:b32cf4ef45c5 | 627 | // pin |
embeddedartists | 4:b32cf4ef45c5 | 628 | int pinnum = (10*(cmd[2]-'0'))+ cmd[3]-'0'; |
embeddedartists | 4:b32cf4ef45c5 | 629 | if (pinnum < 0 || pinnum > 31) break; |
embeddedartists | 4:b32cf4ef45c5 | 630 | |
embeddedartists | 4:b32cf4ef45c5 | 631 | // value |
embeddedartists | 4:b32cf4ef45c5 | 632 | int value = cmd[5]-'0'; |
embeddedartists | 4:b32cf4ef45c5 | 633 | if (!(value == 0 || value == 1)) break; |
embeddedartists | 4:b32cf4ef45c5 | 634 | |
embeddedartists | 4:b32cf4ef45c5 | 635 | #ifdef PORT_PIN_BUG_IN_MBED_SDK |
embeddedartists | 4:b32cf4ef45c5 | 636 | PinName pin = port_pin2(port, pinnum); |
embeddedartists | 4:b32cf4ef45c5 | 637 | #else |
embeddedartists | 4:b32cf4ef45c5 | 638 | PinName pin = port_pin(port, pinnum); |
embeddedartists | 4:b32cf4ef45c5 | 639 | #endif |
embeddedartists | 4:b32cf4ef45c5 | 640 | |
embeddedartists | 4:b32cf4ef45c5 | 641 | gpio_t gp; |
embeddedartists | 13:d868b74fd08e | 642 | gpio_init(&gp, pin); |
embeddedartists | 13:d868b74fd08e | 643 | gpio_dir(&gp, PIN_OUTPUT); |
embeddedartists | 13:d868b74fd08e | 644 | gpio_mode(&gp, PullNone); |
embeddedartists | 4:b32cf4ef45c5 | 645 | gpio_write(&gp, value); |
embeddedartists | 4:b32cf4ef45c5 | 646 | |
embeddedartists | 4:b32cf4ef45c5 | 647 | return Ok; |
embeddedartists | 4:b32cf4ef45c5 | 648 | |
embeddedartists | 4:b32cf4ef45c5 | 649 | } while (false); |
embeddedartists | 4:b32cf4ef45c5 | 650 | |
embeddedartists | 4:b32cf4ef45c5 | 651 | |
embeddedartists | 4:b32cf4ef45c5 | 652 | return InvalidCommandString; |
embeddedartists | 4:b32cf4ef45c5 | 653 | } |
embeddedartists | 4:b32cf4ef45c5 | 654 | |
embeddedartists | 4:b32cf4ef45c5 | 655 | |
embeddedartists | 0:0fdadbc3d852 | 656 | // ########################### |
embeddedartists | 0:0fdadbc3d852 | 657 | // PCA9532 is used as a control inteface to the display. |
embeddedartists | 0:0fdadbc3d852 | 658 | // voltages can be turned on/off and backlight can be controlled. |
embeddedartists | 0:0fdadbc3d852 | 659 | // ########################### |
embeddedartists | 0:0fdadbc3d852 | 660 | |
embeddedartists | 0:0fdadbc3d852 | 661 | // Helper function to set LED states |
embeddedartists | 0:0fdadbc3d852 | 662 | void EaLcdBoard::setLsStates(uint16_t states, uint8_t* ls, uint8_t mode) |
embeddedartists | 0:0fdadbc3d852 | 663 | { |
embeddedartists | 0:0fdadbc3d852 | 664 | #define IS_LED_SET(bit, x) ( ( ((x) & (bit)) != 0 ) ? 1 : 0 ) |
embeddedartists | 0:0fdadbc3d852 | 665 | |
embeddedartists | 0:0fdadbc3d852 | 666 | int i = 0; |
embeddedartists | 0:0fdadbc3d852 | 667 | |
embeddedartists | 0:0fdadbc3d852 | 668 | for (i = 0; i < 4; i++) { |
embeddedartists | 0:0fdadbc3d852 | 669 | |
embeddedartists | 0:0fdadbc3d852 | 670 | ls[i] |= ( (IS_LED_SET(0x0001, states)*mode << 0) |
embeddedartists | 0:0fdadbc3d852 | 671 | | (IS_LED_SET(0x0002, states)*mode << 2) |
embeddedartists | 0:0fdadbc3d852 | 672 | | (IS_LED_SET(0x0004, states)*mode << 4) |
embeddedartists | 0:0fdadbc3d852 | 673 | | (IS_LED_SET(0x0008, states)*mode << 6) ); |
embeddedartists | 0:0fdadbc3d852 | 674 | |
embeddedartists | 0:0fdadbc3d852 | 675 | states >>= 4; |
embeddedartists | 0:0fdadbc3d852 | 676 | } |
embeddedartists | 0:0fdadbc3d852 | 677 | } |
embeddedartists | 0:0fdadbc3d852 | 678 | |
embeddedartists | 0:0fdadbc3d852 | 679 | void EaLcdBoard::setLeds(void) |
embeddedartists | 0:0fdadbc3d852 | 680 | { |
embeddedartists | 0:0fdadbc3d852 | 681 | uint8_t buf[5]; |
embeddedartists | 0:0fdadbc3d852 | 682 | uint8_t ls[4] = {0,0,0,0}; |
embeddedartists | 0:0fdadbc3d852 | 683 | uint16_t states = _ledStateShadow; |
embeddedartists | 0:0fdadbc3d852 | 684 | |
embeddedartists | 0:0fdadbc3d852 | 685 | // LEDs in On/Off state |
embeddedartists | 0:0fdadbc3d852 | 686 | setLsStates(states, ls, LCDB_LS_MODE_ON); |
embeddedartists | 0:0fdadbc3d852 | 687 | |
embeddedartists | 0:0fdadbc3d852 | 688 | // set the LEDs that should blink |
embeddedartists | 0:0fdadbc3d852 | 689 | setLsStates(_blink0Shadow, ls, LCDB_LS_MODE_BLINK0); |
embeddedartists | 0:0fdadbc3d852 | 690 | setLsStates(_blink1Shadow, ls, LCDB_LS_MODE_BLINK1); |
embeddedartists | 0:0fdadbc3d852 | 691 | |
embeddedartists | 0:0fdadbc3d852 | 692 | buf[0] = LCDB_PCA9532_LS0 | LCDB_PCA9532_AUTO_INC; |
embeddedartists | 0:0fdadbc3d852 | 693 | buf[1] = ls[0]; |
embeddedartists | 0:0fdadbc3d852 | 694 | buf[2] = ls[1]; |
embeddedartists | 0:0fdadbc3d852 | 695 | buf[3] = ls[2]; |
embeddedartists | 0:0fdadbc3d852 | 696 | buf[4] = ls[3]; |
embeddedartists | 0:0fdadbc3d852 | 697 | |
embeddedartists | 0:0fdadbc3d852 | 698 | _i2c.write(LCDB_PCA9532_I2C_ADDR, (char*)buf, 5); |
embeddedartists | 0:0fdadbc3d852 | 699 | } |
embeddedartists | 0:0fdadbc3d852 | 700 | |
embeddedartists | 0:0fdadbc3d852 | 701 | void EaLcdBoard::pca9532_setLeds (uint16_t ledOnMask, uint16_t ledOffMask) |
embeddedartists | 0:0fdadbc3d852 | 702 | { |
embeddedartists | 0:0fdadbc3d852 | 703 | // turn off leds |
embeddedartists | 0:0fdadbc3d852 | 704 | _ledStateShadow &= (~(ledOffMask) & 0xffff); |
embeddedartists | 0:0fdadbc3d852 | 705 | |
embeddedartists | 0:0fdadbc3d852 | 706 | // ledOnMask has priority over ledOffMask |
embeddedartists | 0:0fdadbc3d852 | 707 | _ledStateShadow |= ledOnMask; |
embeddedartists | 0:0fdadbc3d852 | 708 | |
embeddedartists | 0:0fdadbc3d852 | 709 | // turn off blinking |
embeddedartists | 0:0fdadbc3d852 | 710 | _blink0Shadow &= (~(ledOffMask) & 0xffff); |
embeddedartists | 0:0fdadbc3d852 | 711 | _blink1Shadow &= (~(ledOffMask) & 0xffff); |
embeddedartists | 0:0fdadbc3d852 | 712 | |
embeddedartists | 0:0fdadbc3d852 | 713 | setLeds(); |
embeddedartists | 0:0fdadbc3d852 | 714 | } |
embeddedartists | 0:0fdadbc3d852 | 715 | |
embeddedartists | 0:0fdadbc3d852 | 716 | void EaLcdBoard::pca9532_setBlink0Period(uint8_t period) |
embeddedartists | 0:0fdadbc3d852 | 717 | { |
embeddedartists | 0:0fdadbc3d852 | 718 | uint8_t buf[2]; |
embeddedartists | 0:0fdadbc3d852 | 719 | |
embeddedartists | 0:0fdadbc3d852 | 720 | buf[0] = LCDB_PCA9532_PSC0; |
embeddedartists | 0:0fdadbc3d852 | 721 | buf[1] = period; |
embeddedartists | 0:0fdadbc3d852 | 722 | |
embeddedartists | 0:0fdadbc3d852 | 723 | _i2c.write(LCDB_PCA9532_I2C_ADDR, (char*)buf, 2); |
embeddedartists | 0:0fdadbc3d852 | 724 | } |
embeddedartists | 0:0fdadbc3d852 | 725 | |
embeddedartists | 0:0fdadbc3d852 | 726 | void EaLcdBoard::pca9532_setBlink0Duty(uint8_t duty) |
embeddedartists | 0:0fdadbc3d852 | 727 | { |
embeddedartists | 0:0fdadbc3d852 | 728 | uint8_t buf[2]; |
embeddedartists | 0:0fdadbc3d852 | 729 | uint32_t tmp = duty; |
embeddedartists | 0:0fdadbc3d852 | 730 | if (tmp > 100) { |
embeddedartists | 0:0fdadbc3d852 | 731 | tmp = 100; |
embeddedartists | 0:0fdadbc3d852 | 732 | } |
embeddedartists | 0:0fdadbc3d852 | 733 | |
embeddedartists | 0:0fdadbc3d852 | 734 | tmp = (255 * tmp)/100; |
embeddedartists | 0:0fdadbc3d852 | 735 | |
embeddedartists | 0:0fdadbc3d852 | 736 | buf[0] = LCDB_PCA9532_PWM0; |
embeddedartists | 0:0fdadbc3d852 | 737 | buf[1] = tmp; |
embeddedartists | 0:0fdadbc3d852 | 738 | |
embeddedartists | 0:0fdadbc3d852 | 739 | _i2c.write(LCDB_PCA9532_I2C_ADDR, (char*)buf, 2); |
embeddedartists | 0:0fdadbc3d852 | 740 | } |
embeddedartists | 0:0fdadbc3d852 | 741 | |
embeddedartists | 0:0fdadbc3d852 | 742 | void EaLcdBoard::pca9532_setBlink0Leds(uint16_t ledMask) |
embeddedartists | 0:0fdadbc3d852 | 743 | { |
embeddedartists | 0:0fdadbc3d852 | 744 | _blink0Shadow |= ledMask; |
embeddedartists | 0:0fdadbc3d852 | 745 | setLeds(); |
embeddedartists | 0:0fdadbc3d852 | 746 | } |
embeddedartists | 0:0fdadbc3d852 | 747 | |
embeddedartists | 4:b32cf4ef45c5 | 748 | void EaLcdBoard::setWriteProtect(bool enable) |
embeddedartists | 4:b32cf4ef45c5 | 749 | { |
embeddedartists | 4:b32cf4ef45c5 | 750 | if (enable) { |
embeddedartists | 4:b32cf4ef45c5 | 751 | pca9532_setLeds(0, LCDB_EEPROM_WP); |
embeddedartists | 4:b32cf4ef45c5 | 752 | } else { |
embeddedartists | 4:b32cf4ef45c5 | 753 | pca9532_setLeds(LCDB_EEPROM_WP, 0); |
embeddedartists | 4:b32cf4ef45c5 | 754 | } |
embeddedartists | 4:b32cf4ef45c5 | 755 | } |
embeddedartists | 4:b32cf4ef45c5 | 756 | |
embeddedartists | 0:0fdadbc3d852 | 757 | void EaLcdBoard::set3V3Signal(bool enabled) { |
embeddedartists | 0:0fdadbc3d852 | 758 | if (enabled) { |
embeddedartists | 0:0fdadbc3d852 | 759 | pca9532_setLeds(LCDB_CTRL_3V3, 0); |
embeddedartists | 0:0fdadbc3d852 | 760 | } else { |
embeddedartists | 0:0fdadbc3d852 | 761 | pca9532_setLeds(0, LCDB_CTRL_3V3); |
embeddedartists | 0:0fdadbc3d852 | 762 | } |
embeddedartists | 0:0fdadbc3d852 | 763 | } |
embeddedartists | 0:0fdadbc3d852 | 764 | |
embeddedartists | 0:0fdadbc3d852 | 765 | void EaLcdBoard::set5VSignal(bool enabled) { |
embeddedartists | 0:0fdadbc3d852 | 766 | if (enabled) { |
embeddedartists | 0:0fdadbc3d852 | 767 | pca9532_setLeds(LCDB_CTRL_5V, 0); |
embeddedartists | 0:0fdadbc3d852 | 768 | } else { |
embeddedartists | 0:0fdadbc3d852 | 769 | pca9532_setLeds(0, LCDB_CTRL_5V); |
embeddedartists | 0:0fdadbc3d852 | 770 | } |
embeddedartists | 0:0fdadbc3d852 | 771 | } |
embeddedartists | 0:0fdadbc3d852 | 772 | |
embeddedartists | 0:0fdadbc3d852 | 773 | void EaLcdBoard::setDisplayEnableSignal(bool enabled) { |
embeddedartists | 0:0fdadbc3d852 | 774 | if (!enabled) { |
embeddedartists | 0:0fdadbc3d852 | 775 | pca9532_setLeds(LCDB_CTRL_DISP_EN, 0); |
embeddedartists | 0:0fdadbc3d852 | 776 | } else { |
embeddedartists | 0:0fdadbc3d852 | 777 | pca9532_setLeds(0, LCDB_CTRL_DISP_EN); |
embeddedartists | 0:0fdadbc3d852 | 778 | } |
embeddedartists | 0:0fdadbc3d852 | 779 | } |
embeddedartists | 0:0fdadbc3d852 | 780 | |
embeddedartists | 0:0fdadbc3d852 | 781 | void EaLcdBoard::setBacklightContrast(uint32_t value) { |
embeddedartists | 0:0fdadbc3d852 | 782 | |
embeddedartists | 0:0fdadbc3d852 | 783 | if (value > 100) return; |
embeddedartists | 0:0fdadbc3d852 | 784 | |
embeddedartists | 0:0fdadbc3d852 | 785 | pca9532_setBlink0Duty(100-value); |
embeddedartists | 0:0fdadbc3d852 | 786 | pca9532_setBlink0Period(0); |
embeddedartists | 0:0fdadbc3d852 | 787 | pca9532_setBlink0Leds(LCDB_CTRL_BL_C); |
embeddedartists | 0:0fdadbc3d852 | 788 | } |
embeddedartists | 0:0fdadbc3d852 | 789 | |
embeddedartists | 0:0fdadbc3d852 | 790 | |
embeddedartists | 0:0fdadbc3d852 | 791 | // convert string to integer |
embeddedartists | 0:0fdadbc3d852 | 792 | static uint32_t str_to_uint(char* str, uint32_t len) |
embeddedartists | 0:0fdadbc3d852 | 793 | { |
embeddedartists | 0:0fdadbc3d852 | 794 | uint32_t val = 0; |
embeddedartists | 0:0fdadbc3d852 | 795 | |
embeddedartists | 0:0fdadbc3d852 | 796 | while(len > 0 && *str <= '9' && *str >= '0') { |
embeddedartists | 0:0fdadbc3d852 | 797 | val = (val * 10) + (*str - '0'); |
embeddedartists | 0:0fdadbc3d852 | 798 | str++; |
embeddedartists | 0:0fdadbc3d852 | 799 | len--; |
embeddedartists | 0:0fdadbc3d852 | 800 | } |
embeddedartists | 0:0fdadbc3d852 | 801 | |
embeddedartists | 0:0fdadbc3d852 | 802 | return val; |
embeddedartists | 0:0fdadbc3d852 | 803 | } |
embeddedartists | 0:0fdadbc3d852 | 804 | |
embeddedartists | 0:0fdadbc3d852 | 805 |