added printer support

This commit is contained in:
Jorj Bauer 2017-02-20 18:41:46 -05:00
parent 3af0b916d7
commit 32352fcc4c
29 changed files with 3254 additions and 26 deletions

2
.gitignore vendored
View File

@ -1,6 +1,8 @@
apple2e.rom
disk.rom
parallel.rom
*~
*.o
apple/applemmu-rom.h
apple/diskii-rom.h
apple/parallel-rom.h

View File

@ -1,12 +1,12 @@
LDFLAGS=-L/usr/local/lib -lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_features2d -lopencv_calib3d
CXXFLAGS=-Wall -I .. -I . -I apple -O3
CXXFLAGS=-Wall -I .. -I . -I apple -I opencv -O3
TSRC=cpu.cpp util/testharness.cpp
OPENCVOBJS=cpu.o opencv/dummy-speaker.o opencv/opencv-display.o opencv/opencv-keyboard.o opencv/opencv-paddles.o opencv/opencv-filemanager.o apple/appledisplay.o apple/applekeyboard.o apple/applemmu.o apple/applevm.o apple/diskii.o apple/nibutil.o apple/slot.o RingBuffer.o globals.o opencv/aiie.o
OPENCVOBJS=cpu.o opencv/dummy-speaker.o opencv/opencv-display.o opencv/opencv-keyboard.o opencv/opencv-paddles.o opencv/opencv-filemanager.o apple/appledisplay.o apple/applekeyboard.o apple/applemmu.o apple/applevm.o apple/diskii.o apple/nibutil.o RingBuffer.o globals.o opencv/aiie.o apple/parallelcard.o apple/fx80.o opencv/opencv-printer.o
ROMS=apple/applemmu-rom.h apple/diskii-rom.h
ROMS=apple/applemmu-rom.h apple/diskii-rom.h apple/parallel-rom.h
all: opencv
@ -14,17 +14,18 @@ opencv: roms $(OPENCVOBJS)
g++ $(LDFLAGS) -o aiie-opencv $(OPENCVOBJS)
clean:
rm -f *.o *~ */*.o */*~ testharness.basic testharness.verbose testharness.extended aiie-opencv apple/diskii-rom.h apple/applemmu-rom.h
rm -f *.o *~ */*.o */*~ testharness.basic testharness.verbose testharness.extended aiie-opencv apple/diskii-rom.h apple/applemmu-rom.h apple/parallel-rom.h
test: $(TSRC)
g++ $(CXXFLAGS) -DBASICTEST $(TSRC) -o testharness.basic
g++ $(CXXFLAGS) -DVERBOSETEST $(TSRC) -o testharness.verbose
g++ $(CXXFLAGS) -DEXTENDEDTEST $(TSRC) -o testharness.extended
roms: apple2e.rom disk.rom
./util/genrom.pl apple2e.rom disk.rom
roms: apple2e.rom disk.rom parallel.rom
./util/genrom.pl apple2e.rom disk.rom parallel.rom
apple/applemmu-rom.h: roms
apple/diskii-rom.h: roms
apple/parallel-rom.h: roms

View File

@ -26,16 +26,21 @@ As with many emulators, you have to go get the ROMs yourself. I've got
the ROMs that I dumped out of my Apple //e. You can probably get yours
a lot easier.
There are two files that you'll need:
There are three files that you'll need:
* apple2e.rom -- a 32k dump of the entire Apple //e ROM
* disk.rom -- a 256 byte dump of the DiskII controller ROM (16-sector P5)
* parallel.rom -- a 256 byte dump of either of the two Apple Parallel cards
The MD5 sums of those two files are:
The MD5 sums of those files are:
* 003a780b461c96ae3e72861ed0f4d3d9 apple2e.rom
* 2020aa1413ff77fe29353f3ee72dc295 disk.rom
* 5902996f16dc78fc013f6e1db14805b3 parallel.rom
-or-
d666ea749f79a35faa31b4e9a7878eb7 parallel.rom
From those, the appropriate headers will be automatically generated by
"make roms" (or any other target that relies on the ROMs).

