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