home‎ > ‎Projects‎ > ‎Moo Machine‎ > ‎

Program

The interpreter and interface logic was written in C, using the Arduino libraries and IDE.  More information is available at http://www.arduino.cc/.  The Arduino Mega is the target platform.

Code


/*
 *
 * MooMachine:  Basic Program for MooMachine, both Editor and Interter
 * Version 0.9
 *
 */
 
#include <EEPROM.h>
 
//Program-wide Variables
#define DEBOUNCEDELAY 10


//Use C++ Defines for Switch and LED Definitions

//Lets start with output LEDs...will be doing 22-52 (even...matches Arduino Mega)
#define D0 22
#define D1 24
#define D2 26
#define D3 28

#define A0 30
#define A1 32
#define A2 34
#define A3 36
#define A4 38
#define A5 40
#define A6 42
#define A7 44
#define A8 46
#define A9 48

#define WAIT 43
#define HLD 45

#define MEMR 47
#define INP 49
#define MI 51
#define OUT 53
#define WO 52
#define INT 50


//Switches (input) will be 23-53 (odd)
#define S0 23
#define S1 25
#define S2 27
#define S3 29
#define S4 31
#define S5 33
#define S6 35
#define S7 37
#define S8 39
#define S9 41


//Input ports, which will use the PWM capabile ports (for now...)

#define RUN 2
#define STEP 3
#define EXAMINE 4
#define EXAMINENXT 5
#define DEPOSIT 6
#define DEPOSITNXT 7

#define RESET 8
#define CLR 9
#define SAVE 10
#define LOAD 11
#define AUX 12


//Static Arrays for Data/Address LEDs and Switches Addresses

