'work in progress' - arduino driven plotter

here is the skeleton of my plotting sketch, it takes care of not overrunning the plotter's 1024 byte buffer and detects disconnections and plotter errors.

user.h

enum pState {
  reset,
  waiting,
  plotting,
  buffering,
  noconnection,
  error
};

enum pWorld {
  plotter,
  text,
  drawing
};

void setState(pState state);

First Part of code (too long to fit one post)

#include "user.h"
#include <math.h>
#include <avr/pgmspace.h>  // for progmem stuff

#define DEBUG_enabled 0

#define buttonPin 8

#define ESC "\x1B"

#define cmdBufferSize 255

pState plotterState;
pState noConnectionReturnState;
pWorld plotterWorld;

byte errorCode = 0;
byte statusCode = 0;
int bufferCapacity = 0;

char serInStr[64]; 
char cmd[cmdBufferSize] ="";
char progStrLine[48] = "";
boolean textMessageBuffered;
boolean textMessagePlotted;

unsigned long nextDrawMillis = 0ul;
unsigned long nextPingMillis = 0ul;

union coordinate {
  byte b[4];
  double d;
} 
currentCoordinate;

const double minDistToDraw = 60.0;
double x, y, xOld, yOld;

boolean firstDraw = true;
boolean penDown = false;
boolean wantsToEnd = false;
boolean endingInited = false;

int currentPen = 0;

// A3 plotter space size: 16158 x 11040
int plotterWidth = 16158;
int plotterHeight = 11040;

// system coordinates MAX_INT x MAX_INT
int systemWidth=32767;
int systemHeight=32767;

int textLines = 0;
int margin = 40*10;

/********************** PROGMEM SECTION BELOW **********************/
// long text string can be stored in program memory, and sent to the plotter
// from there as commands or log messages

const char startMessage[] PROGMEM = 
"\n___________________________________________\n"
"\nARDUINO PLOTTER\n"
"version 2.0\n"
"\n"
"ole kristensen 2010\n"
"\n"
"mailto:ole@kristensen.name\n"
"http://ole.kristensen.name\n"
"___________________________________________\n\n"
;

const char textMessage[] PROGMEM =
"http://ole.kristensen.name\n"
"mailto:ole" "\x40" "kristensen.name\n"
;

const char resetPlotterCodes[] PROGMEM =
"\x1B" ".Y\n"
"\x1B" ".R\n"
"\x1B" ".M0;;;13:\n"
"IN;\n"
"SP0;\n"
;

boolean getProgStrLine(const prog_char str[], int lineNo){
  memset(progStrLine, 0, sizeof(progStrLine));
  char c;
  int currentLine = 0;
  byte currentChar = 0;
  if(!str) return false;
  while((c = pgm_read_byte(str++))){
    progStrLine[currentChar] = c;
    currentChar++;
    if(c == '\n'){
      if(currentLine == lineNo) {
        if(currentChar == 1){
          progStrLine[0] = ' ';
        }
        return true;
      } 
      else {
        memset(progStrLine, 0, sizeof(progStrLine));
        currentLine++;
        currentChar = 0;
      }
    }
  }
  if(currentLine == lineNo && currentChar > 0){
    return true;
  }
  if(currentLine < lineNo) {
    return false;
  }
}

void printProgStr(const prog_char str[])
{
  char c;
  if(!str) return;
  while((c = pgm_read_byte(str++)))
    Serial.print(c,BYTE);
}

void logProgStr(const prog_char str[])
{
  Serial.println(ESC ".)");
  printProgStr( str );
  Serial.println(ESC ".(");
}

/********************** MAIN SECTION BELOW **********************/

void setup() {

  // start/stop button
  pinMode(buttonPin, INPUT);

  Serial.begin(9600);

  setState(reset);
}

