1 /* pro_la50.c: LA50 printer emulator
2
3 Copyright (c) 1997-2003, Tarik Isani (xhomer@isani.org)
4
5 This file is part of Xhomer.
6
7 Xhomer is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2
9 as published by the Free Software Foundation.
10
11 Xhomer is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Xhomer; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21
22 /* TBD:
23 -speed up emu while printing PCL
24 */
25
26 #ifdef PRO
27 #include "pdp11_defs.h"
28
29 #define SIX_RPT 0x21
30 #define SIX_NL 0x2d
31 #define SIX_CR 0x24
32 #define SIX_SUB 0x1a
33
34 #define ESC 0x1b
35 #define FF 0x0c
36
37 #define PWIDTH 85 /* paper width in inches*10 */
38
39 #define MAXOUTRES 600
40
41 #define MAXCOLS (PWIDTH*MAXOUTRES/10)
42 #define MAXCOLBYTES ((MAXCOLS+7)/8)
43
44 #define S_IDLE 0
45 #define S_ESC 1
46 #define S_WAIT_ESC 2
47 #define S_SIX_IDLE 3
48 #define S_SIX_ESC 4
49 #define S_SIX_RPT 5
50
51 #define PTR_FIFO_DEPTH (MAXCOLBYTES*6*8)
52
53
54 /* LA50 code entry points */
55
56 struct sercall pro_la50 = {&pro_la50_get, &pro_la50_put,
57 &pro_la50_ctrl_get, &pro_la50_ctrl_put,
58 &pro_la50_reset, &pro_la50_exit};
59
60
61 int pro_la50_dpi = 300; /* actual output resolution in DPI */
62
63 LOCAL unsigned char tmpstr[256];
64
65 LOCAL int col;
66 LOCAL int maxcols, maxpos;
67
68 LOCAL int state;
69 LOCAL int esc_cmd;
70
71 LOCAL int rpt;
72
73 LOCAL int colrcnt, rowrcnt;
74
75 LOCAL unsigned char pic[6][MAXCOLBYTES];
76
77
78 LOCAL int ptr_fifo_h;
79 LOCAL int ptr_fifo_t;
80 LOCAL int ptr_fifo_level;
81 LOCAL unsigned char ptr_fifo[PTR_FIFO_DEPTH];
82
83
84 /* Put character in FIFO */
85
ptr_fifo_put(int c)86 void ptr_fifo_put (int c)
87 {
88 ptr_fifo[ptr_fifo_h] = (unsigned char)c;
89 ptr_fifo_h++;
90 if (ptr_fifo_h == PTR_FIFO_DEPTH)
91 ptr_fifo_h = 0;
92
93 ptr_fifo_level++;
94 }
95
96
ptr_fifo_printf(unsigned char * s)97 void ptr_fifo_printf (unsigned char *s)
98 {
99 while(*s != '\0')
100 {
101 ptr_fifo_put((int)*s);
102 s++;
103 }
104 }
105
106
107 /* Read character at head of FIFO, but don't advance
108 head pointer */
109
ptr_fifo_get()110 int ptr_fifo_get ()
111 {
112 int c;
113
114 /* Check if FIFO is empty */
115
116 if (ptr_fifo_h == ptr_fifo_t)
117 c = PRO_NOCHAR;
118 else
119 {
120 c = (int)ptr_fifo[ptr_fifo_t];
121 ptr_fifo_level--;
122 }
123
124 return c;
125 }
126
127
128 /* Advance FIFO head pointer */
129
ptr_fifo_advance()130 void ptr_fifo_advance ()
131 {
132 ptr_fifo_t++;
133 if (ptr_fifo_t == PTR_FIFO_DEPTH)
134 ptr_fifo_t = 0;
135 }
136
137
start_pcl()138 void start_pcl()
139 {
140 sprintf(tmpstr, "%c*t%dR%c*r0A", ESC, pro_la50_dpi, ESC);
141 ptr_fifo_printf(tmpstr);
142
143 colrcnt = 0;
144 rowrcnt = 0;
145
146 col = 0;
147 maxcols = 0;
148 memset(pic, 0, 6*MAXCOLBYTES);
149 }
150
151
end_pcl()152 void end_pcl()
153 {
154 sprintf(tmpstr, "%c*rB", ESC);
155 ptr_fifo_printf(tmpstr);
156 }
157
158
output_pcl()159 void output_pcl()
160 {
161 int ocol8, ocolmax, orow;
162 int ipos, opos, pix;
163 int rep, res;
164
165 unsigned char oline[MAXCOLBYTES];
166
167 /* replication factors for 300 & 600 dpi */
168
169 int colrep[2][2] = {{1, 2}, {3, 3}};
170 int rowrep[2][4] = {{4, 4, 4, 3}, {8, 7, 8, 7}};
171
172
173 if (pro_la50_dpi == 300)
174 res = 0;
175 else
176 res = 1;
177
178 for(orow=0; orow<6; orow++)
179 {
180 /* Scale line up */
181
182 opos = 0;
183
184 memset(oline, 0, MAXCOLBYTES);
185
186 /* XXX make this maxcols */
187
188 for(ipos=0; ipos<MAXCOLS; ipos++)
189 {
190 pix = (pic[orow][ipos/8] >> (7-(ipos%8))) & 1;
191
192 for(rep=0; rep<colrep[res][colrcnt]; rep++)
193 {
194 if (opos<maxpos)
195 oline[opos/8] |= pix << (7-(opos%8));
196 opos++;
197 }
198
199 colrcnt++;
200 if (colrcnt == 2)
201 colrcnt = 0;
202 }
203
204 for(ocolmax=MAXCOLBYTES-1; ocolmax>0; ocolmax--)
205 if (oline[ocolmax] != 0)
206 break;
207
208 ocolmax++;
209
210 for(rep=0; rep<rowrep[res][rowrcnt]; rep++)
211 {
212 sprintf(tmpstr, "%c*b%dW", ESC, ocolmax);
213 ptr_fifo_printf(tmpstr);
214
215 for(ocol8=0; ocol8<ocolmax; ocol8++)
216 ptr_fifo_put((int)oline[ocol8]);
217 }
218
219 rowrcnt++;
220 if (rowrcnt == 4)
221 rowrcnt = 0;
222 }
223 }
224
225
plot_six(int c,int rep)226 void plot_six(int c, int rep)
227 {
228 int sixel, prow, pcol, pcolb, pcolb_r;
229
230 sixel = c - 0x3f;
231
232 for(pcol=col; pcol<(col+rep); pcol++)
233 {
234 if (pcol < MAXCOLS)
235 {
236 pcolb = pcol / 8;
237 pcolb_r = pcol % 8;
238
239 for(prow=0; prow<6; prow++)
240 {
241 pic[prow][pcolb] |= ((sixel >> prow) & 1) << (7-pcolb_r);
242 }
243
244 maxcols++;
245 }
246 }
247
248 col += rep;
249 }
250
251
six_filter(int c)252 void six_filter(int c)
253 {
254 switch(state)
255 {
256 case S_IDLE:
257 if (c == ESC)
258 state = S_ESC;
259 else
260 ptr_fifo_put(c);
261 break;
262
263 case S_ESC:
264 if (c < 32)
265 state = S_IDLE;
266 else
267 {
268 esc_cmd = c;
269 state = S_WAIT_ESC;
270 }
271 break;
272
273 case S_WAIT_ESC:
274 if (((c >= (int)'A') && (c <= (int)'Z'))
275 || ((c >= (int)'a') && (c <= (int)'z'))
276 || (c == (int)'<') || (c == (int)'}'))
277 {
278 if ((c == (int)'q') && (esc_cmd == (int)'P'))
279 {
280 start_pcl();
281 state = S_SIX_IDLE;
282 }
283 else
284 state = S_IDLE;
285 }
286 break;
287
288 case S_SIX_IDLE:
289 if ((c>=0x3f) && (c<=0x7e))
290 {
291 plot_six(c, 1);
292 break;
293 }
294 else if (c == ESC)
295 {
296 state = S_SIX_ESC;
297 break;
298 }
299 else if (c == SIX_RPT)
300 {
301 rpt = 0;
302 state = S_SIX_RPT;
303 break;
304 }
305 else if (c == SIX_NL)
306 {
307 output_pcl();
308 col = 0;
309 maxcols = 0;
310 memset(pic, 0, 6*MAXCOLBYTES);
311 break;
312 }
313 else if (c == SIX_CR)
314 {
315 col = 0;
316 break;
317 }
318 else if (c == SIX_SUB)
319 {
320 plot_six(0x3f, 1);
321 break;
322 }
323
324 case S_SIX_ESC:
325 /* ending sequence is ESC\, but we'll take anything */
326
327 end_pcl();
328
329 state = S_IDLE;
330 break;
331
332 case S_SIX_RPT:
333 if (c == ESC)
334 {
335 state = S_SIX_ESC;
336 break;
337 }
338 else if ((c>(int)'9') || (c<(int)'0'))
339 {
340 if (c == SIX_SUB)
341 c = 0x3f;
342
343 if ((c>=0x3f) && (c<=0x7e))
344 plot_six(c, rpt);
345
346 state = S_SIX_IDLE;
347 break;
348 }
349 else
350 {
351 rpt = 10*rpt + c - (int)'0';
352 break;
353 }
354 }
355 }
356
357
358 /* Get character from LA50 */
359
pro_la50_get(int dev)360 int pro_la50_get (int dev)
361 {
362 int i, schar;
363
364
365 /* This is a bit of a hack
366 Every time the emu does a read poll,
367 this routine polls the pcl output FIFO and copies
368 up to 10 bytes from it to the real printer hardware. */
369
370 for(i=0; i<10; i++)
371 {
372 schar = ptr_fifo_get();
373 if (schar == PRO_NOCHAR)
374 break;
375 else
376 {
377 if (pro_la50device->put(dev, schar) == PRO_FAIL)
378 break;
379 else
380 ptr_fifo_advance();
381 }
382 }
383
384 return pro_la50device->get(dev);
385 }
386
387
388 /* Send character to LA50 */
389
pro_la50_put(int dev,int schar)390 int pro_la50_put (int dev, int schar)
391 {
392 int stat;
393
394
395 if (ptr_fifo_level<PTR_FIFO_DEPTH/2)
396 {
397 six_filter(schar);
398 stat = PRO_SUCCESS;
399 }
400 else
401 stat = PRO_FAIL;
402
403 return stat;
404 }
405
406
407 /* Return serial line parameters */
408
pro_la50_ctrl_get(int dev,struct serctrl * sctrl)409 void pro_la50_ctrl_get (int dev, struct serctrl *sctrl)
410 {
411 pro_la50device->ctrl_get(dev, sctrl);
412 }
413
414
415 /* Set serial line parameters */
416
pro_la50_ctrl_put(int dev,struct serctrl * sctrl)417 void pro_la50_ctrl_put (int dev, struct serctrl *sctrl)
418 {
419 pro_la50device->ctrl_put(dev, sctrl);
420 }
421
422
423 /* Reset LA50 */
424
pro_la50_reset(int dev,int portnum)425 void pro_la50_reset (int dev, int portnum)
426 {
427 state = S_IDLE;
428 ptr_fifo_h = 0;
429 ptr_fifo_t = 0;
430 ptr_fifo_level = 0;
431 maxpos = (PWIDTH*pro_la50_dpi/10);
432
433 pro_la50device->reset(dev, pro_la50device_port);
434 }
435
436
437 /* Exit routine */
438
pro_la50_exit(int dev)439 void pro_la50_exit (int dev)
440 {
441 pro_la50device->exit(dev);
442 }
443 #endif
444