View File

@ -19,6 +19,10 @@ AppleVM::AppleVM()
((AppleMMU *)mmu)->setSlot(6, disk6);
keyboard = new AppleKeyboard((AppleMMU *)mmu);
parallel = new ParallelCard();
((AppleMMU *)mmu)->setSlot(1, parallel);
#ifdef TEENSYDUINO
teensyClock = new TeensyClock((AppleMMU *)mmu);
((AppleMMU *)mmu)->setSlot(7, teensyClock);
@ -51,6 +55,7 @@ void AppleVM::cpuMaintenance(uint32_t cycles)
}
keyboard->maintainKeyboard(cycles);
parallel->update();
}
void AppleVM::Reset()

View File

@ -5,6 +5,7 @@
#include "appledisplay.h"
#include "diskii.h"
#include "vmkeyboard.h"
#include "parallelcard.h"
#ifdef TEENSYDUINO
#include "teensy-clock.h"
#endif
@ -32,6 +33,7 @@ class AppleVM : public VM {
protected:
DiskII *disk6;
VMKeyboard *keyboard;
ParallelCard *parallel;
#ifdef TEENSYDUINO
TeensyClock *teensyClock;
#endif

2570
apple/fx80-font.h Normal file

File diff suppressed because it is too large Load Diff

259
apple/fx80.cpp Normal file
View File

@ -0,0 +1,259 @@
#include <string.h> // memset
#include <stdint.h>
#include <stdio.h> // while debugging
#include "fx80.h"
#include "fx80-font.h"
#include "globals.h"
Fx80::Fx80()
{
clearLine();
escapeMode = false;
proportionalMode = false;
carriageDot = 0;
twoSixteenthsLineSpacing = 36; // 1/6" line spacing is the default (12 pixels)
graphicsWidth = 960;
ninePinGraphics = false;
escapeModeActive = 0;
escapeModeExpectingBytes = -1;
escapeModeLengthByteCount = 0;
escapeModeLength = 0;
}
Fx80::~Fx80()
{
}
void Fx80::handleEscape(uint8_t c)
{
switch (c & 0x7F) {
case 75: // FIXME: single-density 480 dpi graphics line
graphicsWidth = 480;
break;
case 76: // FIXME: low-speed double-density graphics line
case 89: // FIXME: high-speed double-density graphics
graphicsWidth = 960;
escapeModeActive = c;
escapeModeExpectingBytes = -1;
escapeModeLengthByteCount = 0;
break;
case 90: // FIXME: quadruple-density graphics
graphicsWidth = 960 * 2;
break;
case 94: // FIXME: enable 9-pin graphics
escapeModeActive = c;
escapeModeExpectingBytes = -1;
escapeModeLengthByteCount = 0;
break;
case 65: // set line spacing
escapeModeActive = c;
escapeModeExpectingBytes = 1;
break;
case 33: // FIXME: mode select
case 35: // FIXME: enable 8-bit reception from computer
case 37: // FIXME: pick charset from ROM
case 38: // FIXME: define chars in RAM
case 42: // FIXME: set vertical tabs
case 43: // FIXME: set form length (default: 66 lines, 11 inches)
case 68: // FIXME: reset current tabs, pitch
case 69: // FIXME: emphasized mode on
case 70: // FIXME: emphasized mode off
case 71: // FIXME: double-strike on
case 72: // FIXME: double-strike off
case 73: // FIXME: enable printing chr[0..31] except control codes
case 74: // FIXME: line feed immediately, n/216th of an inch
case 77: // FIXME: elite mode (12cpi)
case 78: // FIXME: turn on skip-over perforation
case 79: // FIXME: turn off skip-over perforation
case 80: // FIXME: disable elite; enable pica mode (unless compressed is enabled)
case 81: // FIXME: cancel print buffer, set right margin
case 82: // FIXME: select international charset
case 83: // FIXME: script mode on
case 84: // FIXME: script mode off
case 85: // FIXME: unidirecitonal mode on/off
case 87: // FIXME: expanded mode
case 98: // FIXME: set vertical tab
case 105: // FIXME: immediate mode on
case 106: // FIXME: immediate reverse linefeed 1/216"
case 108: // FIXME: set left margin
case 112: // FIXME: turn on proportional mode
case 115: // FIXME: print speed
printf("unhandled escape code %d\n", c);
break;
}
}
void Fx80::handleActiveEscapeMode(uint8_t c)
{
switch (escapeModeActive) {
case 76:
case 89:
// one column of double-density graphics
{
// FIXME: abstract this - second time it's being used
uint16_t byteIdx = (carriageDot+0) / 8 + (FX80_MAXWIDTH/8) * 0;
uint8_t bitIdx = (carriageDot+0) % 8;
for (int i=0; i<8; i++) {
if (c & (1 << (7-i))) {
rowOfBits[byteIdx] |= (1 << (7-bitIdx));
}
byteIdx += (FX80_MAXWIDTH/8);
}
}
carriageDot++;
break;
case 65: // set line spacing to n/72ths of an inch (n=0-85)
twoSixteenthsLineSpacing = 3 * c;
break;
default:
printf("unhandled active escape mode %d\n", c);
break;
}
}
void Fx80::input(uint8_t c)
{
if (escapeMode) {
handleEscape(c);
escapeMode = false;
return;
}
// Is this an escape mode that gets a fixed amount of input?
if (escapeModeActive) {
if (escapeModeExpectingBytes < 0) {
// We're reading 2 bytes of length
escapeModeLengthByteCount++;
if (escapeModeLengthByteCount == 1) {
escapeModeLength = c;
} else {
escapeModeLength |= (c << 8);
escapeModeExpectingBytes = escapeModeLength;
}
return;
} else {
escapeModeExpectingBytes--;
}
handleActiveEscapeMode(c);
if (escapeModeExpectingBytes == 0) {
escapeModeActive = 0;
}
return;
}
if (c == 27) {
escapeMode = true;
return;
}
// FIXME: all these also work as 128 + c
switch (c & 0x7F) {
case 0: // FIXME: terminate horiz/vert tab setting
return;
case 7: // beep
return;
case 8: // FIXME: "at current width" instead of this fixed-12
if (carriageDot >= 12)
carriageDot -= 12;
return;
case 9: // FIXME: HTAB
return;
case 10:
lineFeed();
return;
case 11: // FIXME: VTAB
return;
case 12: // FIXME: Form Feed
lineFeed();
return;
case 13:
carriageDot = 0;
// lineFeed(); // FIXME: this was controlled by a switch
return;
case 14: // FIXME: Shift Out - turns on "Expanded Mode"
case 15: // FIXME: Shift In - turns on "Compressed Mode"
case 17: // FIXME: DC1
case 18: // FIXME: DC2
case 19: // FIXME: DC3
case 20: // FIXME: DC4
case 24: // FIXME: cancel text in print buffer; not the same as "clear line"
case 127: // FIXME: delete last char in the print buffer
return;
}
// normal print - send the character verbatim...
addCharacter(c & 0x7F); // FIXME: masking high bit
}
// add the given character on the line at the current carriage dot position
void Fx80::addCharacter(uint8_t c)
{
uint8_t width = Fx80Font[c * 19];
// FIXME: is 12 right for non-proportional mode?
if (!proportionalMode)
width = 12;
// Each row for this char has two bytes of bits, left-to-right, high
// bit leftmost.
const uint8_t *charPtr = &Fx80Font[c * 19];
charPtr++;
for (uint8_t row=0; row<9; row++) {
// Don't print beyond end of line!
for (uint8_t xoff = 0; xoff < 8; xoff++) {
if (carriageDot+xoff >= FX80_MAXWIDTH)
continue;
uint16_t byteIdx = (carriageDot+xoff) / 8 + (FX80_MAXWIDTH/8) * row;
uint8_t bitIdx = (carriageDot+xoff) % 8;
// We never clear bits - it's possible to overstrike, so just add more...
if (charPtr[2*row] & (1 << (7-xoff))) {
rowOfBits[byteIdx] |= (1 << (7-bitIdx));
}
if (charPtr[2*row+1] & (1 << (7-xoff))) {
rowOfBits[byteIdx+1] |= (1 << (7-bitIdx));
}
}
}
carriageDot += 12; // FIXME
}
void Fx80::lineFeed()
{
emitLine();
g_printer->moveDownPixels(twoSixteenthsLineSpacing / 3); // pixel estimation
clearLine();
}
void Fx80::clearLine()
{
memset(rowOfBits, 0, sizeof(rowOfBits));
}
void Fx80::emitLine()
{
// FIXME: this is very wrong. Doesn't deal with line advance
// properly. But it's good enough for debugging basic operation.
g_printer->addLine(rowOfBits);
}
void Fx80::update()
{
// The onscreen window needs to update regularly, and we probably
// want to periodically flush the Teensy buffer.
if (g_printer) {
g_printer->update();
}
}

75
apple/fx80.h Normal file
View File

@ -0,0 +1,75 @@
#ifndef __FX80_H
#define __FX80_H
#include <stdint.h>
/* maximum width, in dots, that we're supporting. The FX80 supported
* up to 1920 ("quadruple density") -- which I'm not, b/c that's
* overkill for what I'm doing at the moment. I'm supporting "double density"
* (960 dots per 8-inch line).
*
* My general strategy here is to fill up a line with bits until the
* printer thinks it needs to move to the next line; and then do
* something with the bits (send them to a printer, a screen, a file,
* whatever). This gets both graphics and text modes in one swell foop.
*
* There is the troublesome "9-pin graphics mode" where each column of
* bits is > 1 byte of data; for that, we keep an extra "rowOfPin9"
* bits, which is just a bit stream across the width. It would be
* easier to make rowOfBits be uint16_t but it would consume more RAM,
* and I'm trying to minimize that as I'm down to about 13k of free
* space in the Teensy!
*/
#define FX80_MAXWIDTH 960
#ifdef TEENSYDUINO
class TeensyPrinter;
#else
class OpenCVPrinter;
#endif
class Fx80 {
public:
Fx80();
~Fx80();
void input(uint8_t c);
void update();
private:
void lineFeed();
void clearLine();
void addCharacter(uint8_t c);
void handleEscape(uint8_t c);
void handleActiveEscapeMode(uint8_t c);
void emitLine();
protected:
bool escapeMode;
bool proportionalMode;
uint16_t carriageDot; // what dot-column we are at
// Line spacing. 1/216th of an inch is 1/3 of a dot, which is the minimum
// supported by the FX-80. This is usually set in terms of 72nds, and
// it's unlikely that I'll render anything at 1/216, but might as
// well interpret it the way the printer understands it.
// (That means 8/72, which is a setting of 24 here, is 8 dots tall.)
uint16_t twoSixteenthsLineSpacing;
uint16_t graphicsWidth;
bool ninePinGraphics;
uint8_t escapeModeActive;
int32_t escapeModeExpectingBytes;
uint8_t escapeModeLengthByteCount;
uint16_t escapeModeLength;
// 9 pixel-rows of (FX80_MAXWIDTH) bits (stuffed in 8-bit bytes)
uint8_t rowOfBits[(FX80_MAXWIDTH/8)*9];
};
#endif

50
apple/parallelcard.cpp Normal file
View File

@ -0,0 +1,50 @@
#include "parallelcard.h"
#include <string.h>
#include "parallel-rom.h"
#include "fx80.h"
ParallelCard::ParallelCard()
{
fx80 = new Fx80();
}
ParallelCard::~ParallelCard()
{
}
void ParallelCard::Reset()
{
}
uint8_t ParallelCard::readSwitches(uint8_t s)
{
return 0xFF;
}
void ParallelCard::writeSwitches(uint8_t s, uint8_t v)
{
if (s == 0x00) {
fx80->input(v);
} else {
// printf("unknown switch 0x%X\n", s);
}
}
void ParallelCard::loadROM(uint8_t *toWhere)
{
#ifdef TEENSYDUINO
Serial.println("loading parallel slot rom");
for (uint16_t i=0; i<=0xFF; i++) {
toWhere[i] = pgm_read_byte(&romData[i]);
}
#else
printf("loading parallel slot rom\n");
memcpy(toWhere, romData, 256);
#endif
}
void ParallelCard::update()
{
fx80->update();
}

32
apple/parallelcard.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef __PARALLELCARD_H
#define __PARALLELCARD_H
#ifdef TEENSYDUINO
#include <Arduino.h>
#else
#include <stdint.h>
#include <stdio.h>
#endif
#include "applemmu.h"
#include "slot.h"
class Fx80;
class ParallelCard : public Slot {
public:
ParallelCard();
virtual ~ParallelCard();
virtual void Reset(); // used by BIOS cold-boot
virtual uint8_t readSwitches(uint8_t s);
virtual void writeSwitches(uint8_t s, uint8_t v);
virtual void loadROM(uint8_t *toWhere);
void update();
private:
Fx80 *fx80;
};
#endif

View File

@ -1,9 +0,0 @@
#include "slot.h"
Slot::Slot()
{
}
Slot::~Slot()
{
}

View File

@ -11,8 +11,7 @@
class Slot {
public:
Slot();
~Slot();
virtual ~Slot() {};
virtual void Reset() = 0; // for use at cold-boot

View File

@ -7,5 +7,6 @@ PhysicalDisplay *g_display = NULL;
PhysicalKeyboard *g_keyboard = NULL;
PhysicalSpeaker *g_speaker = NULL;
PhysicalPaddles *g_paddles = NULL;
PhysicalPrinter *g_printer = NULL;
int16_t g_volume;
uint8_t g_displayType = 3; // FIXME m_perfectcolor

View File

@ -7,6 +7,7 @@
#include "physicalkeyboard.h"
#include "physicalspeaker.h"
#include "physicalpaddles.h"
#include "physicalprinter.h"
extern FileManager *g_filemanager;
extern Cpu *g_cpu;
@ -15,5 +16,6 @@ extern PhysicalDisplay *g_display;
extern PhysicalKeyboard *g_keyboard;
extern PhysicalSpeaker *g_speaker;
extern PhysicalPaddles *g_paddles;
extern PhysicalPrinter *g_printer;
extern int16_t g_volume;
extern uint8_t g_displayType;

View File

@ -12,6 +12,7 @@
#include "dummy-speaker.h"
#include "opencv-paddles.h"
#include "opencv-filemanager.h"
#include "opencv-printer.h"
#include "globals.h"
@ -247,14 +248,14 @@ static void *cpu_thread(void *dummyptr) {
#endif
if (send_rst) {
#if 0
#if 1
printf("Sending reset\n");
// g_cpu->Reset();
g_cpu->Reset();
// testing startup keyboard presses - perform Apple //e self-test
g_vm->getKeyboard()->keyDepressed(RA);
g_vm->Reset();
g_cpu->Reset();
//g_vm->getKeyboard()->keyDepressed(RA);
//g_vm->Reset();
//g_cpu->Reset();
//((AppleVM *)g_vm)->insertDisk(0, "disks/DIAGS.DSK");
#else
@ -293,6 +294,7 @@ static void *cpu_thread(void *dummyptr) {
int main(int argc, char *argv[])
{
g_speaker = new DummySpeaker();
g_printer = new OpenCVPrinter();
// create the filemanager - the interface to the host file system.
g_filemanager = new OpenCVFileManager();

View File

@ -61,7 +61,7 @@ const char *OpenCVFileManager::fileName(int8_t fd)
return cachedNames[fd];
}
int8_t OpenCVFileManager::readDir(const char *where, const char *suffix, char *outputFN, int8_t startIdx, uint8_t maxlen)
int8_t OpenCVFileManager::readDir(const char *where, const char *suffix, char *outputFN, int8_t startIdx, uint16_t maxlen)
{
// not used in this version
return -1;

75
opencv/opencv-printer.cpp Normal file
View File

@ -0,0 +1,75 @@
#include "opencv-printer.h"
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/features2d/features2d.hpp"
using namespace cv;
using namespace std;
#define WINDOWNAME "printer"
#define HEIGHT 800
#define NATIVEWIDTH 960 // FIXME: printer can change density...
//#define WIDTH 384 // emulating the teeny printer I've got
#define WIDTH 960
OpenCVPrinter::OpenCVPrinter()
{
pixels = new Mat(HEIGHT, WIDTH, CV_8U);
*pixels = cv::Scalar(0xFF);
ypos = 0;
isDirty = false;
namedWindow(WINDOWNAME, CV_WINDOW_AUTOSIZE);
}
OpenCVPrinter::~OpenCVPrinter()
{
delete pixels; pixels = NULL;
}
void OpenCVPrinter::update()
{
if (isDirty) {
imshow(WINDOWNAME, *pixels);
isDirty = false;
}
}
void OpenCVPrinter::addLine(uint8_t *rowOfBits)
{
isDirty = true;
for (int yoff=0; yoff<8; yoff++) {
// 960 pixels == 120 bytes -- FIXME
for (int i=0; i<(NATIVEWIDTH/8); i++) {
uint8_t bv = rowOfBits[yoff*120+i];
for (int xoff=0; xoff<8; xoff++) {
// scale X from "actual FX80" coordinates to "real printer" coordinates
uint16_t actualX = (uint16_t)(((float)(i*8+xoff) * (float)WIDTH) / (float)NATIVEWIDTH);
uint8_t oldPixel = pixels->at<uchar>((ypos + yoff)%HEIGHT, actualX);
uint8_t pixelColor = (bv & (1 << (7-xoff))) ? 0x00 : 0xFF;
// Make sure to preserve any pixels we've already drawn
pixels->at<uchar>((ypos + yoff)%HEIGHT, actualX) = ~(~oldPixel | ~pixelColor);
}
}
}
if (ypos >= HEIGHT) {
ypos = 0;
}
}
void OpenCVPrinter::moveDownPixels(uint8_t p)
{
ypos+= p;
if (ypos >= HEIGHT) {
// clear page & restart
*pixels = cv::Scalar(0xFF);
ypos = 0;
}
}

31
opencv/opencv-printer.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef __OPENCV_PRINTER_H
#define __OPENCV_PRINTER_H
#include <stdlib.h>
#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "physicalprinter.h"
class OpenCVPrinter : public PhysicalPrinter {
public:
OpenCVPrinter();
virtual ~OpenCVPrinter();
virtual void addLine(uint8_t *rowOfBits); // must be 960 pixels wide (120 bytes)
virtual void update();
virtual void moveDownPixels(uint8_t p);
private:
bool isDirty;
uint16_t ypos;
cv::Mat *pixels;
};
#endif

13
physicalprinter.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef __PHYSICALPRINTER_H
#define __PHYSICALPRINTER_H
class PhysicalPrinter {
public:
virtual ~PhysicalPrinter() {}
// must be 960 pixels wide (120 bytes)
virtual void addLine(uint8_t *rowOfBits) = 0;
virtual void update() = 0;
virtual void moveDownPixels(uint8_t p) = 0;
};
#endif

1
teensy/fx80-font.h Symbolic link
View File

@ -0,0 +1 @@
../apple/fx80-font.h

1
teensy/fx80.cpp Symbolic link
View File

@ -0,0 +1 @@
../apple/fx80.cpp

1
teensy/fx80.h Symbolic link
View File

@ -0,0 +1 @@
../apple/fx80.h

1
teensy/parallel-rom.h Symbolic link
View File

@ -0,0 +1 @@
../apple/parallel-rom.h

1
teensy/parallelcard.cpp Symbolic link
View File

@ -0,0 +1 @@
../apple/parallelcard.cpp

1
teensy/parallelcard.h Symbolic link
View File

@ -0,0 +1 @@
../apple/parallelcard.h

1
teensy/physicalprinter.h Symbolic link
View File

@ -0,0 +1 @@
../physicalprinter.h

78
teensy/teensy-printer.cpp Normal file
View File

@ -0,0 +1,78 @@
#include <Arduino.h>
#include "teensy-printer.h"
#define WIDTH (384) // width of printer, in dots
#define NATIVEWIDTH 960 //
#define RXPIN 57
#define TXPIN 56
TeensyPrinter::TeensyPrinter()
{
ser = new SoftwareSerial(RXPIN, TXPIN, false);
ser->begin(19200);
char buf[6] = { 27, '@', // init command '@'
27, '3', 8, // ESC-3 is "set line spacing"; default 30
0 // terminator
};
ser->print(buf);
}
TeensyPrinter::~TeensyPrinter()
{
delete ser;
}
void TeensyPrinter::update()
{
}
void TeensyPrinter::addLine(uint8_t *rowOfBits)
{
static uint8_t linebuf[WIDTH/8]; // output data for one line of pixels
// The rowOfBits is a set of *rows* of bits. The printer needs *columns*.
// Convert and send as necessary.
// Send bitmap command, followed by bitmap data, followed by linefeed?
// ser->write(27); // set line spacing
// ser->write('3');
// ser->write((uint8_t)30);
#define DC2 18
// FIXME: is this 0-6, or 1-7? One of them is empty..
// FIXME: also read this off of the print head size/line feed size?
for (int yoff=1; yoff<8; yoff++) {
memset(linebuf, 0, sizeof(linebuf)); // start clear...
for (int i=0; i<(NATIVEWIDTH/8); i++) {
uint8_t bv = rowOfBits[yoff*120+i];
// Process the 8 bits in this byte
for (int xoff=0; xoff<8; xoff++) {
// scale X from "actual FX80" coordinates to "real printer" coordinates
uint16_t actualX = (uint16_t)(((float)(i*8+xoff) * (float)WIDTH) / (float)NATIVEWIDTH);
if (bv & (1 << (7-xoff))) { // if it's on in the original
// then turn it on in our copy
uint8_t bitNum = actualX & 0x07;
linebuf[actualX>>3] |= (1<<(7-bitNum));
}
}
}
// Send this line to the printer
ser->write(DC2); // send this line as a bitmap
ser->write('*');
ser->write(1); // FIXME: height
ser->write(48); // FIXME: width, in bytes
for (int i=0; i<WIDTH/8; i++) {
ser->write(linebuf[i]);
}
}
// ser->write(10); // linefeed @ the end
}
void TeensyPrinter::moveDownPixels(uint8_t p)
{
}

25
teensy/teensy-printer.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef __TEENSY_PRINTER_H
#define __TEENSY_PRINTER_H
#include <stdlib.h>
#include <SoftwareSerial.h>
#include "physicalprinter.h"
class TeensyPrinter : public PhysicalPrinter {
public:
TeensyPrinter();
virtual ~TeensyPrinter();
virtual void addLine(uint8_t *rowOfBits); // must be 960 pixels wide (120 bytes)
virtual void update();
virtual void moveDownPixels(uint8_t p);
private:
uint16_t ypos;
SoftwareSerial *ser;
};
#endif

View File

@ -5,12 +5,15 @@ use warnings;
my $romfile = shift || die "Must provide the path to an Apple //e ROM image";
my $diskrom = shift || die "Must also provide the path to an Apple //e Disk II ROM image";
my $parallelrom = shift || die "Must also provide the path to an Apple // parallel card ROM image";
validate($romfile, 32768, "an Apple //e ROM image");
validate($diskrom, 256, "a DiskII ROM image");
validate($parallelrom, 256, "a parallel card ROM image");
dumpRom($romfile, "apple/applemmu-rom.h", "romData", 32768);
dumpRom($diskrom, "apple/diskii-rom.h", "romData", 256);
dumpRom($parallelrom, "apple/parallel-rom.h", "romData", 256);
exit 0;
sub validate {
@ -38,7 +41,7 @@ sub dumpRom {
#endif
static
uint8_t romData[32768] PROGMEM = {
uint8_t romData[$datasize] PROGMEM = {
EOF
;