A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2* __________ __ ___.
3* Open \______ \ ____ ____ | | _\_ |__ _______ ___
4* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7* \/ \/ \/ \/ \/
8* $Id$
9*
10* New greyscale framework
11* Core & miscellaneous functions
12*
13* This is a generic framework to display 129 shades of grey on low-depth
14* bitmap LCDs (Archos b&w, Iriver & Ipod 4-grey) within plugins.
15*
16* Copyright (C) 2008 Jens Arnold
17*
18* This program is free software; you can redistribute it and/or
19* modify it under the terms of the GNU General Public License
20* as published by the Free Software Foundation; either version 2
21* of the License, or (at your option) any later version.
22*
23* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
24* KIND, either express or implied.
25*
26****************************************************************************/
27
28#include "plugin.h"
29#include "grey.h"
30#include "fixedpoint.h"
31
32#if defined(HAVE_ADJUSTABLE_CPU_FREQ) && \
33 (defined(CPU_PP) || (CONFIG_LCD == LCD_TL0350A))
34#define NEED_BOOST
35#endif
36
37#ifndef SIMULATOR
38
39#if defined IAUDIO_M3 /* verified */
40/* Average measurements of 2 iAudio remotes connected to an M3. */
41static const unsigned char lcdlinear[256] = {
42 5, 9, 13, 17, 21, 26, 30, 34, 38, 42, 46, 50, 54, 58, 62, 66,
43 70, 73, 76, 78, 80, 82, 84, 86, 88, 90, 91, 92, 94, 95, 96, 97,
44 98, 99, 99, 100, 101, 102, 102, 103, 104, 104, 105, 105, 106, 107, 107, 108,
45109, 109, 110, 110, 111, 111, 112, 112, 113, 113, 114, 114, 115, 115, 116, 116,
46117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 121, 122, 122, 123, 123, 123,
47124, 124, 124, 125, 125, 126, 126, 126, 127, 127, 127, 128, 128, 129, 129, 129,
48130, 130, 131, 131, 132, 132, 133, 133, 134, 134, 134, 135, 135, 136, 136, 136,
49137, 137, 137, 138, 138, 139, 139, 139, 140, 140, 141, 141, 142, 142, 143, 143,
50144, 144, 145, 145, 146, 147, 147, 148, 149, 149, 150, 150, 151, 151, 152, 152,
51153, 153, 154, 154, 155, 155, 156, 156, 157, 157, 158, 158, 159, 160, 160, 161,
52162, 162, 163, 164, 164, 165, 166, 167, 168, 168, 169, 169, 170, 171, 171, 172,
53173, 173, 174, 175, 176, 176, 177, 178, 179, 179, 180, 181, 182, 182, 183, 184,
54185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 198, 199, 200, 201,
55202, 203, 204, 205, 207, 208, 209, 210, 211, 212, 213, 214, 216, 217, 218, 219,
56220, 221, 222, 223, 225, 226, 227, 228, 229, 230, 231, 232, 234, 235, 236, 237,
57238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 249, 250, 251, 252
58};
59/* The actual LCD scanrate is 3x as high, but 150 Hz or 75 Hz cause a too high
60 * CPU load (> 50 %). Even at 50Hz, greyscale display is rather smooth. Average
61 * from 2 iAudio remotes. */
62#define LCD_SCANRATE 50 /* Hz */
63
64#elif defined IAUDIO_M5 /* verified */
65/* Measurement of one iAudio M5L */
66static const unsigned char lcdlinear[256] = {
67 4, 6, 8, 10, 11, 13, 15, 17, 19, 21, 22, 24, 25, 27, 28, 30,
68 32, 33, 35, 36, 37, 39, 40, 42, 43, 44, 45, 46, 48, 49, 50, 51,
69 52, 52, 53, 54, 55, 55, 56, 57, 58, 58, 59, 60, 61, 61, 62, 63,
70 64, 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 70, 70, 71, 72, 72,
71 73, 73, 74, 75, 75, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81,
72 82, 82, 83, 84, 84, 85, 86, 86, 87, 87, 88, 89, 89, 90, 91, 91,
73 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 98, 98, 99, 100, 100,
74101, 101, 102, 102, 103, 103, 104, 104, 105, 105, 106, 106, 107, 107, 108, 108,
75109, 109, 110, 110, 111, 111, 112, 112, 113, 113, 114, 114, 115, 115, 116, 116,
76117, 117, 118, 119, 119, 120, 121, 121, 122, 122, 123, 124, 124, 125, 126, 126,
77127, 127, 128, 129, 130, 130, 131, 132, 133, 133, 134, 135, 135, 136, 137, 137,
78138, 139, 140, 141, 142, 142, 143, 144, 145, 146, 147, 148, 149, 149, 150, 151,
79152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 163, 164, 165, 167, 168, 169,
80170, 172, 173, 175, 177, 179, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198,
81200, 202, 204, 205, 207, 209, 210, 212, 214, 216, 218, 219, 221, 223, 224, 226,
82228, 230, 231, 233, 235, 236, 237, 239, 241, 243, 244, 246, 248, 249, 250, 252
83};
84#define LCD_SCANRATE 73 /* Hz */
85
86#elif defined IPOD_1G2G /* verified */
87/* Average measurements of an iPod 1st Gen (0x00010001) and an iPod 2nd Gen
88 * (0x00020000), measured with both backlight off & backlight on (flipped
89 * curves) and medium load (white background when measuring with backlight on),
90 * as the curve is load dependent (the controller's step-up converter doesn't
91 * provide enough juice). Table is for backlight_off state. */
92static const unsigned char lcdlinear[256] = {
93 4, 6, 8, 9, 11, 13, 14, 16, 17, 18, 20, 21, 23, 24, 26, 27,
94 29, 30, 31, 32, 34, 35, 36, 37, 38, 39, 40, 41, 41, 42, 43, 44,
95 45, 45, 46, 47, 47, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53,
96 54, 54, 54, 55, 55, 56, 56, 56, 57, 57, 57, 58, 58, 59, 59, 59,
97 60, 60, 60, 61, 61, 62, 62, 62, 63, 63, 63, 64, 64, 65, 65, 65,
98 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71, 72, 72, 73, 73,
99 74, 74, 74, 75, 75, 76, 76, 76, 77, 77, 78, 78, 79, 79, 80, 80,
100 81, 81, 82, 82, 83, 83, 84, 84, 85, 85, 86, 86, 87, 87, 88, 88,
101 89, 89, 90, 91, 92, 92, 93, 94, 95, 95, 96, 97, 97, 98, 99, 99,
102100, 100, 101, 102, 102, 103, 104, 104, 105, 105, 106, 107, 107, 108, 109, 109,
103110, 110, 111, 112, 113, 113, 114, 115, 116, 116, 117, 118, 119, 119, 120, 121,
104122, 122, 123, 124, 125, 125, 126, 127, 128, 129, 130, 131, 131, 132, 133, 134,
105135, 137, 138, 139, 141, 142, 144, 145, 146, 147, 149, 150, 151, 152, 154, 155,
106156, 158, 159, 161, 162, 164, 165, 167, 169, 171, 172, 174, 175, 177, 178, 180,
107182, 184, 186, 188, 189, 191, 193, 195, 197, 199, 201, 203, 206, 208, 210, 212,
108214, 217, 219, 221, 224, 226, 229, 231, 233, 236, 238, 240, 243, 245, 247, 250
109};
110/* Average from an iPod 1st Gen and an iPod 2nd Gen */
111#define LCD_SCANRATE 96 /* Hz */
112
113#elif defined IPOD_MINI2G /* verified */ \
114 || defined IPOD_MINI /* should be identical */ \
115 || defined IPOD_3G /* TODO: verify */ \
116 || defined IPOD_4G /* TODO: verify */
117/* Measurement of one iPod Mini G2 */
118static const unsigned char lcdlinear[256] = {
119 2, 5, 7, 10, 12, 15, 17, 20, 22, 24, 26, 28, 30, 32, 34, 36,
120 38, 40, 41, 42, 44, 45, 46, 47, 48, 49, 50, 50, 51, 52, 52, 53,
121 54, 54, 55, 55, 56, 56, 57, 57, 58, 58, 58, 59, 59, 60, 60, 60,
122 61, 61, 61, 62, 62, 63, 63, 63, 64, 64, 64, 64, 65, 65, 65, 65,
123 66, 66, 66, 66, 67, 67, 67, 67, 68, 68, 68, 68, 69, 69, 69, 69,
124 70, 70, 70, 70, 71, 71, 71, 71, 72, 72, 72, 73, 73, 74, 74, 74,
125 75, 75, 75, 75, 76, 76, 76, 76, 77, 77, 77, 78, 78, 79, 79, 79,
126 80, 80, 80, 81, 81, 82, 82, 82, 83, 83, 83, 84, 84, 85, 85, 85,
127 86, 86, 86, 87, 87, 88, 88, 88, 89, 89, 90, 90, 91, 91, 92, 92,
128 93, 93, 94, 94, 95, 95, 96, 96, 97, 97, 98, 99, 99, 100, 101, 101,
129102, 102, 103, 104, 104, 105, 106, 106, 107, 108, 109, 110, 110, 111, 112, 113,
130114, 115, 115, 116, 117, 118, 118, 119, 120, 121, 121, 122, 123, 124, 124, 125,
131126, 127, 128, 129, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140,
132141, 142, 143, 144, 146, 147, 148, 149, 150, 151, 153, 154, 155, 156, 158, 159,
133160, 162, 163, 165, 166, 168, 169, 171, 172, 175, 177, 180, 182, 185, 187, 190,
134192, 196, 199, 203, 206, 210, 213, 217, 220, 223, 227, 230, 234, 238, 242, 246
135};
136/* Average of an iPod Mini G2 and 2 3rd Gen iPods. */
137#define LCD_SCANRATE 87 /* Hz */
138
139#elif defined IRIVER_H100_SERIES /* verified */
140/* Measurement of one Iriver H140 */
141static const unsigned char lcdlinear[256] = {
142 5, 8, 12, 15, 18, 22, 25, 28, 31, 34, 36, 39, 42, 44, 47, 50,
143 53, 55, 57, 59, 62, 64, 66, 68, 70, 71, 72, 73, 75, 76, 77, 78,
144 79, 80, 80, 81, 82, 83, 83, 84, 85, 85, 86, 86, 87, 87, 88, 88,
145 89, 89, 90, 90, 91, 91, 92, 92, 93, 93, 93, 94, 94, 95, 95, 95,
146 96, 96, 96, 97, 97, 98, 98, 98, 99, 99, 99, 100, 100, 101, 101, 101,
147102, 102, 102, 103, 103, 104, 104, 104, 105, 105, 106, 106, 107, 107, 108, 108,
148109, 109, 109, 110, 110, 111, 111, 111, 112, 112, 113, 113, 114, 114, 115, 115,
149116, 116, 117, 117, 118, 118, 119, 119, 120, 120, 121, 121, 122, 122, 123, 123,
150124, 124, 125, 125, 126, 127, 127, 128, 129, 129, 130, 130, 131, 131, 132, 132,
151133, 133, 134, 135, 135, 136, 137, 137, 138, 138, 139, 139, 140, 140, 141, 141,
152142, 142, 143, 143, 144, 145, 145, 146, 147, 147, 148, 148, 149, 150, 150, 151,
153152, 152, 153, 153, 154, 155, 155, 156, 157, 157, 158, 159, 160, 160, 161, 162,
154163, 164, 165, 166, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177,
155178, 179, 181, 182, 183, 184, 186, 187, 188, 189, 191, 192, 193, 194, 196, 197,
156198, 200, 202, 203, 205, 207, 208, 210, 212, 214, 215, 217, 218, 220, 221, 223,
157224, 226, 228, 229, 231, 233, 235, 236, 238, 240, 241, 242, 244, 245, 246, 248
158};
159#define LCD_SCANRATE 70 /* Hz */
160
161#elif defined MROBE_100 /* verified */
162/* Average measurements of 2 m:robe 100 s */
163static const unsigned char lcdlinear[256] = {
164 10, 14, 18, 22, 26, 30, 34, 38, 42, 46, 49, 53, 56, 60, 63, 67,
165 70, 73, 76, 79, 81, 84, 87, 90, 92, 95, 97, 100, 102, 105, 107, 110,
166112, 114, 116, 118, 119, 121, 123, 125, 126, 128, 130, 131, 133, 135, 136, 138,
167139, 141, 142, 143, 144, 146, 147, 148, 149, 150, 151, 152, 154, 155, 156, 157,
168158, 159, 160, 161, 161, 162, 163, 164, 165, 166, 167, 168, 168, 169, 170, 171,
169172, 172, 173, 173, 174, 174, 175, 175, 176, 176, 177, 178, 178, 179, 180, 180,
170181, 181, 182, 182, 183, 183, 184, 184, 185, 185, 186, 186, 187, 187, 188, 188,
171189, 189, 190, 190, 191, 191, 192, 192, 193, 193, 193, 194, 194, 195, 195, 195,
172196, 196, 197, 197, 198, 198, 199, 199, 200, 200, 200, 201, 201, 202, 202, 202,
173203, 203, 204, 204, 205, 205, 206, 206, 207, 207, 207, 208, 208, 209, 209, 209,
174210, 210, 210, 211, 211, 212, 212, 212, 213, 213, 213, 214, 214, 215, 215, 215,
175216, 216, 216, 217, 217, 218, 218, 218, 219, 219, 219, 220, 220, 221, 221, 221,
176222, 222, 222, 223, 223, 224, 224, 224, 225, 225, 225, 226, 226, 227, 227, 227,
177228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 232, 233, 233, 234, 234, 234,
178235, 235, 235, 236, 236, 237, 237, 237, 238, 238, 238, 239, 239, 240, 240, 240,
179241, 241, 242, 242, 243, 243, 244, 244, 247, 248, 248, 249, 250, 250, 251, 252
180};
181#define LCD_SCANRATE 51 /* Hz */
182
183#elif defined SANSA_CLIP /* TODO: calibrate */
184static const unsigned char lcdlinear[256] = {
185 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
186 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
187 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
188 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
189 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
190 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
191 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
192112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
193128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
194144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
195160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
196176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
197192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
198208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
199224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
200240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
201};
202#define LCD_SCANRATE 78 /* Hz */
203
204#elif defined SANSA_CLIPV2 /* TODO: calibrate */
205static const unsigned char lcdlinear[256] = {
206 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
207 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
208 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
209 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
210 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
211 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
212 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
213112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
214128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
215144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
216160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
217176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
218192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
219208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
220224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
221240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
222};
223#define LCD_SCANRATE 74 /* Hz */
224
225#elif defined SANSA_CLIPPLUS /* TODO: calibrate */
226static const unsigned char lcdlinear[256] = {
227 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
228 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
229 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
230 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
231 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
232 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
233 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
234112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
235128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
236144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
237160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
238176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
239192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
240208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
241224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
242240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
243};
244#define LCD_SCANRATE 80 /* Hz */
245
246#elif defined MPIO_HD200
247/* matrix generated in the following way
248 * 1) run 5 times test_grey
249 * 2) average results (joint points)
250 * 3) plot full matrix obtained by natural cubic b-spline interpolation
251 * 4) hand tweak joint points to smooth the curve
252 * 5) repeat steps 3 and 4 until interpolated curve is smooth
253 */
254static const unsigned char lcdlinear[256] = {
255 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7,
256 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15,
257 16, 16, 16, 17, 17, 18, 18, 18, 19, 19, 20, 20, 20, 21, 21, 21,
258 22, 22, 22, 22, 23, 23, 23, 24, 24, 24, 24, 25, 25, 25, 26, 26,
259 27, 27, 27, 28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34,
260 35, 35, 36, 36, 37, 37, 38, 39, 39, 40, 41, 41, 42, 43, 43, 44,
261 45, 45, 46, 46, 47, 48, 49, 49, 50, 51, 51, 52, 53, 53, 54, 55,
262 56, 56, 57, 58, 58, 59, 60, 61, 61, 62, 63, 64, 64, 65, 66, 67,
263 68, 68, 69, 70, 71, 71, 72, 73, 74, 75, 75, 76, 77, 78, 79, 80,
264 81, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
265 96, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 108, 109, 110, 111,
266113, 114, 115, 117, 118, 120, 121, 123, 125, 126, 128, 130, 131, 133, 135, 137,
267139, 140, 142, 144, 146, 147, 149, 151, 152, 154, 156, 157, 159, 161, 162, 164,
268166, 167, 169, 170, 172, 173, 175, 176, 177, 179, 180, 182, 183, 184, 186, 187,
269189, 190, 191, 193, 194, 195, 197, 198, 199, 201, 202, 203, 205, 206, 207, 208,
270210, 211, 212, 213, 214, 215, 217, 218, 219, 220, 221, 222, 223, 224, 225, 227
271};
272#define LCD_SCANRATE 153 /* Hz */
273
274#elif defined MPIO_HD300 /* verified */
275/* Measurement of one iAudio M5L */
276static const unsigned char lcdlinear[256] = {
277 4, 6, 8, 10, 11, 13, 15, 17, 19, 21, 22, 24, 25, 27, 28, 30,
278 32, 33, 35, 36, 37, 39, 40, 42, 43, 44, 45, 46, 48, 49, 50, 51,
279 52, 52, 53, 54, 55, 55, 56, 57, 58, 58, 59, 60, 61, 61, 62, 63,
280 64, 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 70, 70, 71, 72, 72,
281 73, 73, 74, 75, 75, 76, 77, 77, 78, 78, 79, 79, 80, 80, 81, 81,
282 82, 82, 83, 84, 84, 85, 86, 86, 87, 87, 88, 89, 89, 90, 91, 91,
283 92, 92, 93, 93, 94, 94, 95, 95, 96, 96, 97, 98, 98, 99, 100, 100,
284101, 101, 102, 102, 103, 103, 104, 104, 105, 105, 106, 106, 107, 107, 108, 108,
285109, 109, 110, 110, 111, 111, 112, 112, 113, 113, 114, 114, 115, 115, 116, 116,
286117, 117, 118, 119, 119, 120, 121, 121, 122, 122, 123, 124, 124, 125, 126, 126,
287127, 127, 128, 129, 130, 130, 131, 132, 133, 133, 134, 135, 135, 136, 137, 137,
288138, 139, 140, 141, 142, 142, 143, 144, 145, 146, 147, 148, 149, 149, 150, 151,
289152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 163, 164, 165, 167, 168, 169,
290170, 172, 173, 175, 177, 179, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198,
291200, 202, 204, 205, 207, 209, 210, 212, 214, 216, 218, 219, 221, 223, 224, 226,
292228, 230, 231, 233, 235, 236, 237, 239, 241, 243, 244, 246, 248, 249, 250, 252
293};
294#define LCD_SCANRATE 73 /* Hz */
295
296#else /* not yet calibrated targets - generic linear mapping */
297static const unsigned char lcdlinear[256] = {
298 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
299 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
300 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
301 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
302 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
303 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
304 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
305112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
306128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
307144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
308160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
309176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
310192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
311208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
312224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
313240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
314};
315/* generic default */
316#define LCD_SCANRATE 70 /* Hz */
317
318#endif
319#else /* SIMULATOR */
320/* undo a (generic) PC display gamma of 2.0 to simulate target behaviour */
321static const unsigned char lcdlinear[256] = {
322 0, 16, 23, 28, 32, 36, 39, 42, 45, 48, 50, 53, 55, 58, 60, 62,
323 64, 66, 68, 70, 71, 73, 75, 77, 78, 80, 81, 83, 84, 86, 87, 89,
324 90, 92, 93, 94, 96, 97, 98, 100, 101, 102, 103, 105, 106, 107, 108, 109,
325111, 112, 113, 114, 115, 116, 117, 118, 119, 121, 122, 123, 124, 125, 126, 127,
326128, 129, 130, 131, 132, 133, 134, 135, 135, 136, 137, 138, 139, 140, 141, 142,
327143, 144, 145, 145, 146, 147, 148, 149, 150, 151, 151, 152, 153, 154, 155, 156,
328156, 157, 158, 159, 160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168,
329169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 179, 179, 180,
330181, 181, 182, 183, 183, 184, 185, 186, 186, 187, 188, 188, 189, 190, 190, 191,
331192, 192, 193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, 201, 201,
332202, 203, 203, 204, 204, 205, 206, 206, 207, 208, 208, 209, 209, 210, 211, 211,
333212, 212, 213, 214, 214, 215, 215, 216, 217, 217, 218, 218, 219, 220, 220, 221,
334221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 228, 228, 229, 229, 230,
335230, 231, 231, 232, 233, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238,
336239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247,
337247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254, 255
338};
339#endif /* SIMULATOR */
340
341/* Prototypes */
342static inline void _deferred_update(void) __attribute__ ((always_inline));
343static void grey_screendump_hook(int fd);
344static void fill_gvalues(void);
345#ifdef SIMULATOR
346static unsigned long _grey_get_pixel(int x, int y);
347#else
348static void _timer_isr(void);
349#endif
350
351
352#if defined(HAVE_BACKLIGHT_INVERSION) && !defined(SIMULATOR)
353static void invert_gvalues(void)
354{
355 unsigned char *val, *end;
356 unsigned char rev_tab[256];
357 unsigned i;
358 unsigned last_i = 0;
359 unsigned x = 0;
360 unsigned last_x;
361
362 /* Step 1: Calculate a transposed table for undoing the old mapping */
363 for (i = 0; i < 256; i++)
364 {
365 last_x = x;
366 x = _grey_info.gvalue[i];
367 if (x > last_x)
368 {
369 rev_tab[last_x++] = (last_i + i) / 2;
370 while (x > last_x)
371 rev_tab[last_x++] = i;
372 last_i = i;
373 }
374 }
375 rev_tab[last_x++] = (last_i + 255) / 2;
376 while (256 > last_x)
377 rev_tab[last_x++] = 255;
378
379 /* Step 2: Calculate new mapping */
380 fill_gvalues();
381
382 /* Step 3: Transpose all pixel values */
383 val = _grey_info.values;
384 end = val + _GREY_MULUQ(_grey_info.width, _grey_info.height);
385
386 do
387 *val = _grey_info.gvalue[rev_tab[*val]];
388 while (++val < end);
389}
390#endif
391
392/* Update LCD areas not covered by the greyscale overlay */
393static inline void _deferred_update(void)
394{
395 int x1 = MAX(_grey_info.x, 0);
396 int x2 = MIN(_grey_info.x + _grey_info.width, LCD_WIDTH);
397 int y1 = MAX(_grey_info.y, 0);
398 int y2 = MIN(_grey_info.y + _grey_info.height, LCD_HEIGHT);
399
400 if (y1 > 0) /* refresh part above overlay, full width */
401 rb->lcd_update_rect(0, 0, LCD_WIDTH, y1);
402
403 if (y2 < LCD_HEIGHT) /* refresh part below overlay, full width */
404 rb->lcd_update_rect(0, y2, LCD_WIDTH, LCD_HEIGHT - y2);
405
406 if (x1 > 0) /* refresh part to the left of overlay */
407 rb->lcd_update_rect(0, y1, x1, y2 - y1);
408
409 if (x2 < LCD_WIDTH) /* refresh part to the right of overlay */
410 rb->lcd_update_rect(x2, y1, LCD_WIDTH - x2, y2 - y1);
411}
412
413#ifdef SIMULATOR
414
415/* Callback function for grey_ub_gray_bitmap_part() to read a pixel from the
416 * greybuffer. Note that x and y are in LCD coordinates, not greybuffer
417 * coordinates! */
418static unsigned long _grey_get_pixel(int x, int y)
419{
420 long val;
421 int xg = x - _grey_info.x;
422 int yg = y - _grey_info.y;
423#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
424 int idx = _grey_info.width * yg + xg;
425#else /* vertical packing or vertical interleaved */
426 int idx = _grey_info.width * (yg & ~_GREY_BMASK)
427 + (xg << _GREY_BSHIFT) + (~yg & _GREY_BMASK);
428#endif
429
430 val = _grey_info.values[idx];
431#ifdef HAVE_LCD_SPLIT
432 val -= val >> 7;
433#endif
434 return val;
435}
436
437#else /* !SIMULATOR */
438
439/* Timer interrupt handler: display next frame */
440static void _timer_isr(void)
441{
442#if defined(HAVE_BACKLIGHT_INVERSION) && !defined(SIMULATOR)
443 unsigned long check = rb->is_backlight_on(true)
444 ? 0 : _GREY_BACKLIGHT_ON;
445
446 if ((_grey_info.flags & (_GREY_BACKLIGHT_ON|GREY_RAWMAPPED)) == check)
447 {
448 _grey_info.flags ^= _GREY_BACKLIGHT_ON;
449 invert_gvalues();
450 return; /* don't overload this timer slot */
451 }
452#endif
453#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
454 rb->lcd_blit_grey_phase(_grey_info.values, _grey_info.phases,
455 _grey_info.bx, _grey_info.y,
456 _grey_info.bwidth, _grey_info.height,
457 _grey_info.width);
458#else /* vertical packing or vertical interleaved */
459 rb->lcd_blit_grey_phase(_grey_info.values, _grey_info.phases,
460 _grey_info.x, _grey_info.by,
461 _grey_info.width, _grey_info.bheight,
462 _grey_info.width);
463#endif
464
465 if (_grey_info.flags & _GREY_DEFERRED_UPDATE) /* lcd_update() requested? */
466 {
467 _deferred_update();
468 _grey_info.flags &= ~_GREY_DEFERRED_UPDATE; /* clear request */
469 }
470}
471
472#endif /* !SIMULATOR */
473
474static void fill_gvalues(void)
475{
476 int i;
477 unsigned data;
478
479#if defined(HAVE_BACKLIGHT_INVERSION) && !defined(SIMULATOR)
480 unsigned imask = (_grey_info.flags & _GREY_BACKLIGHT_ON) ? 0xff : 0;
481#else
482 const unsigned imask = 0;
483#endif
484 for (i = 0; i < 256; i++)
485 {
486 data = fp16_exp((_GREY_GAMMA * fp16_log(i * 257 + 1)) >> 8) + 128;
487 data = (data - (data >> 8)) >> 8; /* approx. data /= 257 */
488 data = ((lcdlinear[data ^ imask] ^ imask) << 7) + 127;
489 _grey_info.gvalue[i] = (data + (data >> 8)) >> 8;
490 /* approx. data / 255 */
491 }
492}
493
494/* Initialise the framework and prepare the greyscale display buffer
495
496 arguments:
497 gbuf = pointer to the memory area to use (e.g. plugin buffer)
498 gbuf_size = max usable size of the buffer
499 features = flags for requesting features
500 GREY_BUFFERED: use chunky pixel buffering
501 This allows to use all drawing functions, but needs more
502 memory. Unbuffered operation provides only a subset of
503 drawing functions. (only grey_bitmap drawing and scrolling)
504 GREY_RAWMAPPED: no LCD linearisation and gamma correction
505 width = width in pixels (1..LCD_WIDTH)
506 height = height in pixels (1..LCD_HEIGHT)
507 Note that depending on the target LCD, either height or
508 width are rounded up to a multiple of 4 or 8.
509
510 result:
511 true on success, false on failure
512
513 If you need info about the memory taken by the greyscale buffer, supply a
514 long* as the last parameter. This long will then contain the number of bytes
515 used. The total memory needed can be calculated as follows:
516 total_mem =
517 width * height * 2 [grey display data]
518 + buffered ? (width * height) : 0 [chunky buffer]
519 + 0..3 [alignment]
520
521 The function is authentic regarding memory usage on the simulator, even
522 if it doesn't use all of the allocated memory. */
523bool grey_init(unsigned char *gbuf, long gbuf_size,
524 unsigned features, int width, int height, long *buf_taken)
525{
526 int bdim, i;
527 long plane_size, buftaken;
528 unsigned data;
529#ifndef SIMULATOR
530 unsigned *dst, *end;
531#endif
532
533 if ((unsigned) width > LCD_WIDTH
534 || (unsigned) height > LCD_HEIGHT)
535 return false;
536
537#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
538 bdim = (width + 7) >> 3;
539 width = bdim << 3;
540#else /* vertical packing or vertical interleaved */
541#if (LCD_DEPTH == 1) || (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)
542 bdim = (height + 7) >> 3;
543 height = bdim << 3;
544#elif LCD_DEPTH == 2
545 bdim = (height + 3) >> 2;
546 height = bdim << 2;
547#endif
548#endif
549
550 plane_size = _GREY_MULUQ(width, height);
551#if defined(CPU_COLDFIRE) /* Buffers should be line aligned */ \
552 || defined(CPU_PP) && (NUM_CORES > 1) /* Buffers must be cache line aligned */
553 plane_size += (-plane_size) & 0xf;
554 buftaken = (-(long)gbuf) & 0xf;
555#else /* Buffers must be 32 bit aligned. */
556 buftaken = (-(long)gbuf) & 3;
557#endif
558 gbuf += buftaken;
559
560 if (features & GREY_BUFFERED) /* chunky buffer */
561 {
562 _grey_info.buffer = gbuf;
563 gbuf += plane_size;
564 buftaken += plane_size;
565 }
566#if NUM_CORES > 1 /* Values and phases must be uncached when running on COP */
567 if (features & GREY_ON_COP)
568 gbuf = UNCACHED_ADDR(gbuf);
569#endif
570 _grey_info.values = gbuf;
571 gbuf += plane_size;
572 _grey_info.phases = gbuf;
573 buftaken += 2 * plane_size;
574
575 if (buftaken > gbuf_size)
576 return false;
577
578 /* Init to white */
579 rb->memset(_grey_info.values, 0x80, plane_size);
580
581#ifndef SIMULATOR
582 /* Init phases with random bits */
583 dst = (unsigned*)(_grey_info.phases);
584 end = (unsigned*)(_grey_info.phases + plane_size);
585
586 do
587 *dst++ = rb->rand();
588 while (dst < end);
589#endif
590
591 _grey_info.x = 0;
592 _grey_info.y = 0;
593 _grey_info.width = width;
594 _grey_info.height = height;
595#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
596 _grey_info.bx = 0;
597 _grey_info.bwidth = bdim;
598#else /* vertical packing or vertical interleaved */
599 _grey_info.by = 0;
600 _grey_info.bheight = bdim;
601#endif
602 _grey_info.flags = features & 0xff;
603
604 /* default viewport and settings */
605 grey_set_viewport(NULL);
606 grey_viewport_set_fullscreen(NULL, SCREEN_MAIN);
607 grey_set_framebuffer(NULL);
608
609 /* precalculate the value -> pattern index conversion table, taking
610 linearisation and gamma correction into account */
611 if (features & GREY_RAWMAPPED)
612 {
613 for (i = 0; i < 256; i++)
614 {
615 data = i << 7;
616 _grey_info.gvalue[i] = (data + (data >> 8)) >> 8;
617 }
618 }
619 else
620 {
621#if defined(HAVE_BACKLIGHT_INVERSION) && !defined(SIMULATOR)
622 if (rb->is_backlight_on(true))
623 _grey_info.flags |= _GREY_BACKLIGHT_ON;
624#endif
625 fill_gvalues();
626 }
627
628 if (buf_taken) /* caller requested info about space taken */
629 *buf_taken = buftaken;
630
631 return true;
632}
633
634/* Release the greyscale display buffer and the library
635 DO CALL either this function or at least grey_show_display(false)
636 before you exit, otherwise nasty things may happen. */
637void grey_release(void)
638{
639 grey_show(false);
640}
641
642/* Switch the greyscale overlay on or off
643 DO NOT call lcd_update() or any other api function that directly accesses
644 the lcd while the greyscale overlay is running! If you need to do
645 lcd_update() to update something outside the greyscale overlay area, use
646 grey_deferred_update() instead.
647
648 Other functions to avoid are:
649 lcd_blit_mono(), lcd_update_rect(), lcd_set_contrast(),
650 lcd_set_invert_display(), lcd_set_flip() */
651void grey_show(bool enable)
652{
653 if (enable && !(_grey_info.flags & _GREY_RUNNING))
654 {
655 _grey_info.flags |= _GREY_RUNNING;
656#ifdef SIMULATOR
657 rb->sim_lcd_ex_init(_grey_get_pixel);
658 rb->sim_lcd_ex_update_rect(_grey_info.x, _grey_info.y,
659 _grey_info.width, _grey_info.height);
660#else /* !SIMULATOR */
661#ifdef NEED_BOOST
662 rb->cpu_boost(true);
663#endif
664#if NUM_CORES > 1
665 rb->timer_register(1, NULL, TIMER_FREQ / LCD_SCANRATE,
666 _timer_isr,
667 (_grey_info.flags & GREY_ON_COP) ? COP : CPU);
668#else
669 rb->timer_register(1, NULL, TIMER_FREQ / LCD_SCANRATE, _timer_isr);
670#endif
671#endif /* !SIMULATOR */
672 rb->screen_dump_set_hook(grey_screendump_hook);
673 }
674 else if (!enable && (_grey_info.flags & _GREY_RUNNING))
675 {
676#ifdef SIMULATOR
677 rb->sim_lcd_ex_init(NULL);
678#else /* !SIMULATOR */
679 rb->timer_unregister();
680#if NUM_CORES > 1 /* Make sure the ISR has finished before calling lcd_update() */
681 rb->sleep(HZ/100);
682#endif
683#ifdef NEED_BOOST
684 rb->cpu_boost(false);
685#endif
686#endif /* !SIMULATOR */
687 _grey_info.flags &= ~_GREY_RUNNING;
688 rb->screen_dump_set_hook(NULL);
689 rb->lcd_update(); /* restore whatever there was before */
690 }
691}
692
693void grey_update_rect(int x, int y, int width, int height)
694{
695 grey_ub_gray_bitmap_part(_grey_info.buffer, x, y, _grey_info.width,
696 x, y, width, height);
697}
698
699/* Update the whole greyscale overlay */
700void grey_update(void)
701{
702 grey_ub_gray_bitmap_part(_grey_info.buffer, 0, 0, _grey_info.width,
703 0, 0, _grey_info.width, _grey_info.height);
704}
705
706/* Do an lcd_update() to show changes done by rb->lcd_xxx() functions
707 (in areas of the screen not covered by the greyscale overlay). */
708void grey_deferred_lcd_update(void)
709{
710 if (_grey_info.flags & _GREY_RUNNING)
711 {
712#ifdef SIMULATOR
713 _deferred_update();
714#else
715 _grey_info.flags |= _GREY_DEFERRED_UPDATE;
716#endif
717 }
718 else
719 rb->lcd_update();
720}
721
722/*** Screenshot ***/
723
724#ifdef HAVE_LCD_SPLIT
725#define NUM_SHADES 128
726#define BMP_NUMCOLORS 256
727#else
728#define NUM_SHADES 129
729#define BMP_NUMCOLORS 129
730#endif
731
732#define BMP_BPP 8
733#define BMP_LINESIZE ((LCD_WIDTH + 3) & ~3)
734#define BMP_HEADERSIZE (54 + 4 * BMP_NUMCOLORS)
735#define BMP_DATASIZE (BMP_LINESIZE * (LCD_HEIGHT+LCD_SPLIT_LINES))
736#define BMP_TOTALSIZE (BMP_HEADERSIZE + BMP_DATASIZE)
737
738static const unsigned char bmpheader[] =
739{
740 0x42, 0x4d, /* 'BM' */
741 LE32_CONST(BMP_TOTALSIZE), /* Total file size */
742 0x00, 0x00, 0x00, 0x00, /* Reserved */
743 LE32_CONST(BMP_HEADERSIZE), /* Offset to start of pixel data */
744
745 0x28, 0x00, 0x00, 0x00, /* Size of (2nd) header */
746 LE32_CONST(LCD_WIDTH), /* Width in pixels */
747 LE32_CONST(LCD_HEIGHT+LCD_SPLIT_LINES), /* Height in pixels */
748 0x01, 0x00, /* Number of planes (always 1) */
749 LE16_CONST(BMP_BPP), /* Bits per pixel 1/4/8/16/24 */
750 0x00, 0x00, 0x00, 0x00, /* Compression mode, 0 = none */
751 LE32_CONST(BMP_DATASIZE), /* Size of bitmap data */
752 0xc4, 0x0e, 0x00, 0x00, /* Horizontal resolution (pixels/meter) */
753 0xc4, 0x0e, 0x00, 0x00, /* Vertical resolution (pixels/meter) */
754 LE32_CONST(BMP_NUMCOLORS), /* Number of used colours */
755 LE32_CONST(BMP_NUMCOLORS), /* Number of important colours */
756};
757
758#if LCD_DEPTH == 2
759/* Only defined for positive, non-split LCD for now */
760static const unsigned char colorindex[4] = {128, 85, 43, 0};
761#endif
762
763/* Hook function for core screen_dump() to save the current display
764 content (b&w and greyscale overlay) to an 8-bit BMP file. */
765static void grey_screendump_hook(int fd)
766{
767 fb_data *lcd_fb;
768 struct viewport *vp_main = rb->lcd_set_viewport(NULL);
769 rb->viewport_set_fullscreen(vp_main, SCREEN_MAIN);
770 lcd_fb = vp_main->buffer->fb_ptr;
771
772 int i;
773 int y, gx, gy;
774#if LCD_PIXELFORMAT == VERTICAL_PACKING
775#if LCD_DEPTH == 1
776 unsigned val;
777 unsigned mask;
778#elif LCD_DEPTH == 2
779 int shift;
780#endif
781#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
782 unsigned data;
783 int shift;
784#endif /* LCD_PIXELFORMAT */
785 fb_data *src;
786 unsigned char *gsrc;
787 unsigned char *dst, *dst_end;
788 unsigned char linebuf[MAX(4*NUM_SHADES,BMP_LINESIZE)];
789
790 rb->write(fd, bmpheader, sizeof(bmpheader)); /* write header */
791
792 /* build clut */
793 rb->memset(linebuf, 0, 4*NUM_SHADES);
794 dst = linebuf;
795
796 for (i = 0; i < NUM_SHADES; i++)
797 {
798 *dst++ = (_GREY_MULUQ(BLUE_CMP(LCD_BL_BRIGHTCOLOR)
799 -BLUE_CMP(LCD_BL_DARKCOLOR), i) >> 7)
800 + BLUE_CMP(LCD_BL_DARKCOLOR);
801 *dst++ = (_GREY_MULUQ(GREEN_CMP(LCD_BL_BRIGHTCOLOR)
802 -GREEN_CMP(LCD_BL_DARKCOLOR), i) >> 7)
803 + GREEN_CMP(LCD_BL_DARKCOLOR);
804 *dst++ = (_GREY_MULUQ(RED_CMP(LCD_BL_BRIGHTCOLOR)
805 -RED_CMP(LCD_BL_DARKCOLOR), i) >> 7)
806 + RED_CMP(LCD_BL_DARKCOLOR);
807 dst++;
808 }
809 rb->write(fd, linebuf, 4*NUM_SHADES);
810
811#ifdef HAVE_LCD_SPLIT
812 dst = linebuf;
813
814 for (i = 0; i <= NUM_SHADES; i++)
815 {
816 *dst++ = (_GREY_MULUQ(BLUE_CMP(LCD_BL_BRIGHTCOLOR_2)
817 -BLUE_CMP(LCD_BL_DARKCOLOR_2), i) >> 7)
818 + BLUE_CMP(LCD_BL_DARKCOLOR_2);
819 *dst++ = (_GREY_MULUQ(GREEN_CMP(LCD_BL_BRIGHTCOLOR_2)
820 -GREEN_CMP(LCD_BL_DARKCOLOR_2), i) >> 7)
821 + GREEN_CMP(LCD_BL_DARKCOLOR_2);
822 *dst++ = (_GREY_MULUQ(RED_CMP(LCD_BL_BRIGHTCOLOR_2)
823 -RED_CMP(LCD_BL_DARKCOLOR_2), i) >> 7)
824 + RED_CMP(LCD_BL_DARKCOLOR_2);
825 dst++;
826 }
827 rb->write(fd, linebuf, 4*NUM_SHADES);
828#endif
829
830 /* BMP image goes bottom -> top */
831 for (y = LCD_HEIGHT - 1; y >= 0; y--)
832 {
833 rb->memset(linebuf, 0, BMP_LINESIZE);
834
835#if defined(HAVE_LCD_SPLIT) && (LCD_SPLIT_LINES == 2)
836 if (y == LCD_SPLIT_POS - 1)
837 {
838 rb->write(fd, linebuf, BMP_LINESIZE);
839 rb->write(fd, linebuf, BMP_LINESIZE);
840 }
841#endif
842
843 dst = linebuf;
844 dst_end = dst + LCD_WIDTH;
845 gy = y - _grey_info.y;
846 gx = -_grey_info.x;
847
848#if LCD_PIXELFORMAT == HORIZONTAL_PACKING
849 gsrc = _grey_info.values + _GREY_MULUQ(_grey_info.width, gy);
850
851#if LCD_DEPTH == 2
852 src = lcd_fb + _GREY_MULUQ(LCD_FBWIDTH, y);
853
854 do
855 {
856 if (((unsigned)gy < (unsigned)_grey_info.height)
857 && ((unsigned)gx < (unsigned)_grey_info.width))
858 {
859 *dst++ = *gsrc++;
860 *dst++ = *gsrc++;
861 *dst++ = *gsrc++;
862 *dst++ = *gsrc++;
863 }
864 else
865 {
866 unsigned data = *src;
867 *dst++ = colorindex[(data >> 6) & 3];
868 *dst++ = colorindex[(data >> 4) & 3];
869 *dst++ = colorindex[(data >> 2) & 3];
870 *dst++ = colorindex[data & 3];
871 }
872 gx++, src++;
873 }
874 while (dst < dst_end);
875
876#endif /* LCD_DEPTH */
877#elif LCD_PIXELFORMAT == VERTICAL_PACKING
878 gsrc = _grey_info.values + (~gy & _GREY_BMASK)
879 + _GREY_MULUQ(_grey_info.width, gy & ~_GREY_BMASK);
880
881#if LCD_DEPTH == 1
882 mask = BIT_N(y & 7);
883 src = lcd_fb + _GREY_MULUQ(LCD_WIDTH, y >> 3);
884
885 do
886 {
887 if (((unsigned)gy < (unsigned)_grey_info.height)
888 && ((unsigned)gx < (unsigned)_grey_info.width))
889 {
890 val = *gsrc;
891#ifdef HAVE_LCD_SPLIT
892 val -= val >> 7;
893#endif
894 gsrc += _GREY_BSIZE;
895 }
896 else
897 {
898#ifdef HAVE_NEGATIVE_LCD
899 val = (*src & mask) ? (NUM_SHADES-1) : 0;
900#else
901 val = (*src & mask) ? 0 : (NUM_SHADES-1);
902#endif
903 }
904#ifdef HAVE_LCD_SPLIT
905 if (y < LCD_SPLIT_POS)
906 val |= 0x80;
907#endif
908 *dst++ = val;
909 gx++, src++;
910 }
911 while (dst < dst_end);
912
913#elif LCD_DEPTH == 2
914 shift = 2 * (y & 3);
915 src = lcd_fb + _GREY_MULUQ(LCD_WIDTH, y >> 2);
916
917 do
918 {
919 if (((unsigned)gy < (unsigned)_grey_info.height)
920 && ((unsigned)gx < (unsigned)_grey_info.width))
921 {
922 *dst++ = *gsrc;
923 gsrc += _GREY_BSIZE;
924 }
925 else
926 {
927 *dst++ = colorindex[(*src >> shift) & 3];
928 }
929 gx++, src++;
930 }
931 while (dst < dst_end);
932
933#endif /* LCD_DEPTH */
934#elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
935 gsrc = _grey_info.values + (~gy & _GREY_BMASK)
936 + _GREY_MULUQ(_grey_info.width, gy & ~_GREY_BMASK);
937
938#if LCD_DEPTH == 2
939 shift = y & 7;
940 src = lcd_fb + _GREY_MULUQ(LCD_WIDTH, y >> 3);
941
942 do
943 {
944 if (((unsigned)gy < (unsigned)_grey_info.height)
945 && ((unsigned)gx < (unsigned)_grey_info.width))
946 {
947 *dst++ = *gsrc;
948 gsrc += _GREY_BSIZE;
949 }
950 else
951 {
952 data = (*src >> shift) & 0x0101;
953 *dst++ = colorindex[((data >> 7) | data) & 3];
954 }
955 gx++, src++;
956 }
957 while (dst < dst_end);
958
959#endif /* LCD_DEPTH */
960#endif /* LCD_PIXELFORMAT */
961
962 rb->write(fd, linebuf, BMP_LINESIZE);
963 }
964}