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 apple2e.rom
disk.rom disk.rom
parallel.rom
*~ *~
*.o *.o
apple/applemmu-rom.h apple/applemmu-rom.h
apple/diskii-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 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 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 all: opencv
@ -14,17 +14,18 @@ opencv: roms $(OPENCVOBJS)
g++ $(LDFLAGS) -o aiie-opencv $(OPENCVOBJS) g++ $(LDFLAGS) -o aiie-opencv $(OPENCVOBJS)
clean: 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) test: $(TSRC)
g++ $(CXXFLAGS) -DBASICTEST $(TSRC) -o testharness.basic g++ $(CXXFLAGS) -DBASICTEST $(TSRC) -o testharness.basic
g++ $(CXXFLAGS) -DVERBOSETEST $(TSRC) -o testharness.verbose g++ $(CXXFLAGS) -DVERBOSETEST $(TSRC) -o testharness.verbose
g++ $(CXXFLAGS) -DEXTENDEDTEST $(TSRC) -o testharness.extended g++ $(CXXFLAGS) -DEXTENDEDTEST $(TSRC) -o testharness.extended
roms: apple2e.rom disk.rom roms: apple2e.rom disk.rom parallel.rom
./util/genrom.pl apple2e.rom disk.rom ./util/genrom.pl apple2e.rom disk.rom parallel.rom
apple/applemmu-rom.h: roms apple/applemmu-rom.h: roms
apple/diskii-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 the ROMs that I dumped out of my Apple //e. You can probably get yours
a lot easier. 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 * 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) * 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 * 003a780b461c96ae3e72861ed0f4d3d9 apple2e.rom
* 2020aa1413ff77fe29353f3ee72dc295 disk.rom * 2020aa1413ff77fe29353f3ee72dc295 disk.rom
* 5902996f16dc78fc013f6e1db14805b3 parallel.rom
-or-
d666ea749f79a35faa31b4e9a7878eb7 parallel.rom
From those, the appropriate headers will be automatically generated by From those, the appropriate headers will be automatically generated by
"make roms" (or any other target that relies on the ROMs). "make roms" (or any other target that relies on the ROMs).

View File

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

View File

@ -5,6 +5,7 @@
#include "appledisplay.h" #include "appledisplay.h"
#include "diskii.h" #include "diskii.h"
#include "vmkeyboard.h" #include "vmkeyboard.h"
#include "parallelcard.h"
#ifdef TEENSYDUINO #ifdef TEENSYDUINO
#include "teensy-clock.h" #include "teensy-clock.h"
#endif #endif
@ -32,6 +33,7 @@ class AppleVM : public VM {
protected: protected:
DiskII *disk6; DiskII *disk6;
VMKeyboard *keyboard; VMKeyboard *keyboard;
ParallelCard *parallel;
#ifdef TEENSYDUINO #ifdef TEENSYDUINO
TeensyClock *teensyClock; TeensyClock *teensyClock;
#endif #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 { class Slot {
public: public:
Slot(); virtual ~Slot() {};
~Slot();
virtual void Reset() = 0; // for use at cold-boot virtual void Reset() = 0; // for use at cold-boot

View File

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

View File

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

View File

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

View File

@ -61,7 +61,7 @@ const char *OpenCVFileManager::fileName(int8_t fd)
return cachedNames[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 // not used in this version
return -1; 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 $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 $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($romfile, 32768, "an Apple //e ROM image");
validate($diskrom, 256, "a DiskII 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($romfile, "apple/applemmu-rom.h", "romData", 32768);
dumpRom($diskrom, "apple/diskii-rom.h", "romData", 256); dumpRom($diskrom, "apple/diskii-rom.h", "romData", 256);
dumpRom($parallelrom, "apple/parallel-rom.h", "romData", 256);
exit 0; exit 0;
sub validate { sub validate {
@ -38,7 +41,7 @@ sub dumpRom {
#endif #endif
static static
uint8_t romData[32768] PROGMEM = { uint8_t romData[$datasize] PROGMEM = {
EOF EOF
; ;