summaryrefslogtreecommitdiff
path: root/firmware/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers')
-rw-r--r--firmware/drivers/fat.c165
-rw-r--r--firmware/drivers/lcd-16bit.c26
-rw-r--r--firmware/drivers/lcd-h100-remote.c26
-rw-r--r--firmware/drivers/lcd-h100.c18
-rw-r--r--firmware/drivers/lcd-player.c40
-rw-r--r--firmware/drivers/lcd-recorder.c18
6 files changed, 105 insertions, 188 deletions
diff --git a/firmware/drivers/fat.c b/firmware/drivers/fat.c
index fd09bff0da..559d00b2b9 100644
--- a/firmware/drivers/fat.c
+++ b/firmware/drivers/fat.c
@@ -28,6 +28,7 @@
28#include "system.h" 28#include "system.h"
29#include "timefuncs.h" 29#include "timefuncs.h"
30#include "kernel.h" 30#include "kernel.h"
31#include "rbunicode.h"
31 32
32#define BYTES2INT16(array,pos) \ 33#define BYTES2INT16(array,pos) \
33 (array[pos] | (array[pos+1] << 8 )) 34 (array[pos] | (array[pos+1] << 8 ))
@@ -115,74 +116,6 @@
115#define FAT_BAD_MARK 0x0ffffff7 116#define FAT_BAD_MARK 0x0ffffff7
116#define FAT_EOF_MARK 0x0ffffff8 117#define FAT_EOF_MARK 0x0ffffff8
117 118
118/* filename charset conversion table */
119static const unsigned char unicode2iso8859_2[] = {
120 0x00, 0x00, 0xc3, 0xe3, 0xa1, 0xb1, 0xc6, 0xe6, /* 0x0100 */
121 0x00, 0x00, 0x00, 0x00, 0xc8, 0xe8, 0xcf, 0xef, /* 0x0108 */
122 0xd0, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0110 */
123 0xca, 0xea, 0xcc, 0xec, 0x00, 0x00, 0x00, 0x00, /* 0x0118 */
124 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0120 */
125 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0128 */
126 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0130 */
127 0x00, 0xc5, 0xe5, 0x00, 0x00, 0xa5, 0xb5, 0x00, /* 0x0138 */
128 0x00, 0xa3, 0xb3, 0xd1, 0xf1, 0x00, 0x00, 0xd2, /* 0x0140 */
129 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0148 */
130 0xd5, 0xf5, 0x00, 0x00, 0xc0, 0xe0, 0x00, 0x00, /* 0x0150 */
131 0xd8, 0xf8, 0xa6, 0xb6, 0x00, 0x00, 0xaa, 0xba, /* 0x0158 */
132 0xa9, 0xb9, 0xde, 0xfe, 0xab, 0xbb, 0x00, 0x00, /* 0x0160 */
133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0xf9, /* 0x0168 */
134 0xdb, 0xfb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0170 */
135 0x00, 0xac, 0xbc, 0xaf, 0xbf, 0xae, 0xbe, 0x00, /* 0x0178 */
136 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0180 */
137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0188 */
138 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0190 */
139 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0198 */
140 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01a0 */
141 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01a8 */
142 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01b0 */
143 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01b8 */
144 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01c0 */
145 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01c8 */
146 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01d0 */
147 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01d8 */
148 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01e0 */
149 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01e8 */
150 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01f0 */
151 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x01f8 */
152 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0200 */
153 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0208 */
154 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0210 */
155 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0218 */
156 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0220 */
157 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0228 */
158 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0230 */
159 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0238 */
160 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0240 */
161 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0248 */
162 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0250 */
163 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0258 */
164 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0260 */
165 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0268 */
166 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0270 */
167 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0278 */
168 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0280 */
169 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0288 */
170 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0290 */
171 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x0298 */
172 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02a0 */
173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02a8 */
174 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02b0 */
175 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02b8 */
176 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, /* 0x02c0 */
177 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02c8 */
178 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02d0 */
179 0xa2, 0xff, 0x00, 0xb2, 0x00, 0xbd, 0x00, 0x00, /* 0x02d8 */
180 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02e0 */
181 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02e8 */
182 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x02f0 */
183 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /* 0x02f8 */
184};
185
186struct fsinfo { 119struct fsinfo {
187 unsigned long freecount; /* last known free cluster count */ 120 unsigned long freecount; /* last known free cluster count */
188 unsigned long nextfree; /* first cluster to start looking for free 121 unsigned long nextfree; /* first cluster to start looking for free
@@ -1106,10 +1039,11 @@ static int write_long_name(struct fat_file* file,
1106 unsigned char* entry; 1039 unsigned char* entry;
1107 unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR; 1040 unsigned int idx = firstentry % DIR_ENTRIES_PER_SECTOR;
1108 unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR; 1041 unsigned int sector = firstentry / DIR_ENTRIES_PER_SECTOR;
1109 unsigned int i, j=0;
1110 unsigned char chksum = 0; 1042 unsigned char chksum = 0;
1111 int nameidx=0, namelen = strlen(name); 1043 unsigned int i, j=0;
1044 unsigned int nameidx=0, namelen = utf8length(name);
1112 int rc; 1045 int rc;
1046 unsigned short name_utf16[namelen + 1];
1113 1047
1114 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n", 1048 LDEBUGF("write_long_name(file:%lx, first:%d, num:%d, name:%s)\n",
1115 file->firstcluster, firstentry, numentries, name); 1049 file->firstcluster, firstentry, numentries, name);
@@ -1132,6 +1066,11 @@ static int write_long_name(struct fat_file* file,
1132 nameidx < (namelen - NAME_BYTES_PER_ENTRY); 1066 nameidx < (namelen - NAME_BYTES_PER_ENTRY);
1133 nameidx += NAME_BYTES_PER_ENTRY); 1067 nameidx += NAME_BYTES_PER_ENTRY);
1134 1068
1069 /* we need to convert the name first */
1070 /* since it is written in reverse order */
1071 for (i = 0; i <= namelen; i++)
1072 name = utf8decode(name, &name_utf16[i]);
1073
1135 for (i=0; i < numentries; i++) { 1074 for (i=0; i < numentries; i++) {
1136 /* new sector? */ 1075 /* new sector? */
1137 if ( idx >= DIR_ENTRIES_PER_SECTOR ) { 1076 if ( idx >= DIR_ENTRIES_PER_SECTOR ) {
@@ -1170,7 +1109,7 @@ static int write_long_name(struct fat_file* file,
1170 memset(entry, 0, DIR_ENTRY_SIZE); 1109 memset(entry, 0, DIR_ENTRY_SIZE);
1171 if ( i+1 < numentries ) { 1110 if ( i+1 < numentries ) {
1172 /* longname entry */ 1111 /* longname entry */
1173 int k, l = nameidx; 1112 unsigned int k, l = nameidx;
1174 1113
1175 entry[FATLONG_ORDER] = numentries-i-1; 1114 entry[FATLONG_ORDER] = numentries-i-1;
1176 if (i==0) { 1115 if (i==0) {
@@ -1178,22 +1117,22 @@ static int write_long_name(struct fat_file* file,
1178 entry[FATLONG_ORDER] |= 0x40; 1117 entry[FATLONG_ORDER] |= 0x40;
1179 1118
1180 /* pad name with 0xffff */ 1119 /* pad name with 0xffff */
1181 for (k=1; k<12; k++) entry[k] = 0xff; 1120 for (k=1; k<11; k++) entry[k] = 0xff;
1182 for (k=14; k<26; k++) entry[k] = 0xff; 1121 for (k=14; k<26; k++) entry[k] = 0xff;
1183 for (k=28; k<32; k++) entry[k] = 0xff; 1122 for (k=28; k<32; k++) entry[k] = 0xff;
1184 }; 1123 };
1185 /* set name */ 1124 /* set name */
1186 for (k=0; k<5 && l <= namelen; k++) { 1125 for (k=0; k<5 && l <= namelen; k++) {
1187 entry[k*2 + 1] = name[l++]; 1126 entry[k*2 + 1] = (unsigned char)(name_utf16[l] & 0xff);
1188 entry[k*2 + 2] = 0; 1127 entry[k*2 + 2] = (unsigned char)(name_utf16[l++] >> 8);
1189 } 1128 }
1190 for (k=0; k<6 && l <= namelen; k++) { 1129 for (k=0; k<6 && l <= namelen; k++) {
1191 entry[k*2 + 14] = name[l++]; 1130 entry[k*2 + 14] = (unsigned char)(name_utf16[l] & 0xff);
1192 entry[k*2 + 15] = 0; 1131 entry[k*2 + 15] = (unsigned char)(name_utf16[l++] >> 8);
1193 } 1132 }
1194 for (k=0; k<2 && l <= namelen; k++) { 1133 for (k=0; k<2 && l <= namelen; k++) {
1195 entry[k*2 + 28] = name[l++]; 1134 entry[k*2 + 28] = (unsigned char)(name_utf16[l] & 0xff);
1196 entry[k*2 + 29] = 0; 1135 entry[k*2 + 29] = (unsigned char)(name_utf16[l++] >> 8);
1197 } 1136 }
1198 1137
1199 entry[FATDIR_ATTR] = FAT_ATTR_LONG_NAME; 1138 entry[FATDIR_ATTR] = FAT_ATTR_LONG_NAME;
@@ -1291,7 +1230,7 @@ static int add_dir_entry(struct fat_dir* dir,
1291 1230
1292 /* one dir entry needed for every 13 bytes of filename, 1231 /* one dir entry needed for every 13 bytes of filename,
1293 plus one entry for the short name */ 1232 plus one entry for the short name */
1294 entries_needed = (strlen(name) + (NAME_BYTES_PER_ENTRY-1)) 1233 entries_needed = (utf8length(name) + (NAME_BYTES_PER_ENTRY-1))
1295 / NAME_BYTES_PER_ENTRY + 1; 1234 / NAME_BYTES_PER_ENTRY + 1;
1296 } 1235 }
1297 1236
@@ -2226,58 +2165,6 @@ int fat_opendir(IF_MV2(int volume,)
2226 return 0; 2165 return 0;
2227} 2166}
2228 2167
2229/* convert from unicode to a single-byte charset */
2230static void unicode2iso(const unsigned char* unicode, unsigned char* iso,
2231 int count)
2232{
2233 int i;
2234
2235 for (i=0; i<count; i++) {
2236 int x = i*2;
2237 switch (unicode[x+1]) {
2238 case 0x01: /* latin extended. convert to ISO 8859-2 */
2239 case 0x02:
2240 iso[i] = unicode2iso8859_2[unicode[x]];
2241 break;
2242
2243 case 0x03: /* greek, convert to ISO 8859-7 */
2244 iso[i] = unicode[x] + 0x30;
2245 break;
2246
2247 /* Sergei says most russians use Win1251, so we will too.
2248 Win1251 differs from ISO 8859-5 by an offset of 0x10. */
2249 case 0x04: /* cyrillic, convert to Win1251 */
2250 switch (unicode[x]) {
2251 case 1:
2252 iso[i] = 168;
2253 break;
2254
2255 case 81:
2256 iso[i] = 184;
2257 break;
2258
2259 default:
2260 iso[i] = unicode[x] + 0xb0; /* 0xa0 for ISO 8859-5 */
2261 break;
2262 }
2263 break;
2264
2265 case 0x05: /* hebrew, convert to ISO 8859-8 */
2266 iso[i] = unicode[x] + 0x10;
2267 break;
2268
2269 case 0x06: /* arabic, convert to ISO 8859-6 */
2270 case 0x0e: /* thai, convert to ISO 8859-11 */
2271 iso[i] = unicode[x] + 0xa0;
2272 break;
2273
2274 default:
2275 iso[i] = unicode[x];
2276 break;
2277 }
2278 }
2279}
2280
2281int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry) 2168int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
2282{ 2169{
2283 bool done = false; 2170 bool done = false;
@@ -2348,7 +2235,8 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
2348 2235
2349 /* replace shortname with longname? */ 2236 /* replace shortname with longname? */
2350 if ( longs ) { 2237 if ( longs ) {
2351 int j,l=0; 2238 int j;
2239 unsigned char* utf8 = entry->name;
2352 /* iterate backwards through the dir entries */ 2240 /* iterate backwards through the dir entries */
2353 for (j=longs-1; j>=0; j--) { 2241 for (j=longs-1; j>=0; j--) {
2354 unsigned char* ptr = cached_buf; 2242 unsigned char* ptr = cached_buf;
@@ -2370,16 +2258,11 @@ int fat_getnext(struct fat_dir *dir, struct fat_direntry *entry)
2370 index &= SECTOR_SIZE-1; 2258 index &= SECTOR_SIZE-1;
2371 } 2259 }
2372 2260
2373 /* names are stored in unicode, but we 2261 utf8 = utf16LEdecode(ptr + index + 1, utf8, 5);
2374 only grab the low byte (iso8859-1). */ 2262 utf8 = utf16LEdecode(ptr + index + 14, utf8, 6);
2375 unicode2iso(ptr + index + 1, entry->name + l, 5); 2263 utf8 = utf16LEdecode(ptr + index + 28, utf8, 2);
2376 l+= 5;
2377 unicode2iso(ptr + index + 14, entry->name + l, 6);
2378 l+= 6;
2379 unicode2iso(ptr + index + 28, entry->name + l, 2);
2380 l+= 2;
2381 } 2264 }
2382 entry->name[l]=0; 2265 *utf8 = 0;
2383 } 2266 }
2384 done = true; 2267 done = true;
2385 sectoridx = 0; 2268 sectoridx = 0;
diff --git a/firmware/drivers/lcd-16bit.c b/firmware/drivers/lcd-16bit.c
index a4ae6cd553..582050c878 100644
--- a/firmware/drivers/lcd-16bit.c
+++ b/firmware/drivers/lcd-16bit.c
@@ -30,6 +30,7 @@
30#include "debug.h" 30#include "debug.h"
31#include "system.h" 31#include "system.h"
32#include "font.h" 32#include "font.h"
33#include "rbunicode.h"
33#include "bidi.h" 34#include "bidi.h"
34 35
35#define SCROLLABLE_LINES 26 36#define SCROLLABLE_LINES 26
@@ -542,13 +543,13 @@ void lcd_bitmap(const fb_data *src, int x, int y, int width, int height)
542/* put a string at a given pixel position, skipping first ofs pixel columns */ 543/* put a string at a given pixel position, skipping first ofs pixel columns */
543static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str) 544static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
544{ 545{
545 int ch; 546 unsigned short ch;
547 unsigned short *ucs;
546 struct font* pf = font_get(curfont); 548 struct font* pf = font_get(curfont);
547 549
548 if (bidi_support_enabled) 550 ucs = bidi_l2v(str, 1);
549 str = bidi_l2v(str, 1);
550 551
551 while ((ch = *str++) != '\0' && x < LCD_WIDTH) 552 while ((ch = *ucs++) != 0 && x < LCD_WIDTH)
552 { 553 {
553 int width; 554 int width;
554 const unsigned char *bits; 555 const unsigned char *bits;
@@ -559,7 +560,7 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
559 ch -= pf->firstchar; 560 ch -= pf->firstchar;
560 561
561 /* get proportional width and glyph bits */ 562 /* get proportional width and glyph bits */
562 width = pf->width ? pf->width[ch] : pf->maxwidth; 563 width = font_get_width(pf,ch);
563 564
564 if (ofs > width) 565 if (ofs > width)
565 { 566 {
@@ -567,8 +568,7 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
567 continue; 568 continue;
568 } 569 }
569 570
570 bits = pf->bits + (pf->offset ? 571 bits = font_get_bits(pf, ch);
571 pf->offset[ch] : ((pf->height + 7) / 8 * pf->maxwidth * ch));
572 572
573 lcd_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height); 573 lcd_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height);
574 574
@@ -597,7 +597,7 @@ void lcd_puts_style(int x, int y, const unsigned char *str, int style)
597 return; 597 return;
598 598
599 lcd_getstringsize(str, &w, &h); 599 lcd_getstringsize(str, &w, &h);
600 xpos = xmargin + x*w / strlen(str); 600 xpos = xmargin + x*w / utf8length(str);
601 ypos = ymargin + y*h; 601 ypos = ymargin + y*h;
602 lcd_putsxy(xpos, ypos, str); 602 lcd_putsxy(xpos, ypos, str);
603 drawmode = (DRMODE_SOLID|DRMODE_INVERSEVID); 603 drawmode = (DRMODE_SOLID|DRMODE_INVERSEVID);
@@ -707,7 +707,7 @@ void lcd_puts_scroll_style(int x, int y, const unsigned char *string, int style)
707 end = strchr(s->line, '\0'); 707 end = strchr(s->line, '\0');
708 strncpy(end, string, LCD_WIDTH/2); 708 strncpy(end, string, LCD_WIDTH/2);
709 709
710 s->len = strlen(string); 710 s->len = utf8length(string);
711 s->offset = 0; 711 s->offset = 0;
712 s->startx = x; 712 s->startx = x;
713 s->backward = false; 713 s->backward = false;
@@ -765,9 +765,11 @@ static void scroll_thread(void)
765 } 765 }
766 } 766 }
767 else { 767 else {
768 /* scroll forward the whole time */ 768 /* pause at beginning of line */
769 if (s->offset >= s->width) 769 if (s->offset >= s->width) {
770 s->offset %= s->width; 770 s->offset = 0;
771 s->start_tick = current_tick + scroll_delay * 2;
772 }
771 } 773 }
772 774
773 lastmode = drawmode; 775 lastmode = drawmode;
diff --git a/firmware/drivers/lcd-h100-remote.c b/firmware/drivers/lcd-h100-remote.c
index 33a8b3790d..a2fe63ee97 100644
--- a/firmware/drivers/lcd-h100-remote.c
+++ b/firmware/drivers/lcd-h100-remote.c
@@ -29,6 +29,7 @@
29#include "debug.h" 29#include "debug.h"
30#include "system.h" 30#include "system.h"
31#include "font.h" 31#include "font.h"
32#include "rbunicode.h"
32#include "bidi.h" 33#include "bidi.h"
33 34
34/*** definitions ***/ 35/*** definitions ***/
@@ -1091,13 +1092,13 @@ void lcd_remote_bitmap(const unsigned char *src, int x, int y, int width,
1091/* put a string at a given pixel position, skipping first ofs pixel columns */ 1092/* put a string at a given pixel position, skipping first ofs pixel columns */
1092static void lcd_remote_putsxyofs(int x, int y, int ofs, const unsigned char *str) 1093static void lcd_remote_putsxyofs(int x, int y, int ofs, const unsigned char *str)
1093{ 1094{
1094 int ch; 1095 unsigned short ch;
1096 unsigned short *ucs;
1095 struct font* pf = font_get(curfont); 1097 struct font* pf = font_get(curfont);
1096 1098
1097 if (bidi_support_enabled) 1099 ucs = bidi_l2v(str, 1);
1098 str = bidi_l2v(str, 1);
1099 1100
1100 while ((ch = *str++) != '\0' && x < LCD_REMOTE_WIDTH) 1101 while ((ch = *ucs++) != 0 && x < LCD_REMOTE_WIDTH)
1101 { 1102 {
1102 int width; 1103 int width;
1103 const unsigned char *bits; 1104 const unsigned char *bits;
@@ -1108,7 +1109,7 @@ static void lcd_remote_putsxyofs(int x, int y, int ofs, const unsigned char *str
1108 ch -= pf->firstchar; 1109 ch -= pf->firstchar;
1109 1110
1110 /* get proportional width and glyph bits */ 1111 /* get proportional width and glyph bits */
1111 width = pf->width ? pf->width[ch] : pf->maxwidth; 1112 width = font_get_width(pf, ch);
1112 1113
1113 if (ofs > width) 1114 if (ofs > width)
1114 { 1115 {
@@ -1116,8 +1117,7 @@ static void lcd_remote_putsxyofs(int x, int y, int ofs, const unsigned char *str
1116 continue; 1117 continue;
1117 } 1118 }
1118 1119
1119 bits = pf->bits + (pf->offset ? 1120 bits = font_get_bits(pf, ch);
1120 pf->offset[ch] : ((pf->height + 7) / 8 * pf->maxwidth * ch));
1121 1121
1122 lcd_remote_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, 1122 lcd_remote_bitmap_part(bits, ofs, 0, width, x, y, width - ofs,
1123 pf->height); 1123 pf->height);
@@ -1153,7 +1153,7 @@ void lcd_remote_puts_style(int x, int y, const unsigned char *str, int style)
1153 return; 1153 return;
1154 1154
1155 lcd_remote_getstringsize(str, &w, &h); 1155 lcd_remote_getstringsize(str, &w, &h);
1156 xpos = xmargin + x*w / strlen((char *)str); 1156 xpos = xmargin + x*w / utf8length((char *)str);
1157 ypos = ymargin + y*h; 1157 ypos = ymargin + y*h;
1158 lcd_remote_putsxy(xpos, ypos, str); 1158 lcd_remote_putsxy(xpos, ypos, str);
1159 drawmode = (DRMODE_SOLID|DRMODE_INVERSEVID); 1159 drawmode = (DRMODE_SOLID|DRMODE_INVERSEVID);
@@ -1256,7 +1256,7 @@ void lcd_remote_puts_scroll_style(int x, int y, const unsigned char *string, int
1256 end = strchr(s->line, '\0'); 1256 end = strchr(s->line, '\0');
1257 strncpy(end, (char *)string, LCD_REMOTE_WIDTH/2); 1257 strncpy(end, (char *)string, LCD_REMOTE_WIDTH/2);
1258 1258
1259 s->len = strlen((char *)string); 1259 s->len = utf8length((char *)string);
1260 s->offset = 0; 1260 s->offset = 0;
1261 s->startx = x; 1261 s->startx = x;
1262 s->backward = false; 1262 s->backward = false;
@@ -1323,9 +1323,11 @@ static void scroll_thread(void)
1323 } 1323 }
1324 } 1324 }
1325 else { 1325 else {
1326 /* scroll forward the whole time */ 1326 /* pause at beginning of line */
1327 if (s->offset >= s->width) 1327 if (s->offset >= s->width) {
1328 s->offset %= s->width; 1328 s->offset = 0;
1329 s->start_tick = current_tick + scroll_delay * 2;
1330 }
1329 } 1331 }
1330 1332
1331 lastmode = drawmode; 1333 lastmode = drawmode;
diff --git a/firmware/drivers/lcd-h100.c b/firmware/drivers/lcd-h100.c
index ba959d23de..1199bf04a1 100644
--- a/firmware/drivers/lcd-h100.c
+++ b/firmware/drivers/lcd-h100.c
@@ -28,6 +28,7 @@
28#include "debug.h" 28#include "debug.h"
29#include "system.h" 29#include "system.h"
30#include "font.h" 30#include "font.h"
31#include "rbunicode.h"
31#include "bidi.h" 32#include "bidi.h"
32 33
33/*** definitions ***/ 34/*** definitions ***/
@@ -1014,13 +1015,13 @@ void lcd_bitmap(const unsigned char *src, int x, int y, int width, int height)
1014/* put a string at a given pixel position, skipping first ofs pixel columns */ 1015/* put a string at a given pixel position, skipping first ofs pixel columns */
1015static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str) 1016static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
1016{ 1017{
1017 int ch; 1018 unsigned short ch;
1019 unsigned short *ucs;
1018 struct font* pf = font_get(curfont); 1020 struct font* pf = font_get(curfont);
1019 1021
1020 if (bidi_support_enabled) 1022 ucs = bidi_l2v(str, 1);
1021 str = bidi_l2v(str, 1);
1022 1023
1023 while ((ch = *str++) != '\0' && x < LCD_WIDTH) 1024 while ((ch = *ucs++) != 0 && x < LCD_WIDTH)
1024 { 1025 {
1025 int width; 1026 int width;
1026 const unsigned char *bits; 1027 const unsigned char *bits;
@@ -1031,7 +1032,7 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
1031 ch -= pf->firstchar; 1032 ch -= pf->firstchar;
1032 1033
1033 /* get proportional width and glyph bits */ 1034 /* get proportional width and glyph bits */
1034 width = pf->width ? pf->width[ch] : pf->maxwidth; 1035 width = font_get_width(pf,ch);
1035 1036
1036 if (ofs > width) 1037 if (ofs > width)
1037 { 1038 {
@@ -1039,8 +1040,7 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
1039 continue; 1040 continue;
1040 } 1041 }
1041 1042
1042 bits = pf->bits + (pf->offset ? 1043 bits = font_get_bits(pf, ch);
1043 pf->offset[ch] : ((pf->height + 7) / 8 * pf->maxwidth * ch));
1044 1044
1045 lcd_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height); 1045 lcd_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height);
1046 1046
@@ -1069,7 +1069,7 @@ void lcd_puts_style(int x, int y, const unsigned char *str, int style)
1069 return; 1069 return;
1070 1070
1071 lcd_getstringsize(str, &w, &h); 1071 lcd_getstringsize(str, &w, &h);
1072 xpos = xmargin + x*w / strlen((char *)str); 1072 xpos = xmargin + x*w / utf8length((char *)str);
1073 ypos = ymargin + y*h; 1073 ypos = ymargin + y*h;
1074 lcd_putsxy(xpos, ypos, str); 1074 lcd_putsxy(xpos, ypos, str);
1075 drawmode = (DRMODE_SOLID|DRMODE_INVERSEVID); 1075 drawmode = (DRMODE_SOLID|DRMODE_INVERSEVID);
@@ -1178,7 +1178,7 @@ void lcd_puts_scroll_style(int x, int y, const unsigned char *string, int style)
1178 end = strchr(s->line, '\0'); 1178 end = strchr(s->line, '\0');
1179 strncpy(end, (char *)string, LCD_WIDTH/2); 1179 strncpy(end, (char *)string, LCD_WIDTH/2);
1180 1180
1181 s->len = strlen((char *)string); 1181 s->len = utf8length((char *)string);
1182 s->offset = 0; 1182 s->offset = 0;
1183 s->startx = x; 1183 s->startx = x;
1184 s->backward = false; 1184 s->backward = false;
diff --git a/firmware/drivers/lcd-player.c b/firmware/drivers/lcd-player.c
index 566c868d7f..d01ec3447f 100644
--- a/firmware/drivers/lcd-player.c
+++ b/firmware/drivers/lcd-player.c
@@ -31,6 +31,7 @@
31#include "system.h" 31#include "system.h"
32#include "font.h" 32#include "font.h"
33#include "lcd-player-charset.h" 33#include "lcd-player-charset.h"
34#include "rbunicode.h"
34 35
35/*** definitions ***/ 36/*** definitions ***/
36 37
@@ -323,9 +324,24 @@ static void lcd_puts_cont_scroll(int x, int y, const unsigned char *string)
323} 324}
324void lcd_puts(int x, int y, const unsigned char *string) 325void lcd_puts(int x, int y, const unsigned char *string)
325{ 326{
327 int i=0;
328 unsigned short ucs;
329 const unsigned char *utf8 = string;
330 unsigned char tmp[12];
331
332 while (*utf8 && i<11) {
333 utf8 = utf8decode(utf8, &ucs);
334 if (ucs < 256)
335 tmp[i++] = ucs;
336 else
337 tmp[i++] = '?';
338 }
339
340 tmp[i] = 0;
341
326 DEBUGF("lcd_puts(%d, %d) -> ", x, y); 342 DEBUGF("lcd_puts(%d, %d) -> ", x, y);
327 scroll[y].mode=SCROLL_MODE_OFF; 343 scroll[y].mode=SCROLL_MODE_OFF;
328 return lcd_puts_cont_scroll(x, y, string); 344 return lcd_puts_cont_scroll(x, y, tmp);
329} 345}
330 346
331void lcd_put_cursor(int x, int y, char cursor_char) 347void lcd_put_cursor(int x, int y, char cursor_char)
@@ -627,14 +643,28 @@ void lcd_bidir_scroll(int percent)
627void lcd_puts_scroll(int x, int y, const unsigned char* string ) 643void lcd_puts_scroll(int x, int y, const unsigned char* string )
628{ 644{
629 struct scrollinfo* s; 645 struct scrollinfo* s;
630 int i; 646 int i=0;
647 unsigned short ucs;
648 const unsigned char *utf8 = string;
649 unsigned char tmp[utf8length(string)+1];
650
651 while (*utf8) {
652 utf8 = utf8decode(utf8, &ucs);
653 if (ucs < 256)
654 tmp[i++] = ucs;
655 else
656 tmp[i++] = '?';
657 }
658
659 tmp[i] = 0;
660
631 661
632 DEBUGF("lcd_puts_scroll(%d, %d, %s)\n", x, y, string); 662 DEBUGF("lcd_puts_scroll(%d, %d, %s)\n", x, y, string);
633 663
634 s = &scroll[y]; 664 s = &scroll[y];
635 665
636 lcd_puts_cont_scroll(x,y,string); 666 lcd_puts_cont_scroll(x,y,tmp);
637 s->textlen = strlen(string); 667 s->textlen = strlen(tmp);
638 668
639 if ( s->textlen > 11-x ) { 669 if ( s->textlen > 11-x ) {
640 s->mode = SCROLL_MODE_RUN; 670 s->mode = SCROLL_MODE_RUN;
@@ -649,7 +679,7 @@ void lcd_puts_scroll(int x, int y, const unsigned char* string )
649 s->jump_scroll_steps=11-x; 679 s->jump_scroll_steps=11-x;
650 s->jump_scroll=jump_scroll; 680 s->jump_scroll=jump_scroll;
651 } 681 }
652 strncpy(s->text,string,sizeof s->text); 682 strncpy(s->text,tmp,sizeof s->text);
653 s->turn_offset=-1; 683 s->turn_offset=-1;
654 if (bidir_limit && (s->textlen < ((11-x)*(100+bidir_limit))/100)) { 684 if (bidir_limit && (s->textlen < ((11-x)*(100+bidir_limit))/100)) {
655 s->turn_offset=s->textlen+x-11; 685 s->turn_offset=s->textlen+x-11;
diff --git a/firmware/drivers/lcd-recorder.c b/firmware/drivers/lcd-recorder.c
index 7e064b8001..081a7a5267 100644
--- a/firmware/drivers/lcd-recorder.c
+++ b/firmware/drivers/lcd-recorder.c
@@ -28,6 +28,7 @@
28#include "system.h" 28#include "system.h"
29#include "font.h" 29#include "font.h"
30#include "hwcompat.h" 30#include "hwcompat.h"
31#include "rbunicode.h"
31#include "bidi.h" 32#include "bidi.h"
32 33
33/*** definitions ***/ 34/*** definitions ***/
@@ -844,13 +845,13 @@ void lcd_bitmap(const unsigned char *src, int x, int y, int width, int height)
844/* put a string at a given pixel position, skipping first ofs pixel columns */ 845/* put a string at a given pixel position, skipping first ofs pixel columns */
845static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str) 846static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
846{ 847{
847 int ch; 848 unsigned short ch;
849 unsigned short *ucs;
848 struct font* pf = font_get(curfont); 850 struct font* pf = font_get(curfont);
849 851
850 if (bidi_support_enabled) 852 ucs = bidi_l2v(str, 1);
851 str = bidi_l2v(str, 1);
852 853
853 while ((ch = *str++) != '\0' && x < LCD_WIDTH) 854 while ((ch = *ucs++) != 0 && x < LCD_WIDTH)
854 { 855 {
855 int width; 856 int width;
856 const unsigned char *bits; 857 const unsigned char *bits;
@@ -861,7 +862,7 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
861 ch -= pf->firstchar; 862 ch -= pf->firstchar;
862 863
863 /* get proportional width and glyph bits */ 864 /* get proportional width and glyph bits */
864 width = pf->width ? pf->width[ch] : pf->maxwidth; 865 width = font_get_width(pf,ch);
865 866
866 if (ofs > width) 867 if (ofs > width)
867 { 868 {
@@ -869,8 +870,7 @@ static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
869 continue; 870 continue;
870 } 871 }
871 872
872 bits = pf->bits + (pf->offset ? 873 bits = font_get_bits(pf, ch);
873 pf->offset[ch] : ((pf->height + 7) / 8 * pf->maxwidth * ch));
874 874
875 lcd_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height); 875 lcd_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height);
876 876
@@ -898,7 +898,7 @@ void lcd_puts_style(int x, int y, const unsigned char *str, int style)
898 return; 898 return;
899 899
900 lcd_getstringsize(str, &w, &h); 900 lcd_getstringsize(str, &w, &h);
901 xpos = xmargin + x*w / strlen(str); 901 xpos = xmargin + x*w / utf8length(str);
902 ypos = ymargin + y*h; 902 ypos = ymargin + y*h;
903 lcd_putsxy(xpos, ypos, str); 903 lcd_putsxy(xpos, ypos, str);
904 drawmode = (DRMODE_SOLID|DRMODE_INVERSEVID); 904 drawmode = (DRMODE_SOLID|DRMODE_INVERSEVID);
@@ -1007,7 +1007,7 @@ void lcd_puts_scroll_style(int x, int y, const unsigned char *string, int style)
1007 end = strchr(s->line, '\0'); 1007 end = strchr(s->line, '\0');
1008 strncpy(end, string, LCD_WIDTH/2); 1008 strncpy(end, string, LCD_WIDTH/2);
1009 1009
1010 s->len = strlen(string); 1010 s->len = utf8length(string);
1011 s->offset = 0; 1011 s->offset = 0;
1012 s->startx = x; 1012 s->startx = x;
1013 s->backward = false; 1013 s->backward = false;