/* ucg_com_msg_api.c Universal uC Color Graphics Library Copyright (c) 2014, olikraus@gmail.com All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "ucg.h" int16_t ucg_com_template_cb(ucg_t *ucg, int16_t msg, uint32_t arg, uint8_t *data) { switch(msg) { case UCG_COM_MSG_POWER_UP: break; case UCG_COM_MSG_POWER_DOWN: break; case UCG_COM_MSG_DELAY: break; case UCG_COM_MSG_CHANGE_RESET_LINE: break; case UCG_COM_MSG_CHANGE_CS_LINE: break; case UCG_COM_MSG_CHANGE_CD_LINE: break; case UCG_COM_MSG_SEND_BYTE: break; case UCG_COM_MSG_REPEAT_1_BYTE: break; case UCG_COM_MSG_REPEAT_2_BYTES: break; case UCG_COM_MSG_REPEAT_3_BYTES: break; case UCG_COM_MSG_SEND_STR: break; case UCG_COM_MSG_SEND_CD_DATA_SEQUENCE: break; } return 1; } void ucg_com_PowerDown(ucg_t *ucg) { if ( (ucg->com_status & UCG_COM_STATUS_MASK_POWER) != 0 ) ucg->com_cb(ucg, UCG_COM_MSG_POWER_DOWN, 0, NULL); ucg->com_status &= ~UCG_COM_STATUS_MASK_POWER; } /* clk_speed in nano-seconds, range: 0..4095 */ int16_t ucg_com_PowerUp(ucg_t *ucg, uint16_t serial_clk_speed, uint16_t parallel_clk_speed) { int16_t r; ucg_com_info_t com_info; com_info.serial_clk_speed = serial_clk_speed; com_info.parallel_clk_speed = parallel_clk_speed; ucg_com_PowerDown(ucg); ucg->com_initial_change_sent = 0; r = ucg->com_cb(ucg, UCG_COM_MSG_POWER_UP, 0UL, (uint8_t *)&com_info); if ( r != 0 ) { ucg->com_status |= UCG_COM_STATUS_MASK_POWER; } return r; } void ucg_com_SetLineStatus(ucg_t *ucg, uint8_t level, uint8_t mask, uint8_t msg) { if ( level == 0 ) { if ( (ucg->com_initial_change_sent & mask) == 0 || (ucg->com_status & mask) == mask ) { ucg->com_cb(ucg, msg, level, NULL); ucg->com_status &= ~mask; ucg->com_initial_change_sent |= mask; } } else { if ( (ucg->com_initial_change_sent & mask) == 0 || (ucg->com_status & mask) == 0 ) { ucg->com_cb(ucg, msg, level, NULL); ucg->com_status |= mask; ucg->com_initial_change_sent |= mask; } } } void ucg_com_SetResetLineStatus(ucg_t *ucg, uint8_t level) { ucg_com_SetLineStatus(ucg, level, UCG_COM_STATUS_MASK_RESET, UCG_COM_MSG_CHANGE_RESET_LINE); } void ucg_com_SetCSLineStatus(ucg_t *ucg, uint8_t level) { ucg_com_SetLineStatus(ucg, level, UCG_COM_STATUS_MASK_CS, UCG_COM_MSG_CHANGE_CS_LINE); } void ucg_com_SetCDLineStatus(ucg_t *ucg, uint8_t level) { ucg_com_SetLineStatus(ucg, level, UCG_COM_STATUS_MASK_CD, UCG_COM_MSG_CHANGE_CD_LINE); } /* delay in microseconds */ void ucg_com_DelayMicroseconds(ucg_t *ucg, uint16_t delay) { ucg->com_cb(ucg, UCG_COM_MSG_DELAY, delay, NULL); } /* delay in milliseconds */ void ucg_com_DelayMilliseconds(ucg_t *ucg, uint16_t delay) { while( delay > 0 ) { ucg_com_DelayMicroseconds(ucg, 1000); delay--; } } #ifndef ucg_com_SendByte void ucg_com_SendByte(ucg_t *ucg, uint8_t byte) { ucg->com_cb(ucg, UCG_COM_MSG_SEND_BYTE, byte, NULL); } #endif void ucg_com_SendRepeatByte(ucg_t *ucg, uint16_t cnt, uint8_t byte) { ucg->com_cb(ucg, UCG_COM_MSG_REPEAT_1_BYTE, cnt, &byte); } void ucg_com_SendRepeat2Bytes(ucg_t *ucg, uint16_t cnt, uint8_t *byte_ptr) { ucg->com_cb(ucg, UCG_COM_MSG_REPEAT_2_BYTES, cnt, byte_ptr); } #ifndef ucg_com_SendRepeat3Bytes void ucg_com_SendRepeat3Bytes(ucg_t *ucg, uint16_t cnt, uint8_t *byte_ptr) { ucg->com_cb(ucg, UCG_COM_MSG_REPEAT_3_BYTES, cnt, byte_ptr); } #endif void ucg_com_SendString(ucg_t *ucg, uint16_t cnt, const uint8_t *byte_ptr) { ucg->com_cb(ucg, UCG_COM_MSG_SEND_STR, cnt, (uint8_t *)byte_ptr); } void ucg_com_SendStringP(ucg_t *ucg, uint16_t cnt, const ucg_pgm_uint8_t *byte_ptr) { uint8_t b; while( cnt > 0 ) { b = ucg_pgm_read(byte_ptr); //b = *byte_ptr; ucg->com_cb(ucg, UCG_COM_MSG_SEND_BYTE, b, NULL); byte_ptr++; cnt--; } } void ucg_com_SendCmdDataSequence(ucg_t *ucg, uint16_t cnt, const uint8_t *byte_ptr, uint8_t cd_line_status_at_end) { ucg->com_cb(ucg, UCG_COM_MSG_SEND_CD_DATA_SEQUENCE, cnt, (uint8_t *)byte_ptr); ucg_com_SetCDLineStatus(ucg, cd_line_status_at_end); // ensure that the status is set correctly for the CD line */ } /* Command-Sequence Language CMD10 1x CMD Byte, 0x Argument Data Bytes CMD20 2x CMD Byte, 0x Argument Data Bytes CMD11 1x CMD Byte, 1x Argument Data Bytes CMD21 2x CMD Byte, 1x Argument Data Bytes CMD12 1x CMD Byte, 2x Argument Data Bytes CMD22 2x CMD Byte, 2x Argument Data Bytes CMD13 1x CMD Byte, 3x Argument Data Bytes CMD23 2x CMD Byte, 3x Argument Data Bytes CMD14 1x CMD Byte, 4x Argument Data Bytes CMD24 2x CMD Byte, 4x Argument Data Bytes DATA1 1x Data Bytes DATA2 2x Data Bytes DATA3 3x Data Bytes DATA4 4x Data Bytes DATA5 5x Data Bytes DATA6 6x Data Bytes RST_LOW Output 0 on reset line RST_HIGH Output 1 on reset line CS_LOW Output 0 on chip select line CS_HIGH Output 1 on chip select line DLY_MS Delay for specified amount of milliseconds (0..2000) DLY_US Delay for specified amount of microconds (0..2000) Configuration CFG_CD(c,a) Configure CMD/DATA line: "c" logic level CMD, "a" logic level CMD Args 0000xxxx End Marker 0001xxxx 1x CMD Byte, 0..15 Argument Data Bytes 0010xxxx 2x CMD Byte, 0..15 Argument Data Bytes 0011xxxx 3x CMD Byte, 0..15 Argument Data Bytes 0100xxxx 0101xxxx 0110xxxx Arg Bytes 0..15 0111xxxx Data Bytes 0...15 1000xxxx xxxxxxxx DLY MS 1001xxxx xxxxxxxx DLY US 1010sssss aaaaaaaa oooooooo (var0>>s)&a|o, send as argument 1011sssss aaaaaaaa oooooooo (var1>>s)&a|o, send as argument 1100xxxx 1101xxxx 1110xxxx 11110000 RST_LOW 11110001 RST_HIGH 1111001x 11110100 CS_LOW 11110101 CS_HIGH 1111011x 111110xx 111111ca CFG_CD(c,a) #define C10(c0) 0x010, (c0) #define C20(c0,c1) 0x020, (c0),(c1) #define C11(c0,a0) 0x011, (c0),(a0) #define C21(c0,c1,a0) 0x021, (c0),(c1),(a0) #define C12(c0,a0,a1) 0x012, (c0),(a0),(a1) #define C22(c0,c1,a0,a1) 0x022, (c0),(c1),(a0),(a1) #define C13(c0,a0,a1,a2) 0x013, (c0),(a0),(a1),(a2) #define C23(c0,c1,a0,a1,a2) 0x023, (c0),(c1),(a0),(a1),(a2) #define C14(c0,a0,a1,a2,a3) 0x013, (c0),(a0),(a1),(a2),(a3) #define C24(c0,c1,a0,a1,a2,a3) 0x023, (c0),(c1),(a0),(a1),(a2),(a3) #define UCG_DATA() 0x070 #define D1(d0) 0x071, (d0) #define D2(d0,d1) 0x072, (d0),(d1) #define D3(d0,d1,d3) 0x073, (d0),(d1),(d2) #define D4(d0,d1,d3,d4) 0x074, (d0),(d1),(d2),(d3) #define D5(d0,d1,d3,d4,d5) 0x075, (d0),(d1),(d2),(d3),(d5) #define D6(d0,d1,d3,d4,d5,d6) 0x076, (d0),(d1),(d2),(d3),(d5),(d6) #define DLY_MS(t) 0x080 | (((t)>>8)&15), (t)&255 #define DLY_US(t) 0x090 | (((t)>>8)&15), (t)&255 s: Shift right a: And mask o: Or mask #define UCG_VARX(s,a,o) 0x0a0 | ((s)&15), (a), (o) #define UCG_VARY(s,a,o) 0x0b0 | ((s)&15), (a), (o) #define RST(level) 0x0f0 | ((level)&1) #define CS(level) 0x0f4 | ((level)&1) #define CFG_CD(c,a) 0x0fc | (((c)&1)<<1) | ((a)&1) #define END() 0x00 */ static void ucg_com_SendCmdArg(ucg_t *ucg, const ucg_pgm_uint8_t *data, uint8_t cmd_cnt, uint8_t arg_cnt) { ucg_com_SetCDLineStatus(ucg, (ucg->com_cfg_cd>>1)&1 ); ucg_com_SendStringP(ucg, cmd_cnt, data); if ( arg_cnt > 0 ) { data += cmd_cnt; ucg_com_SetCDLineStatus(ucg, (ucg->com_cfg_cd)&1 ); ucg_com_SendStringP(ucg, arg_cnt, data); } } //void ucg_com_SendCmdSeq(ucg_t *ucg, const ucg_pgm_uint8_t *data) void ucg_com_SendCmdSeq(ucg_t *ucg, const ucg_pgm_uint8_t *data) { uint8_t b; uint8_t bb; uint8_t hi; uint8_t lo; for(;;) { b = ucg_pgm_read(data); //b = *data; hi = (b) >> 4; lo = (b) & 0x0f; switch( hi ) { case 0: return; /* end marker */ case 1: case 2: case 3: ucg_com_SendCmdArg(ucg, data+1, hi, lo); data+=1+hi+lo; break; case 6: ucg_com_SetCDLineStatus(ucg, (ucg->com_cfg_cd)&1 ); ucg_com_SendStringP(ucg, lo, data+1); data+=1+lo; break; case 7: /* note: 0x070 is used to set data line status */ ucg_com_SetCDLineStatus(ucg, ((ucg->com_cfg_cd>>1)&1)^1 ); if ( lo > 0 ) ucg_com_SendStringP(ucg, lo, data+1); data+=1+lo; break; case 8: data++; b = ucg_pgm_read(data); //b = *data; ucg_com_DelayMilliseconds(ucg, (((uint16_t)lo)<<8) + b ); data++; break; case 9: data++; b = ucg_pgm_read(data); //b = *data; ucg_com_DelayMicroseconds(ucg, (((uint16_t)lo)<<8) + b ); data++; break; case 10: data++; b = ucg_pgm_read(data); data++; bb = ucg_pgm_read(data); data++; //b = data[0]; //bb = data[1]; ucg_com_SetCDLineStatus(ucg, (ucg->com_cfg_cd)&1 ); ucg_com_SendByte(ucg, (((uint8_t)(((ucg->arg.pixel.pos.x)>>lo)))&b)|bb ); //data+=2; break; case 11: data++; b = ucg_pgm_read(data); data++; bb = ucg_pgm_read(data); data++; //b = data[0]; //bb = data[1]; ucg_com_SetCDLineStatus(ucg, (ucg->com_cfg_cd)&1 ); ucg_com_SendByte(ucg, (((uint8_t)(((ucg->arg.pixel.pos.y)>>lo)))&b)|bb ); //data+=2; break; case 15: hi = lo >> 2; lo &= 3; switch(hi) { case 0: ucg_com_SetResetLineStatus(ucg, lo&1); break; case 1: ucg_com_SetCSLineStatus(ucg, lo&1); break; case 3: ucg->com_cfg_cd = lo; break; } data++; break; default: return; } } }