byte DataLEDAddr[] = {D0, D1, D2, D3};
int DataLEDAddrSize=4;
byte AddressLEDAddr[] = {A0, A1, A2, A3, A4, A5, A6, A7, A8, A9};
int AddressLEDAddrSize=10;
byte IndicatorLEDAddr[] = {WAIT, HLD, MEMR, INP, MI, OUT, WO, INT};
int IndicatorLEDAddrSize = 8;
byte SwitchAddr[] = {S0, S1, S2, S3, S4, S5, S6, S7, S8, S9};
int SwitchAddrSize=10;
byte SwitchCmdAddr[] = {RUN, STEP, EXAMINE, EXAMINENXT, DEPOSIT, DEPOSITNXT, RESET, CLR, SAVE, LOAD, AUX};
int SwitchCmdAddrSize = 11;
int SwitchPosition[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
int SwitchPositionSize = 10;

//Program Variables
//  Assume 512 instructions (using bytes, although just 4-bit used internally)
//  Assumes 512 memory positions (bytes)
int instructionArray[1024];
int instructionArraySize = 1024;
int memoryArray[1024];
int memoryArraySize = 1024;

//position, represented by int
int instructionPointer = 0;
int memoryPointer = 0;

//Register

int registerValue;
//registerValue=0;


void setup() {
  //Setup LED Pins
  for (byte i=0;i<DataLEDAddrSize;i++) {
    pinMode(DataLEDAddr[i], OUTPUT);
  } 
  for (byte i=0;i<AddressLEDAddrSize;i++) {
    pinMode(AddressLEDAddr[i], OUTPUT);
  } 
  for (byte i=0;i<IndicatorLEDAddrSize;i++) {
    pinMode(AddressLEDAddr[i], OUTPUT);
  } 

 
 
 
 
  //INPUT PINS
  for (byte i=0;i<SwitchAddrSize;i++) {
    //Setup Switch PINS, setting internal pullup resistors
    pinMode(SwitchAddr[i], INPUT);
    digitalWrite(SwitchAddr[i], HIGH);
  }
  for (byte i=0;i<SwitchCmdAddrSize;i++) {
    //Setup Switch PINS, setting internal pullup resistors
    pinMode(SwitchCmdAddr[i], INPUT);
    digitalWrite(SwitchCmdAddr[i], HIGH);
  }
 
  // Fill Instruction Arrays with "13"s (invalid instructions...just in case)

  for (int i=0;i<instructionArraySize;i++) {
    //Setup Switch PINS, setting internal pullup resistors
    instructionArray[i] = 13;
  }


  //Serial Debug
 
    //Setup Serial Communication
   Serial.begin(9600);
  
  
   Serial.println("Setup Done...Ready for Commands");
 
 
}


void loop() {
  //Determine if RUN has been selected
  if (debounceRead(RUN) == LOW) {
   //Serial.println("RUN");
    //Run Routine
    mooRun();
  } else {
   //Serial.println("EDIT");
    //Edit mode..
    mooEdit();
  }
 
 
}


/*
 *
 * mooRun:  Run single step for program in memory
 *
 */
void mooRun() {

    //First, clear data display
     for (byte i=0;i<DataLEDAddrSize;i++) {
        digitalWrite(DataLEDAddr[i], LOW);
      }     
 
    int mooRunReturn;
   
    mooRunReturn = mooExec(instructionArray[instructionPointer]);
 
    if (mooRunReturn != 0) {
       errorHandler();  
     
    } else {
 
      instructionPointer++;
     
    }




 
}
   
   
// mooEdit: Perform any Edits that need to be made (plus update lights)

void mooEdit() {

  //Read Address/Data Switch Positions...since we need accurate switch positions for the rest of this routine
  readSwitch();

  //If Deposit or DepostNext are selected, then run deposit routine
  if (debounceRead(DEPOSIT) == LOW) { 
    //Wait for HIGH (switch to return)
       Serial.println("DEPOSIT");
    while (debounceRead(DEPOSIT) == LOW) {
       true;
    }

    readInst();

    displayDataInstLed();
   
  } else if (debounceRead(DEPOSITNXT) == LOW) {
    //Wait for HIGH (switch to return)
       Serial.println("DEPOSITNXT");
    while (debounceRead(DEPOSITNXT) == LOW) {
        true;
    }
   
    readInst();

    //Increment Instruction Pointer
    instructionPointer++;
   
    displayDataInstLed();
    displayDataAddrLed();
   
  } else if (debounceRead(EXAMINE) == LOW) {
           Serial.println("EXAMINE");
    //Wait for HIGH (switch to return)
    while (debounceRead(EXAMINE) == LOW) {
      true;
    }
   
    readAddr();
   
    displayDataAddrLed();
    displayDataInstLed();
   
  } else if (debounceRead(EXAMINENXT) == LOW) {
       Serial.println("EXAMINENXT");

    //Wait for HIGH (switch to return)
    while (debounceRead(EXAMINENXT) == LOW) {
       true;
    }

    //Increment instruction pointer by one
    instructionPointer++;
   
    //readAddr();
   
    displayDataAddrLed();
    displayDataInstLed();
   
  } else if (debounceRead(RESET) == LOW) {
       Serial.println("RESET");
    //Wait for HIGH (switch to return)
    while (debounceRead(RESET) == LOW) {
       true;
    }
    //Set instruction and memory pointer to address 0
    instructionPointer=0;
    memoryPointer=0;
    displayDataInstLed();
    displayDataAddrLed();

  } else if (debounceRead(CLR) == LOW) {
    Serial.println("CLEAR");
    //Wait for HIGH (switch to return)
    while (debounceRead(CLR) == LOW) {
       true;
    }

    //Clear memory
    clearMemory();
    displayDataInstLed();
    displayDataAddrLed();

  } else if (debounceRead(SAVE) == LOW) {
    Serial.println("SAVE");
    //Wait for HIGH (switch to return)
    while (debounceRead(SAVE) == LOW) {
       true;
    }
   
    saveToROM();
 
//Temporary change to test load switch
  } else if (debounceRead(LOAD) == LOW) {
    Serial.println("LOAD");
    //Wait for HIGH (switch to return)
    while (debounceRead(LOAD) == LOW) {
       true;
    }
   
    //TODO: Wirte routine for Load
    loadFromROM();
   
  }
}


/*
 *  Main Functions
 *
 */


//Read Switch Positions
void readSwitch() {
  for (byte i=0;i<SwitchAddrSize;i++) {
     SwitchPosition[i] = debounceRead(SwitchAddr[i]);
  }
 
}


//Clear memory, both instructions and memory
void clearMemory() {
    for (int i=0; i<instructionArraySize; i++) {
       //Assign null to all instruction positions
       instructionArray[i]=NULL;
    }
    for (int i=0; i<memoryArraySize; i++) {
       //Assign null to all memory positions
       memoryArray[i]=NULL;
    }



// Read an instruction from the switch array, and set the current instruction bit
void readInst() {
    int totalValue=0;
    int currentBitValue=1;
    for (int pin=0; pin<4; pin++) {
        if (SwitchPosition[pin] == LOW) {
           totalValue = totalValue + currentBitValue;
        }
        currentBitValue = currentBitValue*2;
    }
    instructionArray[instructionPointer] = totalValue;
    Serial.print("Instruction: ");
    Serial.println(totalValue);
}

// Read an address from the switch array, and set the current pointer
void readAddr() {
    int totalValue=0;
    int currentBitValue=1;
    for (int pin=0; pin<10; pin++) {
        if (SwitchPosition[pin] == LOW) {
           totalValue = totalValue + currentBitValue;
        }
        currentBitValue = currentBitValue*2;
    }
    instructionPointer = totalValue;

    Serial.print("Address: ");
    Serial.println(totalValue);
}


/*
 *
 *  Low-level Functions
 *
 *
 */


//Update all Datadisplay LEDs to match switch LEDs
//**TODO**: Rewirte to includate data at current instruction pointer!
void displayDataInstLed() {

    if (instructionArray[instructionPointer] == 13) {
        Serial.println("Display NULL VALUE (13) ");
        for (byte i=0;i<4;i++) {
          digitalWrite(DataLEDAddr[i],LOW); // send 0         
        }
    } else {
    Serial.print("Display Data: ");
    Serial.println(instructionArray[instructionPointer]);
    //Heavily modified from http://www.arduino.cc/en/Tutorial/BitMask...although I'm purposly going through the bitmask, and using the size of the
    //Data instruction 
    int mask = 0001;
    for (byte i=0;i<4;i++) {
      if (instructionArray[instructionPointer] & mask){ // if bitwise AND resolves to true
         digitalWrite(DataLEDAddr[i],HIGH); // send 1
      }
      else{ //if bitwise and resolves to false
          digitalWrite(DataLEDAddr[i],LOW); // send 0
      }
      mask <<= 1;
     
    }
   
    }
}


void displayDataAddrLed() {
  //TODO:  there will be an issue, with a 10-bit address pointer.  Probably will have to do something about that mask
  //Display the address of the "instructionPointer" itself..., taken from displayDataInstLed
    Serial.print("Display Data Address: ");
    Serial.println(instructionPointer);


     int mask = 00000001;
     for (byte i=0;i<AddressLEDAddrSize;i++) {
      if (instructionPointer & mask){ // if bitwise AND resolves to true
         digitalWrite(AddressLEDAddr[i],HIGH); // send 1
      }
      else{ //if bitwise and resolves to false
          digitalWrite(AddressLEDAddr[i],LOW); // send 1
      }
      mask <<= 1;
     
    }

}


//DebounceRead...simple routine to debounce a switch
// Input: Pin Number
// Output:  HIGH or LOW
//TODO: Rewrite to be more like Playground example (as this routine will hold up everything else while attempting to debounce...and
//     takes 5ms per read, or 95ms for all switches (1/10th of sec).  Should keep state and delay in global array

int debounceRead(int pinNum) {
    //Simple routine...read the switch, wait
    int state1;
    int state2;
    state1 = digitalRead(pinNum);
    delay(DEBOUNCEDELAY);
    state2 = digitalRead(pinNum);
    while (state1 != state2) {
        delay(DEBOUNCEDELAY);
        state1 = state2;
        state2 = digitalRead(pinNum);
    }
    return state2;
}

// Instruction Run

int mooExec(int instruction) {

  switch( instruction )
    {
    // moo: Search in reverse for MOO command
    case 0:
        {
            Serial.print("Running instruction 0 from Address: ");
            Serial.println(instructionPointer);
            if( instructionPointer == 0 )
                return 1;

            instructionPointer--;    // skip previous command.
            int level = 1;
            while( level > 0 )
            {
                if( instructionPointer == 0 )
                    break;

                instructionPointer--;
           
                if( instructionArray[instructionPointer] == 0 )
                    level++;
                else
                if( instructionArray[instructionPointer] == 7 )  // look for MOO
                    level--;
            }

            if( level != 0 )
                return 1;

            //TEMP ADD:  If successful, I need to decrease pointer by one, so that mail routine will increment by one
            instructionPointer--;
            
            break;  //All was successful, if we reached this point
        }
   
    // mOo: Move memory position back one
    case 1:
            Serial.print("Running instruction 1 from Address: ");
            Serial.println(instructionPointer);
        if( memoryPointer == 0 )
            return 1;
        else
            memoryPointer--;
        break;
       
        Serial.print("Current memory pointer: ");
        Serial.println(memoryPointer);

    // moO: Move memory position up one
    case 2:
            Serial.print("Running instruction 2 from Address: ");
            Serial.println(instructionPointer);
        memoryPointer++;
        //If memory instruction is at end of array
        if( memoryPointer >= memoryArraySize)
        {
            memoryPointer = memoryArraySize;
            memoryPointer--;
        }
        Serial.print("Current memory pointer: ");
        Serial.println(memoryPointer);

        break;
   
    // mOO: Execute block in memory as if it were an instruction
    case 3:
            Serial.print("Running instruction 3 from Address: ");
            Serial.println(instructionPointer);
        if( memoryArray[memoryPointer] == 3 )
            return 1;
       
        mooExec(memoryArray[memoryPointer]);
       
        break;
   
    // Moo: Input/output.  Of memory block is 0, read in value, else write one out
    case 4:
            Serial.print("Running instruction 4 from Address: ");
            Serial.println(instructionPointer);
        if( memoryArray[memoryPointer] != 0 ) {
            // Output Routine
            displayOutput(memoryArray[memoryPointer]);
        }
        else
        {
            //Input Routine
            memoryArray[memoryPointer] = readInput();
        }
        break;
   
    // MOo: Decrement value in memory block by one
    case 5:
            Serial.print("Running instruction 5 from Address: ");
            Serial.println(instructionPointer);
        memoryArray[memoryPointer] = memoryArray[memoryPointer]-1;
        Serial.print("Decrease memory pointer ");
        Serial.print(memoryPointer);
        Serial.print(" to value ");
        Serial.println(memoryArray[memoryPointer]);

        break;
   
    // MoO: Increment value in memory block by one
    case 6:
            Serial.print("Running instruction 6 from Address: ");
            Serial.println(instructionPointer);
            memoryArray[memoryPointer] = memoryArray[memoryPointer]+1;
        Serial.print("Increase memory pointer ");
        Serial.print(memoryPointer);
        Serial.print(" to value ");
        Serial.println(memoryArray[memoryPointer]);


        break;

    // MOO:  If memory value is zero, then skip next command and search for moo command.  If not zero, then continue executing
    case 7:
            Serial.print("Running instruction 7 from Address: ");
            Serial.println(instructionPointer);
        if( memoryArray[memoryPointer] == 0 )
        {
            Serial.println("7: Zero Pointer Encountered");
           int level = 1;
            int prev = 0;
            instructionPointer++;      // have to skip past next command when looking for next moo.
            if( instructionArray[instructionPointer] == 13 )
                break;
            while( level > 0 )
            {
                prev = instructionPointer;
                instructionPointer++;
               
                if( instructionArray[instructionPointer] == 13 )
                    break;
               
                if( instructionArray[instructionPointer] == 7 )
                    level++;
                else if( instructionArray[instructionPointer] == 0 )    // look for moo command.
                {
                    level--;
                    if( prev == 7 )
                        level--;
                }
            }
            if( level != 0 )
                return 1;
        }
        break;
   
    // OOO: Set current memory block to 0
    case 8:
             Serial.print("Running instruction 8 from Address: ");
            Serial.println(instructionPointer);
        memoryArray[memoryPointer] = 0;
        break;

    // MMM: If register has value, put into memory and clear the register, otherwise copy current memory block into register
    case 9:
            Serial.print("Running instruction 9 from Address: ");
            Serial.println(instructionPointer);

        if( registerValue == 0 ) {
           
            registerValue = memoryArray[memoryPointer];
           
        } else {
             memoryArray[memoryPointer] = registerValue; 
             registerValue=0;
        }
        break;

    // OOM: Print current memory as integer (does the same thing as  3 in this case)
    case 10:
            Serial.print("Running instruction 10 from Address: ");
            Serial.println(instructionPointer);

            displayOutput(memoryArray[memoryPointer]);
            break;
   
    // oom: Read an integer (does the same thing as 3 pretty much)
    case 11:
            Serial.print("Running instruction 11 from Address: ");
            Serial.println(instructionPointer);
            memoryArray[memoryPointer] = readInput();
            break;
       

    // bad stuff
    default:
        return 1;
    };
   
    return 0;

}

/*
 * errorHandler:  Some bad happened, so flash Error light, and wait until Run/Stop Switch is in "Stop"
 *
 */


void errorHandler() {
  //Dump debugging information

  Serial.println("Error Occured!");
  Serial.print("Error: instructionPointer: ");
  Serial.println(instructionPointer);
  Serial.print("Error: instruction: ");
  Serial.println(instructionArray[instructionPointer]);

  Serial.print("Error: memoryPointer: ");
  Serial.println(memoryPointer);
  Serial.print("Error: memory: ");
  Serial.println(memoryArray[memoryPointer]);

  //LIght up HLD light (probably should be HLT)
  digitalWrite(HLD,HIGH);
 
  //Wait for Run switch to be turned off (Loop forever until done)
  while (debounceRead(RUN) == LOW) {
     true;
  }
 
  //Turn off HLD light
  digitalWrite(HLD,LOW); 
 
}

//Read Input...read switch configuration, and return the integer.  Only reads "ASCII" value (first 8 bits)

int readInput() {
    //Indicate input is needed...flash input light three times, then leave one
      digitalWrite(INP,HIGH);
      delay(100);
      digitalWrite(INP,LOW);
      delay(100);
      digitalWrite(INP,HIGH);
      delay(100);
      digitalWrite(INP,LOW);
      delay(100);
      digitalWrite(INP,HIGH);
      delay(100);

    //Wait for DEP Toggle.  Loop forever until switch goes low
    while (DEPOSIT == HIGH) {
       true;
    }


    int totalValue=0;
    int currentBitValue=1;
    for (int pin=0; pin<8; pin++) {
        if (SwitchPosition[pin] == LOW) {
           totalValue = totalValue + currentBitValue;
        }
        currentBitValue = currentBitValue*2;
    }
    Serial.print("readInput: ");
    Serial.println(totalValue); 
    digitalWrite(INP,LOW); 


    return totalValue;

}

// displayOutput.  Display the integer passed to the routine
void displayOutput(int displayValue) {
     Serial.print("Display Value: ");
     Serial.println(displayValue);

    //Indicate input is needed...flash input light three times, then leave one
      digitalWrite(OUT,HIGH);
      delay(100);
      digitalWrite(OUT,LOW);
      delay(100);
      digitalWrite(OUT,HIGH);
      delay(100);
      digitalWrite(OUT,LOW);
      delay(100);
      digitalWrite(OUT,HIGH);
      delay(100);
 

     int mask = 00000001;
     for (byte i=0;i<AddressLEDAddrSize;i++) {
      if (displayValue & mask){ // if bitwise AND resolves to true
         digitalWrite(AddressLEDAddr[i],HIGH); // send 1
      }
      else{ //if bitwise and resolves to false
          digitalWrite(AddressLEDAddr[i],LOW); // send 1
      }
      mask <<= 1;
     
    }
   
    //Wait for EXAMING switch to toggle before continuoing
    while (EXAMINE == HIGH) {
       true;
    }
   
    while (EXAMINE == LOW) {
       true;
    }

      digitalWrite(OUT,LOW);
 
}

void saveToROM() {
   //Determine memory "position"

    int totalValue=0;
    int currentBitValue=1;
    for (int pin=0; pin<2; pin++) {
        if (SwitchPosition[pin] == LOW) {
           totalValue = totalValue + currentBitValue;
        }
        currentBitValue = currentBitValue*2;
    }
    int memoryStart;
    memoryStart = totalValue * 1024;

    Serial.print("Saving to EERPOM in location: ");
    Serial.println(memoryStart);
  
    //Clear EEPROM
    int clearStart = memoryStart;
    for (int i = clearStart; i < clearStart+1024; i++)
      EEPROM.write(i, 0);

    //Save current program to eeprom
    int activeProgCounter = 0;
    for (int i = memoryStart; i < memoryStart+1024; i++) {
      EEPROM.write(i, instructionArray[activeProgCounter]);
      activeProgCounter++;
    } 

    Serial.println("Done Saving"); 
}

void loadFromROM() {
       //Determine memory "position"
    int totalValue=0;
    int currentBitValue=1;
    for (int pin=0; pin<2; pin++) {
        if (SwitchPosition[pin] == LOW) {
           totalValue = totalValue + currentBitValue;
        }
        currentBitValue = currentBitValue*2;
    }
    int memoryStart;
    memoryStart = totalValue * 1024;

    Serial.print("Load from memory position: ");
    Serial.println(memoryStart);

    //Clear memroy
    clearMemory();
   
    //Load memory from EEPROM
    int activeProgCounter = 0;
    for (int i = memoryStart; i < memoryStart+1024; i++) {
      instructionArray[activeProgCounter] = EEPROM.read(i);
      activeProgCounter++;
    } 
   
   
    //Setup pointers to beginning
    instructionPointer=0;
    memoryPointer=0;
    displayDataInstLed();
    displayDataAddrLed();

    Serial.println("Done Loading");
}

Comments