add glyph blit operatin to gcld
[clinton/Smoothieware.git] / src / modules / utils / panel / panels / ReprapDiscountGLCD.cpp
1 /*
2 This file is part of Smoothie (http://smoothieware.org/). The motion control part is heavily based on Grbl (https://github.com/simen/grbl).
3 Smoothie is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
4 Smoothie is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
5 You should have received a copy of the GNU General Public License along with Smoothie. If not, see <http://www.gnu.org/licenses/>.
6 */
7 #include "ReprapDiscountGLCD.h"
8
9 ReprapDiscountGLCD::ReprapDiscountGLCD() {
10 // configure the pins to use
11 this->encoder_a_pin.from_string(THEKERNEL->config->value( panel_checksum, encoder_a_pin_checksum)->by_default("nc")->as_string())->as_input();
12 this->encoder_b_pin.from_string(THEKERNEL->config->value( panel_checksum, encoder_b_pin_checksum)->by_default("nc")->as_string())->as_input();
13 this->click_pin.from_string(THEKERNEL->config->value( panel_checksum, click_button_pin_checksum )->by_default("nc")->as_string())->as_input();
14 this->pause_pin.from_string(THEKERNEL->config->value( panel_checksum, pause_button_pin_checksum)->by_default("nc")->as_string())->as_input();
15 this->buzz_pin.from_string(THEKERNEL->config->value( panel_checksum, buzz_pin_checksum)->by_default("nc")->as_string())->as_output();
16 this->spi_cs_pin.from_string(THEKERNEL->config->value( panel_checksum, spi_cs_pin_checksum)->by_default("nc")->as_string())->as_output();
17
18 // select which SPI channel to use
19 int spi_channel = THEKERNEL->config->value(panel_checksum, spi_channel_checksum)->by_default(0)->as_number();
20 PinName mosi;
21 PinName sclk;
22 if(spi_channel == 0){
23 mosi= P0_18; sclk= P0_15;
24 }else if(spi_channel == 1){
25 mosi= P0_9; sclk= P0_7;
26 }else{
27 mosi= P0_18; sclk= P0_15;
28 }
29
30 this->glcd= new RrdGlcd(mosi, sclk, this->spi_cs_pin);
31
32 int spi_frequency = THEKERNEL->config->value(panel_checksum, spi_frequency_checksum)->by_default(1000000)->as_number();
33 this->glcd->setFrequency(spi_frequency);
34 }
35
36 ReprapDiscountGLCD::~ReprapDiscountGLCD() {
37 delete this->glcd;
38 }
39
40 uint8_t ReprapDiscountGLCD::readButtons() {
41 uint8_t state= 0;
42 state |= (this->click_pin.get() ? BUTTON_SELECT : 0);
43 // check the pause button
44 if(this->pause_pin.connected() && this->pause_pin.get()) state |= BUTTON_PAUSE;
45 return state;
46 }
47
48 int ReprapDiscountGLCD::readEncoderDelta() {
49 static int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};
50 static uint8_t old_AB = 0;
51 old_AB <<= 2; //remember previous state
52 old_AB |= ( this->encoder_a_pin.get() + ( this->encoder_b_pin.get() * 2 ) ); //add current state
53 return enc_states[(old_AB&0x0f)];
54 }
55
56 // cycle the buzzer pin at a certain frequency (hz) for a certain duration (ms)
57 void ReprapDiscountGLCD::buzz(long duration, uint16_t freq) {
58 if(!this->buzz_pin.connected()) return;
59
60 duration *=1000; //convert from ms to us
61 long period = 1000000 / freq; // period in us
62 long elapsed_time = 0;
63 while (elapsed_time < duration) {
64 this->buzz_pin.set(1);
65 wait_us(period / 2);
66 this->buzz_pin.set(0);
67 wait_us(period / 2);
68 elapsed_time += (period);
69 }
70 }
71
72 void ReprapDiscountGLCD::write(const char* line, int len) {
73 for (int i = 0; i < len; ++i) {
74 this->glcd->displayString(this->row, this->col, line, len);
75 }
76 this->col+=len;
77 }
78
79 void ReprapDiscountGLCD::home(){
80 this->col= 0;
81 this->row= 0;
82 }
83
84 void ReprapDiscountGLCD::clear(){
85 this->glcd->clearScreen();
86 this->col= 0;
87 this->row= 0;
88 }
89
90 void ReprapDiscountGLCD::display() {
91 // it is always on
92 }
93
94 void ReprapDiscountGLCD::setCursor(uint8_t col, uint8_t row){
95 this->col= col;
96 this->row= row;
97 }
98
99 void ReprapDiscountGLCD::init(){
100 this->glcd->initDisplay();
101 }
102
103 // displays a selectable rectangle from the glyph
104 void ReprapDiscountGLCD::bltGlyph(int x, int y, int w, int h, const uint8_t *glyph, int span, int x_offset, int y_offset) {
105 if(x_offset == 0 && y_offset == 0 && span == 0) {
106 // blt the whole thing
107 this->glcd->renderGlyph(x, y, glyph, w, h);
108
109 }else{
110 // copy portion of glyph into g where x_offset is left byte aligned
111 // Note currently thw x_offset must be byte aligned
112 int n= w/8; // bytes per line to copy
113 if(w%8 != 0) n++; // round up to next byte
114 uint8_t g[n*h];
115
116 for (int i = 0; i < h; ++i) {
117 memcpy(&g[i*n], &glyph[(i+y_offset)*span+x_offset/8], n);
118 }
119 this->glcd->renderGlyph(x, y, g, w, h);
120 }
121 }
122
123 void ReprapDiscountGLCD::on_refresh(bool now){
124 static int refresh_counts = 0;
125 refresh_counts++;
126 // 5Hz refresh rate
127 if(now || refresh_counts % 4 == 0 ) this->glcd->refresh();
128 }