1 /*
2 * drv-nl10.c - NL10 printer driver.
3 *
4 * Written by
5 * David Hansel <david@hansels.net>
6 *
7 * This file is part of VICE, the Versatile Commodore Emulator.
8 * See README for copyright notice.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
23 * 02111-1307 USA.
24 *
25 */
26
27 #include "vice.h"
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include "archdep.h"
34 #include "driver-select.h"
35 #include "drv-nl10.h"
36 #include "log.h"
37 #include "output-select.h"
38 #include "output.h"
39 #include "palette.h"
40 #include "sysfile.h"
41 #include "types.h"
42 #include "lib.h"
43
44 /* MAX_COL must be a multiple of 32 */
45 /* 2432 x 3172 */
46 #define BORDERX 16
47 #define BORDERY 2
48 #define MAX_COL (80 * 30 + 2 * BORDERX)
49 #define MAX_ROW (66 * 48 + 2 * BORDERY)
50 #define BUF_ROW (4 * 4 * 9 + 1)
51 #define CHARSET_SIZE 200
52 #define NL10_ROM_SIZE 0x8000
53
54 #define NL10_NLQ 0x00001
55 #define NL10_ELITE 0x00002
56 #define NL10_CONDENSED 0x00004
57 #define NL10_EXPANDED 0x00008
58 #define NL10_EXPANDED_LINE 0x00010
59 #define NL10_UNDERLINE 0x00020
60 #define NL10_SUPERSCRIPT 0x00040
61 #define NL10_SUBSCRIPT 0x00080
62 #define NL10_ITALIC 0x00100
63 #define NL10_BOLD 0x00200
64 #define NL10_EMPHASIZE 0x00400
65 #define NL10_PROP 0x00800
66 #define NL10_USERAM 0x01000
67 #define NL10_ASCII 0x02000
68 #define NL10_CBMTEXT 0x04000
69 #define NL10_REVERSE 0x08000
70 #define NL10_QUOTED 0x10000
71 #define NL10_ZERO_CROSSED 0x20000
72
73 #define NL10_GFX_OFF 0x00
74 #define NL10_GFX_SINGLE 0x01
75 #define NL10_GFX_DOUBLE 0x02
76 #define NL10_GFX_QUAD 0x03
77 #define NL10_GFX_CRT 0x04
78 #define NL10_GFX_PLOT 0x05
79 #define NL10_GFX_CRT2 0x06
80 #define NL10_GFX_REVERSE 0x40
81 #define NL10_GFX_7PIN 0x80
82
83 #define NL10_ESCBUF_SIZE 60
84
85 typedef struct nl10_s {
86 uint8_t esc[NL10_ESCBUF_SIZE], esc_ctr;
87 uint8_t line[BUF_ROW][MAX_COL];
88 uint8_t htabs[41], vtabs[41], macro[16];
89 uint8_t mapping[256];
90 uint8_t *char_ram, *char_ram_nlq;
91 uint8_t expand, expand_half;
92
93 int marg_l, marg_r, marg_t, marg_b;
94 int mapping_intl_id;
95 int pos_x, pos_y, pos_y_pix;
96 int col_nr, line_nr;
97 int isopen, mode, gfx_mode, gfx_count;
98 int linespace; /* in 1/216 inch */
99 } nl10_t;
100
101
102 static palette_t *palette = NULL;
103
104 /* Logging goes here. */
105 static log_t drvnl10_log = LOG_ERR;
106
107 #ifdef USE_EMBEDDED
108 #include "printernl10cbm.h"
109 #else
110 static uint8_t drv_nl10_rom[NL10_ROM_SIZE];
111 #endif
112
113 static uint8_t *drv_nl10_charset = drv_nl10_rom;
114 static uint8_t drv_nl10_charset_nlq[CHARSET_SIZE * 47];
115 static uint8_t drv_nl10_charset_nlq_italic[CHARSET_SIZE * 47];
116
117 STATIC_PROTOTYPE const uint8_t drv_nl10_charset_mapping_intl[3][8][14];
118 STATIC_PROTOTYPE const uint8_t drv_nl10_charset_mapping[3][256];
119
120 static int drv_nl10_init_charset(void);
121 static int handle_control_sequence(nl10_t *nl10, unsigned int prnr, const uint8_t c);
122 static int handle_esc_control_sequence(nl10_t *nl10, unsigned int prnr, const uint8_t c);
123
124 static nl10_t drv_nl10[NUM_OUTPUT_SELECT];
125
126
127 /* ------------------------------------------------------------------------- */
128 /* NL-10 printer engine. */
129
set_mode(nl10_t * nl10,unsigned int m)130 static inline void set_mode(nl10_t *nl10, unsigned int m)
131 {
132 nl10->mode |= m;
133 }
134
del_mode(nl10_t * nl10,unsigned int m)135 static inline void del_mode(nl10_t *nl10, unsigned int m)
136 {
137 nl10->mode &= ~m;
138 }
139
is_mode(nl10_t * nl10,unsigned int m)140 static inline int is_mode(nl10_t *nl10, unsigned int m)
141 {
142 return nl10->mode & m;
143 }
144
145
get_char_data(nl10_t * nl10,uint8_t c)146 static uint8_t *get_char_data(nl10_t *nl10, uint8_t c)
147 {
148 uint8_t *data;
149
150 if (nl10->mapping[c] == 0xff) {
151 data = NULL;
152 } else if (is_mode(nl10, NL10_NLQ)) {
153 if (is_mode(nl10, NL10_USERAM) && c >= 32 && c <= 127) {
154 data = nl10->char_ram_nlq + (c - 32) * 47;
155 } else if (is_mode(nl10, NL10_ITALIC)) {
156 data = drv_nl10_charset_nlq_italic + nl10->mapping[c] * 47;
157 } else {
158 data = drv_nl10_charset_nlq + nl10->mapping[c] * 47;
159 }
160 } else {
161 if (is_mode(nl10, NL10_USERAM) && c >= 32 && c <= 127) {
162 data = nl10->char_ram + (c - 32) * 12;
163 } else {
164 data = drv_nl10_charset + nl10->mapping[c] * 12;
165 }
166 }
167
168 return data;
169 }
170
171
get_char_width(nl10_t * nl10,uint8_t c,int no_prop)172 static double get_char_width(nl10_t *nl10, uint8_t c, int no_prop)
173 {
174 uint8_t *data = get_char_data(nl10, c);
175 double w;
176
177 if (data == NULL) {
178 return 0;
179 } else if (is_mode(nl10, NL10_NLQ)) {
180 w = 30;
181 } else if (is_mode(nl10, NL10_ELITE)) {
182 w = is_mode(nl10, NL10_CONDENSED) ? 15 : 25;
183 } else {
184 w = is_mode(nl10, NL10_CONDENSED) ? 17.5 : 30;
185 }
186
187 if (!no_prop && is_mode(nl10, NL10_PROP) && !is_mode(nl10, NL10_NLQ)) {
188 w = (w / 11.0) * ((data[0] & 15) - ((data[0] >> 4) & 7)) + 1;
189 }
190
191 return w * (is_mode(nl10, NL10_EXPANDED | NL10_EXPANDED_LINE) ? 2 : 1) * nl10->expand;
192 }
193
194
init_mapping(nl10_t * nl10,int intl)195 static void init_mapping(nl10_t *nl10, int intl)
196 {
197 int mapping;
198 if (is_mode(nl10, NL10_ASCII)) {
199 mapping = 0;
200 } else if (is_mode(nl10, NL10_CBMTEXT)) {
201 mapping = 2;
202 } else {
203 mapping = 1;
204 }
205
206 nl10->mapping_intl_id = intl;
207
208 memcpy(nl10->mapping, drv_nl10_charset_mapping[mapping], 256);
209 nl10->mapping[0x23] = drv_nl10_charset_mapping_intl[mapping][intl][0];
210 nl10->mapping[0x24] = drv_nl10_charset_mapping_intl[mapping][intl][1];
211 nl10->mapping[0x40] = drv_nl10_charset_mapping_intl[mapping][intl][2];
212 nl10->mapping[0x5b] = drv_nl10_charset_mapping_intl[mapping][intl][3];
213 nl10->mapping[0x5c] = drv_nl10_charset_mapping_intl[mapping][intl][4];
214 nl10->mapping[0x5d] = drv_nl10_charset_mapping_intl[mapping][intl][5];
215 nl10->mapping[0x7b] = drv_nl10_charset_mapping_intl[mapping][intl][6];
216 nl10->mapping[0x7c] = drv_nl10_charset_mapping_intl[mapping][intl][7];
217 nl10->mapping[0x7d] = drv_nl10_charset_mapping_intl[mapping][intl][8];
218 nl10->mapping[0x7e] = drv_nl10_charset_mapping_intl[mapping][intl][9];
219 nl10->mapping[0xdb] = drv_nl10_charset_mapping_intl[mapping][intl][10];
220 nl10->mapping[0xdc] = drv_nl10_charset_mapping_intl[mapping][intl][11];
221 nl10->mapping[0xdd] = drv_nl10_charset_mapping_intl[mapping][intl][12];
222 nl10->mapping[0xde] = drv_nl10_charset_mapping_intl[mapping][intl][13];
223
224 if (is_mode(nl10, NL10_ZERO_CROSSED)) {
225 nl10->mapping[0x30] = 0x1f;
226 }
227 }
228
229
reset(nl10_t * nl10)230 static void reset(nl10_t *nl10)
231 {
232 int i;
233 memset(nl10->line, 0, MAX_COL * BUF_ROW);
234
235 nl10->line_nr = 1;
236 nl10->linespace = 12 * 3;
237 nl10->mode = 0;
238 nl10->gfx_mode = 0;
239 nl10->col_nr = 0;
240 nl10->expand = 1;
241 nl10->marg_l = BORDERX;
242 nl10->marg_r = MAX_COL - BORDERX;
243 nl10->marg_t = 0;
244 nl10->marg_b = 0;
245 nl10->pos_x = nl10->marg_l;
246 /* init_mapping(nl10, 0); */
247
248 for (i = 0; i < 40; i++)
249 {
250 nl10->htabs[i] = 8 * (i + 1);
251 nl10->vtabs[i] = 0;
252 }
253
254 nl10->htabs[40] = 0;
255 nl10->vtabs[40] = 0;
256 }
257
258
reset_hard(nl10_t * nl10)259 static void reset_hard(nl10_t *nl10)
260 {
261 reset(nl10);
262 memset(nl10->char_ram, 0, 12 * 96);
263 memset(nl10->char_ram_nlq, 0, 47 * 96);
264 }
265
266
store_char(uint8_t * dest,const uint8_t * src)267 static int store_char(uint8_t *dest, const uint8_t *src)
268 {
269 uint8_t c, r;
270 int ret = 0, s = (src[0] >> 4) & 7, e = src[0] & 15;
271
272 if (s < 0 || s > 7) {
273 log_warning(drvnl10_log, "Illegal prop-start value: %u\n", s);
274 } else if (e < 4 || e > 11) {
275 log_warning(drvnl10_log, "Illegal prop-end value: %u\n", e);
276 } else if ((e - s) < 4) {
277 log_warning(drvnl10_log, "Illegal character width: (s=%u, e=%u)\n", s, e);
278 } else {
279 ret = 1;
280 }
281
282 dest[0] = ret ? src[0] : ((src[0] & 0x80) | 10);
283 for (c = 0; c < 11; c++)
284 {
285 dest[c + 1] = src[c + 1];
286 if (c != 0) {
287 for (r = 0; r < 8; r++) {
288 if ((dest[c] & (1 << r)) && (dest[c + 1] & (1 << r))) {
289 log_warning(drvnl10_log, "Illegal dot col=%u, row=%u\n", c + 1, r + 1);
290 dest[c + 1] = dest[c + 1] & ~(1 << r);
291 ret = 0;
292 }
293 }
294 }
295 }
296
297 return ret;
298 }
299
300
store_char_nlq(uint8_t * dest,const uint8_t * src)301 static int store_char_nlq(uint8_t *dest, const uint8_t *src)
302 {
303 uint8_t c, r;
304 int ret = 1;
305
306 dest[0] = src[0];
307 for (c = 0; c < 46; c++)
308 {
309 dest[c + 1] = src[c + 1];
310 if (c != 0 && c != 23) {
311 for (r = 0; r < 8; r++) {
312 if ((dest[c] & (1 << r)) && (dest[c + 1] & (1 << r))) {
313 log_warning(drvnl10_log, "Illegal dot col=%u, row=%u\n", c + 1, r + 1);
314 dest[c + 1] = dest[c + 1] & ~(1 << r);
315 ret = 0;
316 }
317 }
318 }
319 }
320
321 return ret;
322 }
323
324
inc_y(nl10_t * nl10)325 static inline int inc_y(nl10_t *nl10)
326 {
327 switch ((nl10->pos_y++) % 3) {
328 case 0: return 1;
329 case 1: return 2;
330 case 2: return 1;
331 }
332
333 return 0;
334 }
335
336
linefeed(nl10_t * nl10,unsigned int prnr)337 static void linefeed(nl10_t *nl10, unsigned int prnr)
338 {
339 int c, i, j;
340
341 for (i = 0; i < nl10->linespace; i++) {
342 for (j = inc_y(nl10); j > 0; j--) {
343 while (nl10->pos_y_pix < BORDERY) {
344 output_select_putc(prnr, (uint8_t)(OUTPUT_NEWLINE));
345 nl10->pos_y_pix++;
346 }
347
348 /* output topmost row */
349 for (c = 0; c < MAX_COL; c++) {
350 output_select_putc(prnr, (uint8_t)(nl10->line[0][c] ? OUTPUT_PIXEL_BLACK : OUTPUT_PIXEL_WHITE));
351 }
352 output_select_putc(prnr, (uint8_t)(OUTPUT_NEWLINE));
353
354 /* move everything else one row up */
355 memmove(nl10->line[0], nl10->line[1], (BUF_ROW - 1) * MAX_COL * sizeof(uint8_t));
356
357 /* clear bottom row */
358 memset(nl10->line[BUF_ROW - 1], 0, MAX_COL * sizeof(uint8_t));
359
360 /* increase pixel row count */
361 nl10->pos_y_pix++;
362
363 /* check end-of-page */
364 if (nl10->pos_y_pix >= MAX_ROW - BORDERY) {
365 while (nl10->pos_y_pix++ < MAX_ROW) {
366 output_select_putc(prnr, (uint8_t)(OUTPUT_NEWLINE));
367 }
368 nl10->line_nr = 0;
369 nl10->pos_y = 0;
370 nl10->pos_y_pix = 0;
371 }
372 }
373 }
374
375 nl10->line_nr++;
376 }
377
378
output_buf(nl10_t * nl10,unsigned int prnr)379 static void output_buf(nl10_t *nl10, unsigned int prnr)
380 {
381 int r, c;
382
383 /* output buffer */
384 for (r = 0; r < BUF_ROW; r++) {
385 for (c = 0; c < MAX_COL; c++) {
386 output_select_putc(prnr, (uint8_t)(drv_nl10[prnr].line[r][c] ? OUTPUT_PIXEL_BLACK : OUTPUT_PIXEL_WHITE));
387 }
388 output_select_putc(prnr, (uint8_t)(OUTPUT_NEWLINE));
389 }
390
391 /* clear buffer */
392 memset(nl10->line, 0, BUF_ROW * MAX_COL * sizeof(uint8_t));
393
394 nl10->pos_y += (BUF_ROW / 4 * 3);
395 nl10->pos_y_pix += BUF_ROW;
396 }
397
398
formfeed(nl10_t * nl10,unsigned int prnr)399 static void formfeed(nl10_t *nl10, unsigned int prnr)
400 {
401 int r;
402 output_buf(nl10, prnr);
403 for (r = nl10->pos_y_pix; r < MAX_ROW; r++) {
404 output_select_putc(prnr, (uint8_t)(OUTPUT_NEWLINE));
405 }
406 nl10->line_nr = 1;
407 nl10->pos_y = 0;
408 nl10->pos_y_pix = 0;
409 }
410
411
draw_point2(nl10_t * nl10,int x,int y)412 inline static void draw_point2(nl10_t *nl10, int x, int y)
413 {
414 /*
415 **
416 #*
417 **
418 */
419
420 nl10->line[y][x] = 1;
421 nl10->line[y][x + 1] = 1;
422 nl10->line[y + 1][x] = 1;
423 nl10->line[y - 1][x] = 1;
424 nl10->line[y + 1][x + 1] = 1;
425 nl10->line[y - 1][x + 1] = 1;
426 }
427
draw_point3(nl10_t * nl10,int x,int y)428 inline static void draw_point3(nl10_t *nl10, int x, int y)
429 {
430 /*
431 *
432 *#*
433 *
434 */
435
436 nl10->line[y][x] = 1;
437 nl10->line[y][x - 1] = 1;
438 nl10->line[y][x + 1] = 1;
439 nl10->line[y - 1][x] = 1;
440 nl10->line[y + 1][x] = 1;
441 }
442
draw_char_nlq(nl10_t * nl10,const uint8_t c)443 static void draw_char_nlq(nl10_t *nl10, const uint8_t c)
444 {
445 /*
446 NLQ (80 char per line, 30 pixels per char):
447 0 1 2
448 012345678901234567890123456789
449 ** * ** * ** * ** * ** * ** *
450 #**#*#**#*#**#*#**#*#**#*#**#*
451 ** * ** * ** * ** * ** * ** *
452
453 ** * ** * ** * ** * ** * **
454 #**#*#**#*#**#*#**#*#**#*#*
455 ** * ** * ** * ** * ** * **
456 */
457
458 int i, j, k, n, rs, re, underline, expanded;
459 uint8_t *cdata = get_char_data(nl10, c);
460
461 if (cdata) {
462 int xs = nl10->pos_x;
463 uint8_t desc = (cdata[0] & 128) ? 0 : 1;
464
465 underline = is_mode(nl10, NL10_UNDERLINE) ? 1 : 0;
466 expanded = (is_mode(nl10, NL10_EXPANDED | NL10_EXPANDED_LINE) ? 2 : 1) * nl10->expand;
467
468 if (nl10->expand_half == 0) {
469 rs = 0; re = 16;
470 } else if (nl10->expand_half == 1) {
471 rs = 0; re = 8;
472 } else if (nl10->expand_half == 2) {
473 rs = 8; re = 16;
474 } else {
475 rs = 0; re = 16;
476 }
477
478 for (i = 0; i < 23; i++) {
479 for (k = 0; k < expanded; k++)
480 {
481 uint16_t data;
482 data = ((cdata[i + 1] & 0x01 ? 0x0002 : 0) + (cdata[i + 24] & 0x01 ? 0x0001 : 0) +
483 (cdata[i + 1] & 0x02 ? 0x0008 : 0) + (cdata[i + 24] & 0x02 ? 0x0004 : 0) +
484 (cdata[i + 1] & 0x04 ? 0x0020 : 0) + (cdata[i + 24] & 0x04 ? 0x0010 : 0) +
485 (cdata[i + 1] & 0x08 ? 0x0080 : 0) + (cdata[i + 24] & 0x08 ? 0x0040 : 0) +
486 (cdata[i + 1] & 0x10 ? 0x0200 : 0) + (cdata[i + 24] & 0x10 ? 0x0100 : 0) +
487 (cdata[i + 1] & 0x20 ? 0x0800 : 0) + (cdata[i + 24] & 0x20 ? 0x0400 : 0) +
488 (cdata[i + 1] & 0x40 ? 0x2000 : 0) + (cdata[i + 24] & 0x40 ? 0x1000 : 0) +
489 (cdata[i + 1] & 0x80 ? 0x8000 : 0) + (cdata[i + 24] & 0x80 ? 0x4000 : 0));
490
491 for (j = rs; j < re; j++) {
492 for (n = 0; n < nl10->expand; n++)
493 {
494 if (underline && (j + desc) == 16 && n == 0) {
495 } else if (data & (1 << (15 - j))) {
496 if (i & 2 || expanded > 1) {
497 draw_point3(nl10, nl10->pos_x - expanded / 2 + k, ((j + desc) * nl10->expand + n) * 2 + 1);
498 } else {
499 draw_point2(nl10, nl10->pos_x - expanded / 2 + k, ((j + desc) * nl10->expand + n) * 2 + 1);
500 }
501 }
502 }
503 }
504
505 nl10->pos_x += ((i * expanded + k) % 4) == 1 ? 2 : 1;
506 }
507 }
508
509 nl10->pos_x += expanded;
510
511 if (underline) {
512 for (i = xs; i < nl10->pos_x; i++) {
513 if ((i & 3) == 1) {
514 draw_point2(nl10, i, (8 * nl10->expand) * 4 + 1);
515 }
516 }
517 }
518 }
519 }
520
draw_char_draft(nl10_t * nl10,const uint8_t c)521 static void draw_char_draft(nl10_t *nl10, const uint8_t c)
522 {
523 /*
524 Pica (80 char per line, 30 pixels per char):
525 0 1 2
526 012345678901234567890123456789
527 * * * * * *
528 *#* *#* *#* *#* *#* *#*
529 * * * * * *
530
531 ** ** ** ** **
532 #* #* #* #* #*
533 ** ** ** ** **
534
535 Elite (96 char per line, 25 pixels per char):
536 0 1 2
537 0123456789012345678901234
538 * * * * * *
539 *#* *#* *#* *#* *#* *#*
540 * * * * * *
541
542 * * * * *
543 *#* *#* *#* *#* *#*
544 * * * * *
545
546 Condensed (136 char per line, 17 3/5 pixels per char):
547 0 1
548 01234567890123456
549 ** ** ** ** ** **
550 #* #* #* #* #* #*
551 ** ** ** ** ** **
552
553 * * * * *
554 *#**#**#**#**#*
555 * * * * *
556 */
557
558 int i, j, k, l, m, n, cs, ce, rs, re, expanded, condensed, pinspace, pinoffset;
559 int bold, emphasize, underline, elite;
560 uint8_t desc, *cdata = get_char_data(nl10, c);
561
562 if (cdata) {
563 int xs = nl10->pos_x;
564
565 elite = is_mode(nl10, NL10_ELITE) ? 1 : 0;
566 expanded = (is_mode(nl10, NL10_EXPANDED | NL10_EXPANDED_LINE) ? 2 : 1) * nl10->expand;
567 underline = is_mode(nl10, NL10_UNDERLINE) ? 1 : 0;
568 bold = is_mode(nl10, NL10_BOLD) ? 1 : 0;
569 emphasize = is_mode(nl10, NL10_EMPHASIZE) ? 1 : 0;
570 condensed = is_mode(nl10, NL10_CONDENSED) && (!emphasize) && (!bold) ? 1 : 0;
571 pinoffset = is_mode(nl10, NL10_SUBSCRIPT) ? 4 * 4 : 0;
572 pinspace = (is_mode(nl10, NL10_SUPERSCRIPT) || is_mode(nl10, NL10_SUBSCRIPT)) ? 2 : 4;
573
574 if (is_mode(nl10, NL10_PROP)) {
575 cs = (cdata[0] >> 4) & 7; ce = (cdata[0] & 15) - 1;
576 } else {
577 cs = 0; ce = 10;
578 }
579
580 if (nl10->expand_half == 0) {
581 rs = 0; re = 8;
582 } else if (nl10->expand_half == 1) {
583 rs = 0; re = 4;
584 } else if (nl10->expand_half == 2) {
585 rs = 4; re = 8;
586 } else {
587 rs = 0; re = 8;
588 }
589
590 desc = (cdata[0] & 128) ? 0 : 1;
591 for (i = cs; i <= ce; i++)
592 {
593 uint8_t data = cdata[i + 1];
594 for (j = rs; j < re; j++) {
595 if (data & (1 << (7 - j))) {
596 for (l = 0; l <= emphasize; l++) {
597 for (m = 0; m <= bold; m++) {
598 for (n = 0; n < nl10->expand; n++) {
599 for (k = 0; k < expanded; k++)
600 {
601 if (underline && (j + desc) == 8 && n == 0) {
602 } else if (condensed) {
603 if ((expanded == 1) && ((i + l) & 1)) {
604 draw_point2(nl10, nl10->pos_x + 1 * l - 1, ((j + desc) * nl10->expand + n) * pinspace + pinoffset + 1 + 2 * m);
605 } else {
606 draw_point3(nl10, nl10->pos_x + 2 * l + 3 * k, ((j + desc) * nl10->expand + n) * pinspace + pinoffset + 1 + 2 * m);
607 }
608 } else if (elite) {
609 draw_point3(nl10, nl10->pos_x + l + 2 * l + 4 * k, ((j + desc) * nl10->expand + n) * pinspace + pinoffset + 1 + 2 * m);
610 } else {
611 if ((expanded == 1) && ((i + l) & 1)) {
612 draw_point2(nl10, nl10->pos_x + 2 * l, ((j + desc) * nl10->expand + n) * pinspace + pinoffset + 1 + 2 * m);
613 } else {
614 draw_point3(nl10, nl10->pos_x + 3 * l + 5 * k, ((j + desc) * nl10->expand + n) * pinspace + pinoffset + 1 + 2 * m);
615 }
616 }
617 }
618 }
619 }
620 }
621 }
622 }
623
624 if (condensed) {
625 nl10->pos_x += (expanded > 1) ? (3 * (expanded / 2)) : ((i & 1) ? 1 : 2);
626 } else if (elite) {
627 nl10->pos_x += 2 * expanded;
628 } else {
629 nl10->pos_x += (expanded > 1) ? (5 * (expanded / 2)) : ((i & 1) ? 3 : 2);
630 }
631 }
632
633 if (condensed) {
634 nl10->pos_x += (((nl10->col_nr % 5) & 1) ? 0 : expanded) + expanded / 2;
635 } else if (elite) {
636 nl10->pos_x += expanded * 3;
637 } else {
638 nl10->pos_x += expanded * 3 - expanded / 2;
639 }
640
641 if (underline) {
642 for (i = xs; i < nl10->pos_x; i++) {
643 if ((i & 3) == 1) {
644 draw_point2(nl10, i, (8 * nl10->expand) * pinspace + pinoffset + 1);
645 }
646 }
647 }
648 }
649 }
650
651
draw_char_draft_reverse(nl10_t * nl10,const uint8_t c)652 static void draw_char_draft_reverse(nl10_t *nl10, const uint8_t c)
653 {
654 int i, j, k, expanded;
655 uint8_t *cdata = get_char_data(nl10, c);
656
657 if (cdata) {
658 expanded = (is_mode(nl10, NL10_EXPANDED | NL10_EXPANDED_LINE) ? 2 : 1) * nl10->expand;
659
660 for (i = 0; i <= 11; i++) {
661 for (k = 0; k < expanded; k++) {
662 for (j = 0; j < 7; j++) {
663 uint8_t bit = 1 << (7 - j);
664
665 if ((i < 11 && (cdata[i + 1] & bit)) || (i > 0 && (cdata[i] & bit))) {
666 } else {
667 if (i & 1) {
668 draw_point2(nl10, nl10->pos_x, (j * 4) + 1);
669 } else {
670 draw_point3(nl10, nl10->pos_x, (j * 4) + 1);
671 }
672
673 if (i == 7) {
674 draw_point2(nl10, nl10->pos_x, (j * 4) + 1);
675 }
676 }
677 }
678
679 nl10->pos_x += ((i * expanded + k) & 1) ? 3 : 2;
680 }
681 }
682 }
683 }
684
685
draw_char(nl10_t * nl10,const uint8_t c)686 static void draw_char(nl10_t *nl10, const uint8_t c)
687 {
688 /*printf("draw_char %i %i\n", c, cc);*/
689
690 if (is_mode(nl10, NL10_NLQ)) {
691 if (is_mode(nl10, NL10_SUBSCRIPT | NL10_SUPERSCRIPT)) {
692 int tmp = nl10->mode;
693 nl10->mode = tmp & (NL10_SUBSCRIPT | NL10_SUPERSCRIPT | NL10_UNDERLINE | NL10_EXPANDED | NL10_EXPANDED_LINE);
694 draw_char_draft(nl10, c);
695 nl10->mode = tmp;
696 } else {
697 draw_char_nlq(nl10, c);
698 }
699 } else if (is_mode(nl10, NL10_REVERSE)) {
700 draw_char_draft_reverse(nl10, c);
701 } else {
702 draw_char_draft(nl10, c);
703 }
704 }
705
706
draw_graphics(nl10_t * nl10,uint8_t c)707 static void draw_graphics(nl10_t *nl10, uint8_t c)
708 {
709 int j;
710
711 if (nl10->gfx_mode & NL10_GFX_7PIN) {
712 switch (nl10->gfx_mode & ~(NL10_GFX_7PIN | NL10_GFX_REVERSE)) {
713 case NL10_GFX_SINGLE:
714 {
715 /* 480 dots per line */
716
717 for (j = 0; j < 7; j++) {
718 if (((c & (1 << j)) != 0) ^ ((nl10->gfx_mode & NL10_GFX_REVERSE) != 0)) {
719 draw_point3(nl10, nl10->pos_x, j * 4 + 1);
720 }
721 }
722
723 nl10->pos_x += 5;
724 break;
725 }
726
727 case NL10_GFX_DOUBLE:
728 {
729 /* 960 dots per line */
730
731 /* 01234 */
732 /* #**#* */
733
734 for (j = 0; j < 7; j++) {
735 if (c & (1 << j)) {
736 if (nl10->gfx_count & 1) {
737 draw_point3(nl10, nl10->pos_x, j * 4 + 1);
738 } else {
739 draw_point2(nl10, nl10->pos_x, j * 4 + 1);
740 }
741 }
742 }
743
744 nl10->pos_x += (nl10->gfx_count & 1) ? 2 : 3;
745 nl10->gfx_count++;
746 break;
747 }
748 }
749 } else {
750 switch (nl10->gfx_mode) {
751 case NL10_GFX_SINGLE:
752 {
753 /* 480 dots per line */
754
755 for (j = 0; j < 8; j++) {
756 if (c & (1 << (7 - j))) {
757 draw_point3(nl10, nl10->pos_x, j * 4 + 1);
758 }
759 }
760
761 nl10->pos_x += 5;
762 break;
763 }
764
765 case NL10_GFX_PLOT:
766 {
767 /* 576 dots per line */
768
769 /* 0123456789012345678901234 */
770 /* *#** *#* *#* *#* *#* *#* */
771
772 for (j = 0; j < 8; j++) {
773 if (c & (1 << (7 - j))) {
774 draw_point3(nl10, nl10->pos_x, j * 4 + 1);
775 if (!(nl10->gfx_count % 6)) {
776 draw_point3(nl10, nl10->pos_x + 1, j * 4 + 1);
777 }
778 }
779 }
780
781 nl10->pos_x += (nl10->gfx_count % 6) ? 4 : 5;
782 break;
783 }
784
785 case NL10_GFX_CRT:
786 {
787 /* 640 dots per line */
788
789 /* 012345678901234 */
790 /* #* *#* *#* *#* */
791
792 for (j = 0; j < 8; j++) {
793 if (c & (1 << (7 - j))) {
794 if ((nl10->gfx_count % 4) == 3) {
795 draw_point2(nl10, nl10->pos_x, j * 4 + 1);
796 } else {
797 draw_point3(nl10, nl10->pos_x, j * 4 + 1);
798 }
799 }
800 }
801
802 nl10->pos_x += (nl10->gfx_count % 4) ? 4 : 3;
803 break;
804 }
805
806 case NL10_GFX_CRT2:
807 {
808 /* 720 dots per line */
809
810 /* 0123456789 */
811 /* #* *#* #* */
812
813 for (j = 0; j < 8; j++) {
814 if (c & (1 << (7 - j))) {
815 if ((nl10->gfx_count % 3) == 2) {
816 draw_point3(nl10, nl10->pos_x, j * 4 + 1);
817 } else {
818 draw_point2(nl10, nl10->pos_x, j * 4 + 1);
819 }
820 }
821 }
822
823 nl10->pos_x += (nl10->gfx_count % 3) ? 3 : 4;
824 break;
825 }
826
827 case NL10_GFX_DOUBLE:
828 {
829 /* 960 dots per line */
830
831 /* 01234 */
832 /* #**#* */
833
834 for (j = 0; j < 8; j++) {
835 if (c & (1 << (7 - j))) {
836 if (nl10->gfx_count & 1) {
837 draw_point3(nl10, nl10->pos_x, j * 4 + 1);
838 } else {
839 draw_point2(nl10, nl10->pos_x, j * 4 + 1);
840 }
841 }
842 }
843
844 nl10->pos_x += (nl10->gfx_count & 1) ? 2 : 3;
845 break;
846 }
847
848 case NL10_GFX_QUAD:
849 {
850 /* 1920 dots per line */
851
852 /* 01234 */
853 /* #* */
854 /* *#* */
855 /* *#* */
856 /* *#* */
857
858 for (j = 0; j < 8; j++) {
859 if (c & (1 << (7 - j))) {
860 if ((nl10->gfx_count % 4) == 0) {
861 draw_point2(nl10, nl10->pos_x, j * 4 + 1);
862 } else {
863 draw_point3(nl10, nl10->pos_x, j * 4 + 1);
864 }
865 }
866 }
867
868 nl10->pos_x += (nl10->gfx_count % 4) ? 1 : 2;
869 break;
870 }
871 }
872 }
873 }
874
875
print_char(nl10_t * nl10,unsigned int prnr,const uint8_t c)876 static void print_char(nl10_t *nl10, unsigned int prnr, const uint8_t c)
877 {
878 /* handle dot-graphics pringing */
879 if (nl10->gfx_mode != NL10_GFX_OFF) {
880 if (nl10->gfx_mode & NL10_GFX_7PIN) {
881 /* 7-pin (CBM) mode */
882 if ((nl10->esc_ctr == 0) && (c & 0x80)) {
883 draw_graphics(nl10, c);
884 return;
885 }
886 } else {
887 /* 8-pin (epson) mode */
888 draw_graphics(nl10, c);
889 nl10->gfx_count--;
890 if (nl10->gfx_count == 0) {
891 nl10->gfx_mode = NL10_GFX_OFF;
892 }
893 return;
894 }
895 }
896
897 /* handle CBM quoted-mode (print description strings for control characters,
898 e.g. print "(rvs)" for character 0x12) */
899 if (is_mode(nl10, NL10_QUOTED)) {
900 uint16_t i = 0;
901
902 /* find pointer to description string in ROM */
903 if ((c >= 0x01) && (c < 0x20) && (c != 0x0d)) {
904 i = ((drv_nl10_rom[0x428e + (c - 0x01) * 2] & 0x7f) << 8) + drv_nl10_rom[0x428f + (c - 0x01) * 2];
905 } else if ((c >= 0x80) && (c < 0xa0)) {
906 i = ((drv_nl10_rom[0x42cc + (c - 0x80) * 2] & 0x7f) << 8) + drv_nl10_rom[0x42cd + (c - 0x80) * 2];
907 }
908
909 if (i) {
910 /* if found, read and print description string from ROM
911 (terminated by 0xff) */
912 while ((i < NL10_ROM_SIZE) && (drv_nl10_rom[i] != 0xff)) {
913 print_char(nl10, prnr, drv_nl10_rom[i++]);
914 }
915 return;
916 }
917 }
918
919 /* ensure that top margin is honored */
920 while (nl10->line_nr <= nl10->marg_t) {
921 linefeed(nl10, prnr);
922 }
923
924 /* ensure that left margin is honored */
925 if (nl10->pos_x < nl10->marg_l) {
926 nl10->pos_x = nl10->marg_l;
927 }
928
929 /* ensure that right margin is honored */
930 if ((nl10->pos_x + get_char_width(nl10, c, 0)) > nl10->marg_r) {
931 linefeed(nl10, prnr);
932 nl10->pos_x = nl10->marg_l;
933 nl10->col_nr = 0;
934 }
935
936 /* ensure that bottom margin is honored */
937 if (nl10->marg_b > 0 && nl10->line_nr > ((MAX_ROW - 2 * BORDERY) / (nl10->linespace * 4 / 3) - nl10->marg_b)) {
938 formfeed(nl10, prnr);
939 }
940
941 /* check if character is part of a control sequence and, if so, process it there.
942 Otherwise draw the character. */
943 if (!handle_control_sequence(nl10, prnr, c)) {
944 if (c == '"') {
945 if (is_mode(nl10, NL10_QUOTED)) {
946 del_mode(nl10, NL10_QUOTED);
947 } else {
948 set_mode(nl10, NL10_QUOTED);
949 }
950 }
951
952 draw_char(nl10, c);
953 nl10->col_nr++;
954 }
955
956 /*printf("modes: esc=%i mode=%i gfx_mode=%i gfx_ctr=%i ls=%i px=%i\n", nl10->esc_ctr, nl10->mode, nl10->gfx_mode, nl10->gfx_count, nl10->linespace, nl10->pos_x);*/
957 }
958
959
handle_control_sequence(nl10_t * nl10,unsigned int prnr,const uint8_t c)960 static int handle_control_sequence(nl10_t *nl10, unsigned int prnr, const uint8_t c)
961 {
962 if (nl10->esc_ctr >= NL10_ESCBUF_SIZE) {
963 /* We should never get here. If we do then there is a bug
964 in the ESC handling routine */
965 log_warning(drvnl10_log, "ESC counter overflow");
966 nl10->esc_ctr = 0;
967 }
968
969 nl10->esc[nl10->esc_ctr] = c;
970 switch (nl10->esc[0]) {
971 case 0:
972 break;
973
974 case 7:
975 /* beep (NOT IMPLEMENTED) */
976 break;
977
978 case 8:
979 {
980 if (is_mode(nl10, NL10_ASCII)) {
981 /* ASCII: step back */
982 nl10->pos_x -= (int) get_char_width(nl10, ' ', 1);
983 } else {
984 /* CBM: set single density graphics and line spacing 7/72" */
985 nl10->gfx_mode = NL10_GFX_SINGLE | NL10_GFX_7PIN;
986 nl10->linespace = 3 * 7;
987 }
988 break;
989 }
990
991 case 9:
992 {
993 if (is_mode(nl10, NL10_ASCII)) {
994 /* ASCII: horizontal tab */
995 int i;
996 double w = get_char_width(nl10, ' ', 1);
997 for (i = 0; nl10->htabs[i] > 0; i++)
998 {
999 int p = nl10->marg_l + (int) (w * nl10->htabs[i]);
1000 if ((nl10->pos_x < p) && (p < nl10->marg_r)) {
1001 nl10->pos_x = p;
1002 break;
1003 }
1004 }
1005 } else {
1006 /* CBM: set double density graphics and line spacing 7/72" */
1007 nl10->gfx_mode = NL10_GFX_DOUBLE | NL10_GFX_7PIN;
1008 nl10->linespace = 3 * 7;
1009 }
1010
1011 break;
1012 }
1013
1014 case 10:
1015 /* linefeed */
1016 linefeed(nl10, prnr);
1017 break;
1018
1019 case 11:
1020 {
1021 /* advance to next vertical tab position */
1022 int i = 0;
1023 while ((nl10->line_nr >= nl10->vtabs[i]) && (i == 0 || (nl10->vtabs[i] > nl10->vtabs[i - 1]))) {
1024 i++;
1025 }
1026
1027 if ((nl10->vtabs[i] <= nl10->vtabs[i - 1])) {
1028 /* we're past the last tab. go to top of next page */
1029 formfeed(nl10, prnr);
1030
1031 /* find the first tab greater than the top margin */
1032 i = 0;
1033 while ((nl10->marg_t >= nl10->vtabs[i]) && (i == 0 || (nl10->vtabs[i] > nl10->vtabs[i - 1]))) {
1034 i++;
1035 }
1036
1037 if (nl10->vtabs[i] <= nl10->vtabs[i - 1]) {
1038 /* past the last tab again => there is no valid tab */
1039 i = -1;
1040 }
1041 }
1042
1043 if (i >= 0) {
1044 while (nl10->line_nr < nl10->vtabs[i]) {
1045 linefeed(nl10, prnr);
1046 }
1047 }
1048 break;
1049 }
1050
1051 case 12:
1052 /* formfeed */
1053 formfeed(nl10, prnr);
1054 break;
1055
1056 case 13:
1057 /* carriage return */
1058 linefeed(nl10, prnr);
1059 del_mode(nl10, NL10_QUOTED | NL10_EXPANDED_LINE);
1060 nl10->pos_x = nl10->marg_l;
1061 nl10->col_nr = 0;
1062 break;
1063
1064 case 14:
1065 {
1066 if (is_mode(nl10, NL10_ASCII)) {
1067 /* ASCII: turn on expanded print for current line */
1068 set_mode(nl10, NL10_EXPANDED_LINE);
1069 } else {
1070 /* CBM: turn on expanded print (and turn off graphics printing) */
1071 set_mode(nl10, NL10_EXPANDED);
1072
1073 if (nl10->gfx_mode & NL10_GFX_7PIN) {
1074 nl10->gfx_mode = NL10_GFX_OFF;
1075 nl10->linespace = 12 * 3;
1076 }
1077 }
1078
1079 break;
1080 }
1081
1082 case 15:
1083 {
1084 if (is_mode(nl10, NL10_ASCII)) {
1085 /* ASCII: turn on condensed print */
1086 set_mode(nl10, NL10_CONDENSED);
1087 } else {
1088 /* CBM: turn off expanded print (and turn off graphics printing) */
1089 del_mode(nl10, NL10_EXPANDED);
1090
1091 if (nl10->gfx_mode & NL10_GFX_7PIN) {
1092 nl10->gfx_mode = NL10_GFX_OFF;
1093 nl10->linespace = 12 * 3;
1094 }
1095 }
1096
1097 break;
1098 }
1099
1100 case 16:
1101 {
1102 /* skip to horizontal print position */
1103 if (nl10->esc_ctr < 2) {
1104 nl10->esc_ctr++;
1105 } else {
1106 int i = 0;
1107 if ((nl10->esc[1] >= '0') && (nl10->esc[1] <= '9')) {
1108 i += 10 * (nl10->esc[1] - '0');
1109 }
1110 if ((nl10->esc[2] >= '0') && (nl10->esc[2] <= '9')) {
1111 i += 1 * (nl10->esc[2] - '0');
1112 }
1113 if (i > 79) {
1114 i = 79;
1115 }
1116 nl10->pos_x = BORDERX + 30 * i;
1117 nl10->esc_ctr = 0;
1118 }
1119 break;
1120 }
1121
1122 case 17:
1123 set_mode(nl10, NL10_CBMTEXT);
1124 init_mapping(nl10, nl10->mapping_intl_id);
1125 break;
1126
1127 case 18:
1128 {
1129 if (is_mode(nl10, NL10_ASCII)) {
1130 /* ASCII: Set 'elite' print mode */
1131 del_mode(nl10, NL10_ELITE);
1132 } else {
1133 /* CBM: Enable reverse print */
1134 set_mode(nl10, NL10_REVERSE);
1135 }
1136 break;
1137 }
1138
1139 case 19:
1140 {
1141 if (!is_mode(nl10, NL10_ASCII)) {
1142 /* clear top/bottom margins (only CMD mode) */
1143 nl10->marg_t = 0;
1144 nl10->marg_b = 0;
1145 }
1146 break;
1147 }
1148
1149 case 20:
1150 {
1151 if (is_mode(nl10, NL10_ASCII)) {
1152 set_mode(nl10, NL10_EXPANDED | NL10_EXPANDED_LINE);
1153 }
1154 break;
1155 }
1156
1157 case 26:
1158 {
1159 if (nl10->esc_ctr < 2) {
1160 nl10->esc_ctr++;
1161 } else {
1162 int i;
1163 if ((nl10->gfx_mode & NL10_GFX_7PIN) && (nl10->esc[2] & 0x80)) {
1164 for (i = 0; i < nl10->esc[1]; i++) {
1165 draw_graphics(nl10, nl10->esc[2]);
1166 }
1167 }
1168 nl10->esc_ctr = 0;
1169 }
1170 break;
1171 }
1172
1173 case 27:
1174 {
1175 /* ESC sequence */
1176 if (nl10->esc_ctr < 1) {
1177 nl10->esc_ctr++;
1178 } else {
1179 return handle_esc_control_sequence(nl10, prnr, c);
1180 }
1181 break;
1182 }
1183
1184 case 145:
1185 /* enable CBM text character mode */
1186 del_mode(nl10, NL10_CBMTEXT);
1187 init_mapping(nl10, nl10->mapping_intl_id);
1188 break;
1189
1190 case 146:
1191 /* disable reverse printing */
1192 del_mode(nl10, NL10_REVERSE);
1193 break;
1194
1195 case 147:
1196 {
1197 if (!is_mode(nl10, NL10_ASCII)) {
1198 nl10->marg_b = 6;
1199 }
1200 break;
1201 }
1202
1203 default:
1204 return 0;
1205 }
1206
1207 return 1;
1208 }
1209
1210
handle_esc_control_sequence(nl10_t * nl10,unsigned int prnr,const uint8_t c)1211 static int handle_esc_control_sequence(nl10_t *nl10, unsigned int prnr, const uint8_t c)
1212 {
1213 switch (nl10->esc[1]) {
1214 case 10:
1215 {
1216 /* reverse paper one line (NOT IMPLEMENTED) */
1217 log_warning(drvnl10_log, "Command 'reverse paper one line' (%i %i) not implemented.",
1218 nl10->esc[0], nl10->esc[1]);
1219 nl10->esc_ctr = 0;
1220 break;
1221 }
1222
1223 case 12:
1224 {
1225 /* reverse paper to top of page (NOT IMPLEMENTED) */
1226 log_warning(drvnl10_log, "Command 'reverse paper to top of page' (%i %i) not implemented.",
1227 nl10->esc[0], nl10->esc[1]);
1228 nl10->esc_ctr = 0;
1229 break;
1230 }
1231
1232 case 15:
1233 /* enable expanded print */
1234 set_mode(nl10, NL10_EXPANDED);
1235 break;
1236
1237 case 16:
1238 {
1239 /* skip to horizontal point position */
1240 if (nl10->esc_ctr < 3) {
1241 nl10->esc_ctr++;
1242 } else {
1243 int i = 256 * nl10->esc[2] + nl10->esc[3];
1244 if (i > 479) {
1245 i = 479;
1246 }
1247 nl10->pos_x = BORDERX + 5 * i;
1248 nl10->esc_ctr = 0;
1249 }
1250 break;
1251 }
1252
1253 case 18:
1254 {
1255 /* CBM: enable single-density reverse graphics printing */
1256 if (!is_mode(nl10, NL10_ASCII)) {
1257 nl10->gfx_mode = NL10_GFX_SINGLE | NL10_GFX_REVERSE | NL10_GFX_7PIN;
1258 }
1259 nl10->esc_ctr = 0;
1260 break;
1261 }
1262
1263 case 25:
1264 {
1265 /* auto-feed mode control (NOT IMPLEMENTED) */
1266 if (nl10->esc_ctr < 2) {
1267 nl10->esc_ctr++;
1268 } else {
1269 log_warning(drvnl10_log, "Command 'auto-feed mode control' (%i %i %i) not implemented.",
1270 nl10->esc[0], nl10->esc[1], nl10->esc[2]);
1271 nl10->esc_ctr = 0;
1272 }
1273 break;
1274 }
1275
1276 case 33:
1277 {
1278 /* master command for print style changes */
1279 if (nl10->esc_ctr < 2) {
1280 nl10->esc_ctr++;
1281 } else {
1282 del_mode(nl10, NL10_ELITE | NL10_CONDENSED | NL10_EXPANDED | NL10_UNDERLINE);
1283 if (nl10->esc[2] & 1) {
1284 set_mode(nl10, NL10_ELITE);
1285 }
1286 if (nl10->esc[2] & 2) {
1287 set_mode(nl10, NL10_PROP);
1288 }
1289 if (nl10->esc[2] & 4) {
1290 set_mode(nl10, NL10_CONDENSED);
1291 }
1292 if (nl10->esc[2] & 8) {
1293 set_mode(nl10, NL10_EMPHASIZE);
1294 }
1295 if (nl10->esc[2] & 16) {
1296 set_mode(nl10, NL10_BOLD);
1297 }
1298 if (nl10->esc[2] & 32) {
1299 set_mode(nl10, NL10_EXPANDED);
1300 }
1301 if (nl10->esc[2] & 128) {
1302 set_mode(nl10, NL10_UNDERLINE);
1303 }
1304 nl10->esc_ctr = 0;
1305 }
1306 break;
1307 }
1308
1309 case 37:
1310 {
1311 /* enable/disable use of character RAM */
1312 if (nl10->esc_ctr < 3) {
1313 nl10->esc_ctr++;
1314 } else {
1315 if ((nl10->esc[2] == '1' || nl10->esc[2] == 1) && nl10->esc[3] == 0) {
1316 set_mode(nl10, NL10_USERAM);
1317 } else if ((nl10->esc[2] == '0' || nl10->esc[2] == 0) && nl10->esc[3] == 0) {
1318 del_mode(nl10, NL10_USERAM);
1319 }
1320
1321 nl10->esc_ctr = 0;
1322 }
1323 break;
1324 }
1325
1326 case 38:
1327 {
1328 /* download new character data to RAM */
1329 if (nl10->esc_ctr < 4 ||
1330 nl10->esc_ctr < 4 + (is_mode(nl10, NL10_NLQ) ? 47 : 12)) {
1331 nl10->esc_ctr++;
1332 } else {
1333 int i;
1334
1335 i = nl10->esc[3];
1336 if ((i >= 32) && (i <= 127)) {
1337 if (is_mode(nl10, NL10_NLQ)) {
1338 store_char_nlq(nl10->char_ram_nlq + (i - 32) * 47, nl10->esc + 5);
1339 } else {
1340 store_char(nl10->char_ram + (i - 32) * 12, nl10->esc + 5);
1341 }
1342 }
1343
1344 nl10->esc[3]++;
1345 nl10->esc_ctr = (nl10->esc[3] <= nl10->esc[4]) ? 5 : 0;
1346 }
1347
1348 break;
1349 }
1350
1351 case 42:
1352 {
1353 /* enter graphics mode */
1354 if (nl10->esc_ctr < 4) {
1355 nl10->esc_ctr++;
1356 } else {
1357 nl10->gfx_mode = NL10_GFX_OFF;
1358 switch (nl10->esc[2]) {
1359 case 0:
1360 nl10->gfx_mode = NL10_GFX_SINGLE;
1361 break;
1362 case 1:
1363 case 2:
1364 nl10->gfx_mode = NL10_GFX_DOUBLE;
1365 break;
1366 case 3:
1367 nl10->gfx_mode = NL10_GFX_QUAD;
1368 break;
1369 case 4:
1370 nl10->gfx_mode = NL10_GFX_CRT; break;
1371 case 5:
1372 nl10->gfx_mode = NL10_GFX_PLOT;
1373 break;
1374 case 6:
1375 nl10->gfx_mode = NL10_GFX_CRT2;
1376 break;
1377 }
1378
1379 nl10->gfx_count = nl10->esc[3] + 256 * nl10->esc[4];
1380 nl10->esc_ctr = 0;
1381 }
1382 break;
1383 }
1384
1385 case 43:
1386 {
1387 /* macro commands */
1388 if (nl10->esc_ctr < 3) {
1389 nl10->esc_ctr++;
1390 } else if (nl10->esc[2] == 1) {
1391 /* execute macro */
1392 uint8_t i;
1393 for (i = 0; i < 16; i++) {
1394 if (nl10->macro[i] == 30) {
1395 break;
1396 } else {
1397 print_char(nl10, prnr, nl10->macro[i]);
1398 }
1399 }
1400 nl10->esc_ctr = 0;
1401 } else if (nl10->esc_ctr < 2 + 16 && nl10->esc[nl10->esc_ctr] != 30) {
1402 nl10->esc_ctr++;
1403 } else {
1404 /* define macro */
1405 uint8_t i;
1406 for (i = 0; i < 16; i++) {
1407 nl10->macro[i] = nl10->esc[2 + i];
1408 }
1409 nl10->esc_ctr = 0;
1410 }
1411
1412 break;
1413 }
1414
1415 case 45:
1416 {
1417 /* turn underline on/off */
1418 if (nl10->esc_ctr < 2) {
1419 nl10->esc_ctr++;
1420 } else {
1421 if ((nl10->esc[2] == '0') || (nl10->esc[2] == 0)) {
1422 del_mode(nl10, NL10_UNDERLINE);
1423 } else if ((nl10->esc[2] == '1') || (nl10->esc[2] == 1)) {
1424 set_mode(nl10, NL10_UNDERLINE);
1425 }
1426
1427 nl10->esc_ctr = 0;
1428 }
1429 break;
1430 }
1431
1432 case 48:
1433 /* line spacing 1/8" */
1434 nl10->linespace = 3 * 9;
1435 nl10->esc_ctr = 0;
1436 break;
1437
1438 case 49:
1439 /* line spacing 7/72" */
1440 nl10->linespace = 3 * 7;
1441 nl10->esc_ctr = 0;
1442 break;
1443
1444 case 50:
1445 /* line spacing 1/6" */
1446 nl10->linespace = 3 * 12;
1447 nl10->esc_ctr = 0;
1448 break;
1449
1450 case 51:
1451 {
1452 /* set line spacing to n/216" */
1453 if (nl10->esc_ctr < 2) {
1454 nl10->esc_ctr++;
1455 } else {
1456 nl10->linespace = nl10->esc[2];
1457 nl10->esc_ctr = 0;
1458 }
1459 break;
1460 }
1461
1462 case 52:
1463 /* Selects italic characters */
1464 set_mode(nl10, NL10_ITALIC);
1465 nl10->esc_ctr = 0;
1466 break;
1467
1468 case 53:
1469 /* Cancels italic characters */
1470 del_mode(nl10, NL10_ITALIC);
1471 nl10->esc_ctr = 0;
1472 break;
1473
1474 case 58:
1475 {
1476 /* copy character set to RAM */
1477 if (nl10->esc_ctr < 4) {
1478 nl10->esc_ctr++;
1479 } else {
1480 if (nl10->esc[2] == 0 && nl10->esc[3] == 0 && nl10->esc[4] == 0) {
1481 int b;
1482 for (b = 0; b < 96; b++) {
1483 memcpy(nl10->char_ram + b * 12, drv_nl10_charset + nl10->mapping[b + 32] * 12, 12);
1484 memcpy(nl10->char_ram_nlq + b * 47, drv_nl10_charset_nlq + nl10->mapping[b + 32] * 47, 47);
1485 }
1486 }
1487 nl10->esc_ctr = 0;
1488 }
1489
1490 break;
1491 }
1492
1493 case 64:
1494 /* (Soft) Reset printer */
1495 reset(nl10);
1496 nl10->esc_ctr = 0;
1497 break;
1498
1499 case 65:
1500 {
1501 /* line spacing n/72" */
1502 if (nl10->esc_ctr < 2) {
1503 nl10->esc_ctr++;
1504 } else {
1505 nl10->linespace = 3 * nl10->esc[2];
1506 nl10->esc_ctr = 0;
1507 }
1508 break;
1509 }
1510
1511 case 66:
1512 {
1513 /* set vertical tabs */
1514 if (nl10->esc_ctr < 3 || (nl10->esc_ctr < 42 && (nl10->esc[nl10->esc_ctr] > nl10->esc[nl10->esc_ctr - 1]))) {
1515 nl10->esc_ctr++;
1516 } else {
1517 int i;
1518 for (i = 2; i < nl10->esc_ctr; i++) {
1519 nl10->vtabs[i - 2] = nl10->esc[i];
1520 }
1521 nl10->vtabs[i - 2] = 0;
1522 nl10->esc_ctr = 0;
1523 }
1524 break;
1525 }
1526
1527 case 67:
1528 {
1529 /* set page length */
1530 if (nl10->esc_ctr < 2 || ((nl10->esc[2] == 0) && nl10->esc_ctr < 3)) {
1531 nl10->esc_ctr++;
1532 } else {
1533 if (nl10->esc[2] == 0) {
1534 /* set page length to n inches (NOT IMPLEMENTED) */
1535 log_warning(drvnl10_log, "Command 'set page length to n inches' (%i %i %i %i) not implemented.",
1536 nl10->esc[0], nl10->esc[1], nl10->esc[2], nl10->esc[3]);
1537 nl10->esc_ctr = 0;
1538 } else {
1539 /* set page length to n lines (NOT IMPLEMENTED) */
1540 log_warning(drvnl10_log, "Command 'set page length to n lines' (%i %i %i) not implemented.",
1541 nl10->esc[0], nl10->esc[1], nl10->esc[2]);
1542 nl10->esc_ctr = 0;
1543 }
1544 }
1545 break;
1546 }
1547
1548 case 68:
1549 {
1550 /* set horizontal tabs */
1551 if (nl10->esc_ctr < 3 || (nl10->esc_ctr < 42 && (nl10->esc[nl10->esc_ctr] > nl10->esc[nl10->esc_ctr - 1]))) {
1552 nl10->esc_ctr++;
1553 } else {
1554 int i;
1555 for (i = 2; i < nl10->esc_ctr; i++) {
1556 nl10->htabs[i - 2] = nl10->esc[i];
1557 }
1558 nl10->htabs[i - 2] = 0;
1559 nl10->esc_ctr = 0;
1560 }
1561 break;
1562 }
1563
1564 case 69:
1565 /* Selects emphasized printing */
1566 set_mode(nl10, NL10_EMPHASIZE);
1567 nl10->esc_ctr = 0;
1568 break;
1569
1570 case 70:
1571 /* Cancels emphasized printing */
1572 del_mode(nl10, NL10_EMPHASIZE);
1573 nl10->esc_ctr = 0;
1574 break;
1575
1576 case 71:
1577 /* Selects boldface printing */
1578 set_mode(nl10, NL10_BOLD);
1579 nl10->esc_ctr = 0;
1580 break;
1581
1582 case 72:
1583 /* Cancels boldface printing */
1584 del_mode(nl10, NL10_BOLD);
1585 nl10->esc_ctr = 0;
1586 break;
1587
1588 case 74:
1589 {
1590 /* one-time linefeed of n/216" */
1591 if (nl10->esc_ctr < 2) {
1592 nl10->esc_ctr++;
1593 } else {
1594 int tmp = nl10->linespace;
1595 nl10->linespace = nl10->esc[2];
1596 linefeed(nl10, prnr);
1597 nl10->linespace = tmp;
1598 nl10->esc_ctr = 0;
1599 }
1600 break;
1601 }
1602
1603 case 75: /* Prints normal density graphics */
1604 case 76: /* Prints double density graphics */
1605 case 89: /* Prints double density graphics (double speed) */
1606 case 90: /* Prints quadruple density graphics */
1607 {
1608 if (nl10->esc_ctr < 3) {
1609 nl10->esc_ctr++;
1610 } else {
1611 nl10->gfx_mode = NL10_GFX_OFF;
1612 switch (nl10->esc[1]) {
1613 case 'K':
1614 nl10->gfx_mode = NL10_GFX_SINGLE;
1615 break;
1616 case 'L':
1617 case 'Y':
1618 nl10->gfx_mode = NL10_GFX_DOUBLE;
1619 break;
1620 case 'Z':
1621 nl10->gfx_mode = NL10_GFX_QUAD;
1622 break;
1623 }
1624
1625 nl10->gfx_count = nl10->esc[2] + 256 * nl10->esc[3];
1626 nl10->esc_ctr = 0;
1627 }
1628 break;
1629 }
1630
1631 case 77:
1632 /* Sets print pitch to elite */
1633 set_mode(nl10, NL10_ELITE);
1634 nl10->esc_ctr = 0;
1635 break;
1636
1637 case 78:
1638 {
1639 /* set bottom margin to n lines */
1640 if (nl10->esc_ctr < 2) {
1641 nl10->esc_ctr++;
1642 } else {
1643 nl10->marg_b = nl10->esc[2];
1644 nl10->esc_ctr = 0;
1645 }
1646 break;
1647 }
1648
1649 case 79:
1650 /* clear top/bottom margins */
1651 nl10->marg_t = 0;
1652 nl10->marg_b = 0;
1653 nl10->esc_ctr = 0;
1654 break;
1655
1656 case 80:
1657 /* Set print pitch to pica */
1658 del_mode(nl10, NL10_ELITE);
1659 nl10->esc_ctr = 0;
1660 break;
1661
1662 case 81:
1663 {
1664 /* Set right margin */
1665 if (nl10->esc_ctr < 2) {
1666 nl10->esc_ctr++;
1667 } else {
1668 nl10->marg_r = BORDERX + (int) (get_char_width(nl10, ' ', 1) * nl10->esc[2]);
1669 if (nl10->marg_r > MAX_COL - BORDERX) {
1670 nl10->marg_r = MAX_COL - BORDERX;
1671 }
1672 nl10->esc_ctr = 0;
1673 }
1674 break;
1675 }
1676
1677 case 82:
1678 {
1679 /* Select an international character set */
1680 if (nl10->esc_ctr < 2) {
1681 nl10->esc_ctr++;
1682 } else {
1683 init_mapping(nl10, nl10->esc[2]);
1684 nl10->esc_ctr = 0;
1685 }
1686 break;
1687 }
1688
1689 case 83:
1690 {
1691 /* Select superscript or subscript */
1692 if (nl10->esc_ctr < 2) {
1693 nl10->esc_ctr++;
1694 } else {
1695 if ((nl10->esc[2] == '0') || (nl10->esc[2] == 0)) {
1696 del_mode(nl10, NL10_SUBSCRIPT);
1697 set_mode(nl10, NL10_SUPERSCRIPT);
1698 } else if ((nl10->esc[2] == '1') || (nl10->esc[2] == 1)) {
1699 set_mode(nl10, NL10_SUBSCRIPT);
1700 del_mode(nl10, NL10_SUPERSCRIPT);
1701 }
1702
1703 nl10->esc_ctr = 0;
1704 }
1705 break;
1706 }
1707
1708 case 84:
1709 {
1710 /* Cancel superscript and subscript */
1711 del_mode(nl10, NL10_SUPERSCRIPT | NL10_SUBSCRIPT);
1712 nl10->esc_ctr = 0;
1713 break;
1714 }
1715
1716 case 87:
1717 {
1718 /* Select/cancel expanded print */
1719 if (nl10->esc_ctr < 2) {
1720 nl10->esc_ctr++;
1721 } else {
1722 if ((nl10->esc[2] == '0') || (nl10->esc[2] == 0)) {
1723 del_mode(nl10, NL10_EXPANDED);
1724 } else if ((nl10->esc[2] == '1') || (nl10->esc[2] == 1)) {
1725 set_mode(nl10, NL10_EXPANDED);
1726 }
1727
1728 nl10->esc_ctr = 0;
1729 }
1730 break;
1731 }
1732
1733 case 93:
1734 {
1735 /* 0=CBM mode, 1=ASCII mode */
1736 if (nl10->esc_ctr < 2) {
1737 nl10->esc_ctr++;
1738 } else {
1739 if ((nl10->esc[2] == '0') || (nl10->esc[2] == 0)) {
1740 del_mode(nl10, NL10_ASCII);
1741 } else if ((nl10->esc[2] == '1') || (nl10->esc[2] == 1)) {
1742 set_mode(nl10, NL10_ASCII);
1743 }
1744
1745 init_mapping(nl10, nl10->mapping_intl_id);
1746 nl10->esc_ctr = 0;
1747 }
1748 break;
1749 }
1750
1751 case 97:
1752 {
1753 /* set horizontal alignment (NOT IMPLEMENTED) */
1754 if (nl10->esc_ctr < 2) {
1755 nl10->esc_ctr++;
1756 } else {
1757 log_warning(drvnl10_log, "Command 'set horizontal alignment' (%i %i %i) not implemented.",
1758 nl10->esc[0], nl10->esc[1], nl10->esc[2]);
1759 nl10->esc_ctr = 0;
1760 }
1761 break;
1762 }
1763
1764 case 104:
1765 {
1766 /* Select double/quadruple sized printing */
1767 if (nl10->esc_ctr < 2) {
1768 nl10->esc_ctr++;
1769 } else {
1770 switch (nl10->esc[2]) {
1771 case 0:
1772 nl10->expand = 1;
1773 nl10->expand_half = 0;
1774 break;
1775 case 1:
1776 nl10->expand = 2;
1777 nl10->expand_half = 0;
1778 break;
1779 case 2:
1780 nl10->expand = 4;
1781 nl10->expand_half = 0;
1782 break;
1783 case 3:
1784 nl10->expand = 2;
1785 nl10->expand_half = 1;
1786 break;
1787 case 4:
1788 nl10->expand = 4;
1789 nl10->expand_half = 1;
1790 break;
1791 case 5:
1792 nl10->expand = 2;
1793 nl10->expand_half = 2;
1794 break;
1795 case 6:
1796 nl10->expand = 4;
1797 nl10->expand_half = 2;
1798 break;
1799 }
1800 nl10->esc_ctr = 0;
1801 }
1802 break;
1803 }
1804
1805 case 108:
1806 {
1807 /* Set left margin */
1808 if (nl10->esc_ctr < 2) {
1809 nl10->esc_ctr++;
1810 } else {
1811 nl10->marg_l = BORDERX + (int) (get_char_width(nl10, ' ', 1) * nl10->esc[2]);
1812 nl10->esc_ctr = 0;
1813 }
1814 break;
1815 }
1816
1817 case 112:
1818 {
1819 /* Select/cancel proportional print */
1820 if (nl10->esc_ctr < 2) {
1821 nl10->esc_ctr++;
1822 } else {
1823 if ((nl10->esc[2] == '0') || (nl10->esc[2] == 0)) {
1824 del_mode(nl10, NL10_PROP);
1825 } else if ((nl10->esc[2] == '1') || (nl10->esc[2] == 1)) {
1826 set_mode(nl10, NL10_PROP);
1827 }
1828
1829 nl10->esc_ctr = 0;
1830 }
1831 break;
1832 }
1833
1834 case 114:
1835 {
1836 /* set top margin to n lines */
1837 if (nl10->esc_ctr < 2) {
1838 nl10->esc_ctr++;
1839 } else {
1840 nl10->marg_t = nl10->esc[2];
1841 nl10->esc_ctr = 0;
1842 }
1843 break;
1844 }
1845
1846 case 120:
1847 {
1848 /* Select/cancel NLQ mode */
1849 if (nl10->esc_ctr < 2) {
1850 nl10->esc_ctr++;
1851 } else {
1852 if ((nl10->esc[2] == '0') || (nl10->esc[2] == 0)) {
1853 del_mode(nl10, NL10_NLQ);
1854 } else if ((nl10->esc[2] == '1') || (nl10->esc[2] == 1)) {
1855 set_mode(nl10, NL10_NLQ);
1856 }
1857
1858 nl10->esc_ctr = 0;
1859 }
1860
1861 break;
1862 }
1863
1864 case 126:
1865 {
1866 /* print 0 with/without slash */
1867 if (nl10->esc_ctr < 2) {
1868 nl10->esc_ctr++;
1869 } else {
1870 if ((nl10->esc[2] == '0') || (nl10->esc[2] == 0)) {
1871 del_mode(nl10, NL10_ZERO_CROSSED);
1872 } else if ((nl10->esc[2] == '1') || (nl10->esc[2] == 1)) {
1873 set_mode(nl10, NL10_ZERO_CROSSED);
1874 }
1875
1876 init_mapping(nl10, nl10->mapping_intl_id);
1877 nl10->esc_ctr = 0;
1878 }
1879
1880 break;
1881 }
1882
1883 default:
1884 {
1885 log_warning(drvnl10_log, "Unsupported escape-sequence: %i %i",
1886 nl10->esc[0], nl10->esc[1]);
1887 nl10->esc_ctr = 0;
1888 return 1;
1889 }
1890 }
1891
1892 return 1;
1893 }
1894
1895
1896 /* ------------------------------------------------------------------------- */
1897 /* Interface to the upper layer. */
1898
drv_nl10_open(unsigned int prnr,unsigned int secondary)1899 static int drv_nl10_open(unsigned int prnr, unsigned int secondary)
1900 {
1901 nl10_t *nl10 = &(drv_nl10[prnr]);
1902
1903 if (secondary == DRIVER_FIRST_OPEN) {
1904 output_parameter_t output_parameter;
1905
1906 output_parameter.maxcol = MAX_COL;
1907 output_parameter.maxrow = MAX_ROW;
1908 output_parameter.dpi_x = 300;
1909 output_parameter.dpi_y = 300;
1910 output_parameter.palette = palette;
1911
1912 drv_nl10[prnr].pos_y = 0;
1913 drv_nl10[prnr].pos_y_pix = 0;
1914 drv_nl10[prnr].isopen = 1;
1915
1916 return output_select_open(prnr, &output_parameter);
1917 }
1918
1919 if (secondary == 7) {
1920 set_mode(nl10, NL10_CBMTEXT);
1921 } else {
1922 del_mode(nl10, NL10_CBMTEXT);
1923 }
1924
1925 init_mapping(nl10, drv_nl10[prnr].mapping_intl_id);
1926
1927 return 0;
1928 }
1929
drv_nl10_close(unsigned int prnr,unsigned int secondary)1930 static void drv_nl10_close(unsigned int prnr, unsigned int secondary)
1931 {
1932 /* cannot call output_select_close() here since it would eject the
1933 current page, which is not what "close"ing a channel to a real
1934 printer does */
1935 /*
1936 if (secondary == DRIVER_LAST_CLOSE) {
1937 output_select_close(prnr);
1938 }
1939 */
1940 }
1941
drv_nl10_putc(unsigned int prnr,unsigned int secondary,uint8_t b)1942 static int drv_nl10_putc(unsigned int prnr, unsigned int secondary, uint8_t b)
1943 {
1944 print_char(&drv_nl10[prnr], prnr, b);
1945 return 0;
1946 }
1947
drv_nl10_getc(unsigned int prnr,unsigned int secondary,uint8_t * b)1948 static int drv_nl10_getc(unsigned int prnr, unsigned int secondary, uint8_t *b)
1949 {
1950 return 0x80;
1951 }
1952
drv_nl10_flush(unsigned int prnr,unsigned int secondary)1953 static int drv_nl10_flush(unsigned int prnr, unsigned int secondary)
1954 {
1955 return 0;
1956 }
1957
drv_nl10_formfeed(unsigned int prnr)1958 static int drv_nl10_formfeed(unsigned int prnr)
1959 {
1960 nl10_t *nl10 = &(drv_nl10[prnr]);
1961 if (nl10->isopen) {
1962 formfeed(nl10, prnr);
1963 }
1964 return 0;
1965 }
1966
drv_nl10_init_resources(void)1967 int drv_nl10_init_resources(void)
1968 {
1969 driver_select_t driver_select;
1970
1971 driver_select.drv_name = "nl10";
1972 driver_select.drv_open = drv_nl10_open;
1973 driver_select.drv_close = drv_nl10_close;
1974 driver_select.drv_putc = drv_nl10_putc;
1975 driver_select.drv_getc = drv_nl10_getc;
1976 driver_select.drv_flush = drv_nl10_flush;
1977 driver_select.drv_formfeed = drv_nl10_formfeed;
1978
1979 driver_select_register(&driver_select);
1980
1981 return 0;
1982 }
1983
drv_nl10_init(void)1984 int drv_nl10_init(void)
1985 {
1986 int i;
1987 static const char *color_names[2] =
1988 {
1989 "Black", "White"
1990 };
1991
1992 drvnl10_log = log_open("NL10");
1993
1994 for (i = 0; i < NUM_OUTPUT_SELECT; i++) {
1995 drv_nl10[i].char_ram = lib_malloc(96 * 12);
1996 drv_nl10[i].char_ram_nlq = lib_malloc(96 * 47);
1997 reset_hard(&(drv_nl10[i]));
1998 drv_nl10[i].isopen = 0;
1999 }
2000
2001 if (drv_nl10_init_charset() < 0) {
2002 return -1;
2003 }
2004
2005 palette = palette_create(2, color_names);
2006
2007 if (palette == NULL) {
2008 return -1;
2009 }
2010
2011 if (palette_load("nl10" FSDEV_EXT_SEP_STR "vpl", palette) < 0) {
2012 #ifndef __LIBRETRO__
2013 log_error(drvnl10_log, "Cannot load palette file `%s'.",
2014 "nl10" FSDEV_EXT_SEP_STR "vpl");
2015 #endif
2016 return -1;
2017 }
2018
2019 log_message(drvnl10_log, "Printer driver initialized.");
2020
2021 return 0;
2022 }
2023
drv_nl10_shutdown(void)2024 void drv_nl10_shutdown(void)
2025 {
2026 int i;
2027 palette_free(palette);
2028
2029 for (i = 0; i < NUM_OUTPUT_SELECT; i++) {
2030 if (drv_nl10[i].isopen) {
2031 output_select_close(i);
2032 }
2033
2034 lib_free(drv_nl10[i].char_ram);
2035 lib_free(drv_nl10[i].char_ram_nlq);
2036 }
2037 }
2038
2039
drv_nl10_reset(void)2040 void drv_nl10_reset(void)
2041 {
2042 int i;
2043 for (i = 0; i < NUM_OUTPUT_SELECT; i++) {
2044 reset_hard(&(drv_nl10[i]));
2045 }
2046 }
2047
2048
2049 /* ------------------------------------------------------------------------- */
2050 /* character data and mappings */
2051
2052
2053 static const uint8_t drv_nl10_charset_mapping_intl[3][8][14] =
2054 { /* ASCII */
2055 {
2056 /* # $ @ [ \ ] { | } ~ */
2057 /* 35, 36, 64, 91, 92, 93, 123, 124, 125, 126, 219, 220, 221, 222 */
2058 /* 0x23, 0x24, 0x40, 0x5b, 0x5c, 0x5d, 0x7b, 0x7c, 0x7d, 0x7e, 0xdb, 0xdc, 0xdd, 0xde */
2059
2060 { 0x23, 0x24, 0x40, 0x5b, 0x5c, 0x5d, 0x7b, 0x7c, 0x7d, 0x7e, 0x81, 0x82, 0x83, 0x84}, /* CBM standard */
2061 { 0x23, 0x24, 0x40, 0x5b, 0x5c, 0x5d, 0x7b, 0x7c, 0x7d, 0x7e, 0x7b, 0x7c, 0x7d, 0x7e}, /* USA */
2062 { 0x23, 0x24, 0x10, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x11, 0x1a, 0x1b, 0x1c, 0x11}, /* Germany */
2063 { 0x23, 0x24, 0x40, 0x12, 0x14, 0x0d, 0x13, 0x15, 0x0e, 0x7e, 0x13, 0x15, 0x0e, 0x7e}, /* Denmark */
2064 { 0x23, 0x24, 0x00, 0x05, 0x0f, 0x10, 0x1e, 0x02, 0x01, 0x16, 0x1e, 0x02, 0x01, 0x16}, /* France */
2065 { 0x23, 0x0b, 0x1d, 0x17, 0x18, 0x0d, 0x1a, 0x1b, 0x0e, 0x1c, 0x1a, 0x1b, 0x0e, 0x1c}, /* Sweden */
2066 { 0x23, 0x24, 0x40, 0x05, 0x5c, 0x1e, 0x00, 0x03, 0x01, 0x04, 0x00, 0x03, 0x01, 0x04}, /* Italy */
2067 { 0x0c, 0x24, 0x40, 0x07, 0x09, 0x08, 0x16, 0x0a, 0x7d, 0x7e, 0x16, 0x0a, 0x7d, 0x7e}, /* Spain */
2068 },
2069
2070 /* CBM graphics */
2071 {
2072 { 0x23, 0x24, 0x40, 0x5b, 0x06, 0x5d, 0xa1, 0xa2, 0xa3, 0xa4, 0xa1, 0xa2, 0xa3, 0xa4}, /* CBM standard */
2073 { 0x23, 0x24, 0x40, 0x5b, 0x5c, 0x5d, 0xa1, 0xa2, 0xa3, 0xa4, 0xa1, 0xa2, 0xa3, 0xa4}, /* USA */
2074 { 0x23, 0x24, 0x10, 0x17, 0x18, 0x19, 0xa1, 0xa2, 0xa3, 0xa4, 0xa1, 0xa2, 0xa3, 0xa4}, /* Germany */
2075 { 0x23, 0x24, 0x40, 0x12, 0x14, 0x0d, 0xa1, 0xa2, 0xa3, 0xa4, 0xa1, 0xa2, 0xa3, 0xa4}, /* Denmark */
2076 { 0x23, 0x24, 0x00, 0x05, 0x0f, 0x10, 0xa1, 0xa2, 0xa3, 0xa4, 0xa1, 0xa2, 0xa3, 0xa4}, /* France */
2077 { 0x23, 0x0b, 0x1d, 0x17, 0x18, 0x0d, 0xa1, 0xa2, 0xa3, 0xa4, 0xa1, 0xa2, 0xa3, 0xa4}, /* Sweden */
2078 { 0x23, 0x24, 0x40, 0x05, 0x5c, 0x1e, 0xa1, 0xa2, 0xa3, 0xa4, 0xa1, 0xa2, 0xa3, 0xa4}, /* Italy */
2079 { 0x0c, 0x24, 0x40, 0x07, 0x09, 0x08, 0xa1, 0xa2, 0xa3, 0xa4, 0xa1, 0xa2, 0xa3, 0xa4}, /* Spain */
2080 },
2081
2082 /* CBM text */
2083 {
2084 { 0x23, 0x24, 0x40, 0x5b, 0x06, 0x5d, 0x81, 0x82, 0x83, 0x84, 0x81, 0x82, 0x83, 0x84}, /* CBM standard */
2085 { 0x23, 0x24, 0x40, 0x5b, 0x5c, 0x5d, 0x7b, 0x7c, 0x7d, 0x7e, 0x7b, 0x7c, 0x7d, 0x7e}, /* USA */
2086 { 0x23, 0x24, 0x10, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x11, 0x1a, 0x1b, 0x1c, 0x11}, /* Germany */
2087 { 0x23, 0x24, 0x40, 0x12, 0x14, 0x0d, 0x13, 0x15, 0x0e, 0x7e, 0x13, 0x15, 0x0e, 0x7e}, /* Denmark */
2088 { 0x23, 0x24, 0x00, 0x05, 0x0f, 0x10, 0x1e, 0x02, 0x01, 0x16, 0x1e, 0x02, 0x01, 0x16}, /* France */
2089 { 0x23, 0x0b, 0x1d, 0x17, 0x18, 0x0d, 0x1a, 0x1b, 0x0e, 0x1c, 0x1a, 0x1b, 0x0e, 0x1c}, /* Sweden */
2090 { 0x23, 0x24, 0x40, 0x05, 0x5c, 0x1e, 0x00, 0x03, 0x01, 0x04, 0x00, 0x03, 0x01, 0x04}, /* Italy */
2091 { 0x0c, 0x24, 0x40, 0x07, 0x09, 0x08, 0x16, 0x0a, 0x7d, 0x7e, 0x16, 0x0a, 0x7d, 0x7e}, /* Spain */
2092 }
2093 };
2094
2095
2096 static const uint8_t drv_nl10_charset_mapping[3][256] =
2097 { /* ASCII */
2098 {
2099 /* unprintable */
2100 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
2101 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
2102
2103 /* digits and punctuation */
2104 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
2105 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
2106
2107 /* uppercase characters */
2108 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
2109 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
2110
2111 /* lowercase characters */
2112 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
2113 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x20,
2114
2115 /* unprintable */
2116 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
2117 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
2118
2119 /* cbm graphic symbols */
2120 0x20, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xc7, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5,
2121 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5,
2122
2123 /* uppercase characters */
2124 0x86, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
2125 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x81, 0x82, 0x83, 0x84, 0x85,
2126
2127 /* cbm graphic symbols */
2128 0x20, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xc7, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5,
2129 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0x84
2130 },
2131 /* CBM graphic */
2132 {
2133 /* unprintable */
2134 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
2135 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
2136
2137 /* digits and punctuation */
2138 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
2139 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
2140
2141 /* uppercase characters */
2142 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
2143 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x06, 0x5d, 0x7f, 0x80,
2144
2145 /* shift-graphic symbols */
2146 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95,
2147 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5,
2148
2149 /* unprintable */
2150 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
2151 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
2152
2153 /* cbm-graphic symbols */
2154 0x20, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5,
2155 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5,
2156
2157 /* shift-graphic symbols */
2158 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95,
2159 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5,
2160
2161 /* cbm-graphic symbols */
2162 0x20, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5,
2163 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xa4
2164 },
2165 /* CBM text */
2166 {
2167 /* unprintable */
2168 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
2169 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
2170
2171 /* digits and punctuation */
2172 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
2173 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
2174
2175 /* lowercase characters */
2176 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
2177 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x06, 0x5d, 0x7f, 0x80,
2178
2179 /* uppercase characters */
2180 0x86, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
2181 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x81, 0x82, 0x83, 0x84, 0x85,
2182
2183 /* unprintable */
2184 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
2185 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
2186
2187 /* cbm-graphic symbols */
2188 0x20, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xc7, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5,
2189 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5,
2190
2191 /* uppercase characters */
2192 0x86, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
2193 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x81, 0x82, 0x83, 0x84, 0x85,
2194
2195 /* cbm-graphic symbols */
2196 0x20, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xc7, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5,
2197 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0x84
2198 }
2199 };
2200
2201 /* -------------------------------------------------------------------------- */
2202
drv_nl10_init_charset(void)2203 static int drv_nl10_init_charset(void)
2204 {
2205 char *name = "nl10-cbm";
2206 int i, j;
2207
2208 memset(drv_nl10_charset_nlq, 0, CHARSET_SIZE * 47);
2209 memset(drv_nl10_charset_nlq_italic, 0, CHARSET_SIZE * 47);
2210
2211 /* load nl-10 rom file */
2212 if (sysfile_load(name, drv_nl10_rom, NL10_ROM_SIZE, NL10_ROM_SIZE) < 0) {
2213 memset(drv_nl10_rom, 0, NL10_ROM_SIZE);
2214 log_error(drvnl10_log, "Could not load NL-10 ROM file '%s'.", name);
2215 return -1;
2216 }
2217
2218 /* check version string */
2219 if (memcmp(drv_nl10_rom + 0x3c7c, "STAR NL-10C VER 1.1\xff", 20) != 0) {
2220 log_warning(drvnl10_log, "Invalid NL-10 ROM file.");
2221 }
2222
2223 /* init NLQ characters */
2224 for (i = 0; i < 129; i++) {
2225 /* roman */
2226 memcpy(drv_nl10_charset_nlq + (i * 47) + 0, drv_nl10_rom + 0x0960 + i * 24, 24);
2227 memcpy(drv_nl10_charset_nlq + (i * 47) + 24, drv_nl10_rom + 0x2191 + i * 24, 23);
2228
2229 /* italic */
2230 memcpy(drv_nl10_charset_nlq_italic + (i * 47) + 0, drv_nl10_rom + 0x1578 + i * 24, 24);
2231 memcpy(drv_nl10_charset_nlq_italic + (i * 47) + 24, drv_nl10_rom + 0x2da9 + i * 24, 23);
2232 }
2233
2234 /* construct nlq cbm-graphic characters from draft cbm-graphic characters */
2235 for (i = 129; i < CHARSET_SIZE; i++) {
2236 drv_nl10_charset_nlq[i * 47] = drv_nl10_charset[i * 12] & 128 ? 255 : 0;
2237 drv_nl10_charset_nlq_italic[i * 47] = drv_nl10_charset[i * 12] & 128 ? 255 : 0;
2238
2239 for (j = 0; j < 6; j++) {
2240 uint8_t b = drv_nl10_charset[i * 12 + j * 2 + 1];
2241 drv_nl10_charset_nlq[i * 47 + j * 4 + 1] = b;
2242 drv_nl10_charset_nlq[i * 47 + j * 4 + 3] = b;
2243 drv_nl10_charset_nlq[i * 47 + j * 4 + 24] = b;
2244 drv_nl10_charset_nlq[i * 47 + j * 4 + 26] = b;
2245
2246 drv_nl10_charset_nlq_italic[i * 47 + j * 4 + 1] = b;
2247 drv_nl10_charset_nlq_italic[i * 47 + j * 4 + 3] = b;
2248 drv_nl10_charset_nlq_italic[i * 47 + j * 4 + 24] = b;
2249 drv_nl10_charset_nlq_italic[i * 47 + j * 4 + 26] = b;
2250 }
2251 }
2252
2253 return 0;
2254 }
2255