void loop() {

  if(plotterState == plotting){
    if(digitalRead(buttonPin) == HIGH){
      wantsToEnd = true;
    }
    if(wantsToEnd && !endingInited){
      endingInited = true;
    }

    if(wantsToEnd){
      plotSend();
      Serial.flush();
      Serial.println(";OA;");
      delay(1000);
      if (readSerialString()) {
        while(readSerialString()){
          Serial.flush();
        }
        setState(reset);
      }
    } 
    else {
      if(statusCode < 16) {

        if(millis() > nextDrawMillis){

          /********************** TEXT PLOTTING BELOW **********************/

          if(!textMessageBuffered){
            int textMessageLineNo = 0;
            textLines = 0;
            while(getProgStrLine(textMessage, textMessageLineNo++)){
              writeTextLine(progStrLine);
            }
            textMessageBuffered = true;
          }

          if(!textMessagePlotted){
            plotSend();
            Serial.flush();
            delay(10);
            Serial.println(";OA;");
            nextDrawMillis = millis() + 2000ul; // prevent buffer overflow while waiting
            if (readSerialString()) {
              while(readSerialString()){
                Serial.flush();
              }
              textMessagePlotted = true;
            }
          } 
          else {

            /********************** MAIN DRAWING BELOW **********************/

            setupDrawingWorld();

            double xReal = 0.0;
            double yReal = 0.0;
            double xDist = 0.0;
            double yDist = 0.0;

            if(firstDraw){
              selectPen(1);
              plotPenUp();
              plotPenAt(x,y);
              firstDraw = false;
            }

            penDown = true;

            x=random(-systemWidth/2.0,systemWidth/2.0);
            y=random(-systemHeight/2.0,systemHeight/2.0);

            xDist = x-xOld;
            yDist = y-yOld;

            xDist = abs(xDist);
            yDist = abs(yDist);

            if(xDist > minDistToDraw || yDist > minDistToDraw) {

              xOld = x;
              yOld = y;

              plotPenAt(x,y);

              if(penDown){
                plotPenDown();
              } 
              else{
                plotPenUp();
              }
            }

          }
        } 

      }
      else {
        if(errorCode == 0){
          if(!plotterPing())
            setState(noconnection);
        }
      }
    }
  } 
  else {
    if(errorCode == 0 && plotterState != reset){
      if(millis() > nextPingMillis){
        nextPingMillis = millis() + 2000ul;
        if(!plotterPing())
          setState(noconnection);
      }
    }
  }

  if(errorCode > 15)
    setState(error);

  if(plotterState == reset){
    resetPlotter();
  }

  if(plotterState == waiting){
    if(digitalRead(buttonPin) == HIGH){
        // give feedback, eg by turning on a specific led
      delay(1000);
      startPlotter();
    }
  }
  if(plotterState == noconnection){
    if(plotterPing()){
      plot(";");
      setState(noConnectionReturnState);
    }
    if(digitalRead(buttonPin) == HIGH){
        // give feedback, eg by turning on a specific led
      delay(1000);
      setState(reset);
    }
    delay(100);
  }
  if(plotterState == error){
    if(digitalRead(buttonPin) == HIGH){
        // give feedback, eg by turning on a specific led
      delay(1000);
      errorCode = 0;
      setState(reset);
    }
  }
}

void waitForPlotterBuffer(){
  boolean isBuffering = true;
  while(isBuffering){
    Serial.flush();
    Serial.println(ESC ".B");
    if (readSerialString()) {
      bufferCapacity = atoi(serInStr);
      debugStr(serInStr);
      if(bufferCapacity >= cmdBufferSize+1){
        isBuffering = false;
        setState(plotting);
      } 
      else {
        setState(buffering);
      }
    } 
    else {
      isBuffering = false;
      setState(noconnection);
    }
  }
}

boolean plotterPing(){
  Serial.println(ESC ".Y");
  Serial.flush();
  if (readSerialString()) {
    while(readSerialString()){
      Serial.flush();
    }
  }
  Serial.println(ESC ".O");
  if (readSerialString()) {
    statusCode = atoi(serInStr);
    char msg[128] = "";
    memset( msg, 0, sizeof(msg) );
    strcat(msg, serInStr);
    Serial.flush();
    if (readSerialString()) {
      while(readSerialString()){
        Serial.flush();
      }
    }
    Serial.println(ESC ".B");
    if (readSerialString()) {
      bufferCapacity = atoi(serInStr);
      strcat(msg, "\t");
      strcat(msg, serInStr);
    }
    if(errorCode == 0){
      Serial.flush();
      if (readSerialString()) {
        while(readSerialString()){
          Serial.flush();
        }
      }
      Serial.println(ESC ".E");
      if (readSerialString()) {
        errorCode = atoi(serInStr);
        strcat(msg, "\t");
        strcat(msg, serInStr);
        if (errorCode == 0){
          debugStr(msg);
          return true;
        }
        else{
          logStr(msg);
          return false;
        }
      }
    } 
    else {
      logStr(msg);
      return true;
    }
  } 
  else {
    return false;
  }
}