SetupLoop.cpp
#include "Flash.h"
#include "serialIF.h"
#include "Interpreter.h"
#include "Arduino.h"
#include "CPLD.h"
// Arduino uses 'setup' and 'loop' instead of 'main'
void setup() {
pinMode(13, OUTPUT);
// Blink LED twice
digitalWrite(13, HIGH);
delay(500);
digitalWrite(13, LOW);
delay(500);
digitalWrite(13, HIGH);
delay(500);
digitalWrite(13, LOW);
}
void loop() {
Interpreter interpreter;
interpreter.Loop();
}
SerialIF.h
#ifndef INCLUDE_SERIALIF_H
#define INCLUDE_SERIALIF_H
// The SerialIF class provides application level access to communication facilities
// c must be:
// > command
// < response
// ! text
// $ payload
// . ready for payload
// Each exchange has an id
// packet ID is used for payloads
class SerialIF
{
public:
SerialIF();
~SerialIF();
public:
// Basic send. See class doc for 'c'. response is a buffer of up to 256. length is 1-256,
bool Send(char c, const uint8_t* response, int16_t length, uint8_t id, uint16_t packetId);
// Basic send. See class doc for 'c'. buffer is a buffer of 256 bytes. length is 1-256,
int16_t Receive(char *pC, uint8_t* buffer, uint8_t* pId, uint16_t *pPacketId);
};
#endif
SerialIF.cpp
#include "SerialIF.h"
#define HEADER_LENGTH (6)
#define TIMEOUT (10000)
#define BAUD_RATE (9600)
///////////////////////////////////////////////////////////////////////////////
//
// Object section
//
SerialIF::SerialIF()
{
Serial.begin(BAUD_RATE);
Serial.setTimeout(TIMEOUT);
}
SerialIF::~SerialIF()
{
Serial.end();
}
///////////////////////////////////////////////////////////////////////////////
//
// Low Level Read/Write section
//
// A single communication consists of a header and the data
// Header is 6 bytes:
// [0] A character:
// '>' PC to Arduino command
// '<' Arduino to PC response
// '!' In progess Arduino -> PC text
// '$' Payload packet (256 bytes unless the last one)
// '.' OK to send next payload packet
// [1] length 1-255, 0 means 256
// [2] 8 bit transaction id
// [3] sum adjustment. Adjust this so the sum of header and data is 0xff
// [4] 2 byte packet # high byte
// [5] 2 byte packet # low byte
//
// The header is hidden from the interface. The user simply used the 'command', 'response',
// 'eventString', or 'buffer' and the proper calling function
//
bool SerialIF::Send(char c, const uint8_t* response, int16_t length, uint8_t id, uint16_t packetId)
{
// Setup up header
uint8_t header[HEADER_LENGTH];
header[0] = c;
header[1] = (uint8_t)length; // 256 converts to 0 in cast
header[2] = id;
header[3] = 0;
header[4] = (byte)(packetId >> 8);
header[5] = (byte)packetId;
// Determine sum for error checking
uint8_t sum = 0;
for (int16_t i = 0; i < HEADER_LENGTH; i++)
{
sum += header[i];
}
for (int16_t i = 0; i < length; i++)
{
sum += response[i];
}
header[3] = (uint8_t)~sum;
// ensure it all gets send
const uint8_t* p = header;
int len = HEADER_LENGTH;
int sent = 0;
while (sent < len)
{
int got = Serial.write(p, len - sent);
if (got < 0 || got > len - sent)
{
digitalWrite(13, HIGH);
return false;
}
sent += got;
p += got;
}
len = length;
p = response;
sent = 0;
while (sent < len)
{
int got = Serial.write(p, len - sent);
if (got < 0 || got > len - sent)
{
digitalWrite(13, HIGH);
return false;
}
sent += got;
p += got;
}
return true;
}
int16_t SerialIF::Receive(char *pC, uint8_t* buffer, uint8_t* pId, uint16_t *pPacketId)
{
uint32_t stopOn = millis() + TIMEOUT;
int16_t received = 0;
int16_t expecting = HEADER_LENGTH;
uint8_t header[HEADER_LENGTH];
uint8_t* p;
// Get header
p = &header[0];
while (millis() < stopOn && received < expecting)
{
size_t got = Serial.readBytes(p, expecting - received);
if (got > (size_t)(expecting - received))
{
digitalWrite(13, HIGH);
return -1;
}
p += got;
received += got;
}
if (received == expecting)
{
// extract the type character
*pC = header[0];
// get the data size
expecting = header[1];
if (expecting == 0)
{
expecting = 256;
}
// get the ID
*pId = header[2]; // return to user
*pPacketId = (header[4] << 8) | header[5];
}
else
{
return -1;
}
// Get the data portion
p = buffer;
*p = 'x'; // destroy first data
received = 0;
while (millis() < stopOn && received < expecting)
{
size_t got = Serial.readBytes(p, expecting - received);
if (got > (size_t)(expecting - received))
{
digitalWrite(13, HIGH);
return -1;
}
received += got;
p += got;
}
if (received == expecting)
{
// ensure the sum is 255
uint8_t sum = 0;
for (int16_t i = 0; i < HEADER_LENGTH; ++i)
{
sum += header[i];
}
for (int16_t i = 0; i < expecting; ++i)
{
sum += buffer[i];
}
if (sum != 255)
{
return -1;
}
}
else
{
return -1;
}
return received;
}
CPLD.h
#ifndef INCLUDE_CPLD_H
#define INCLUDE_CPLD_H
// The CPLD class handles low level access to the CPLD which controls the 39SF020A flash device
class CPLD
{
protected:
CPLD();
// Send CPLD reset sequence
void ResetSequence();
// Update address bits 3:0
void UpdateAddress_3_0(uint32_t addr);
// Update address bits 7:4
void UpdateAddress_7_4(uint32_t addr);
// Update address bits 17:8
void UpdateAddress_17_8(uint32_t addr);
// Update chip control where bits 3-0 are drive, CS*, WR*, and RD*
void UpdateChip(int16_t chip);
// Update the CTRL register that tells which register to pulse data in and out
void UpdateCtrl(int16_t ctrl);
// Swaps a data byte on Din/Dout
uint8_t ReadWrite(uint8_t data);
// Pulse CLK high and low
void PulseClk();
// Pulse nCTRL low and high
void PulseCtrl();
public:
// Control pins directly
bool DirectWrite(uint16_t mask, uint16_t values);
// Read current state of pins
bool DirectRead(uint16_t mask, uint16_t* pValues);
private:
// Update an arbitrary part of the address bits
void UpdateAddress_start_end(uint32_t addr, int16_t startBit, int16_t endBit);
// Keep track of last control address to know which parts to avoid shifting out
int16_t m_lastCtrl;
public:
static const int16_t PIN_nCTRL = 2;
static const int16_t PIN_Dout = 3;
static const int16_t PIN_Din = 4;
static const int16_t PIN_CLK = 5;
static const int16_t PIN_ENABLE = 6;
};
#endif
CPLD.cpp
#include "CPLD.h"
// Adds delay if necessary for viewing pins with DMM
#define SUPER_SLO_MO()
#define LAST_CTRL_INIT (-1)
CPLD::CPLD()
{
m_lastCtrl = LAST_CTRL_INIT;
}
///////////////////////////////////////////////////////////////////////////////
//
// Reset section
//
void CPLD::ResetSequence()
{
// initialize pins before setting output mode
digitalWrite(PIN_ENABLE, HIGH);
digitalWrite(PIN_CLK, HIGH);
digitalWrite(PIN_nCTRL, HIGH);
digitalWrite(PIN_Din, HIGH);
// set pin modes
pinMode(PIN_ENABLE, OUTPUT);
pinMode(PIN_nCTRL, OUTPUT);
pinMode(PIN_Dout, INPUT);
pinMode(PIN_Din, OUTPUT);
pinMode(PIN_CLK, OUTPUT);
// Execute reset sequence
PulseClk();
PulseClk();
digitalWrite(PIN_nCTRL, LOW);
delayMicroseconds(1);
PulseClk();
PulseClk();
PulseClk();
digitalWrite(PIN_nCTRL, HIGH);
digitalWrite(PIN_nCTRL, HIGH);
delayMicroseconds(1);
SUPER_SLO_MO();
digitalWrite(PIN_ENABLE, LOW);
delayMicroseconds(1);
SUPER_SLO_MO();
}
///////////////////////////////////////////////////////////////////////////////
//
// Address Shift Register section
//
void CPLD::UpdateAddress_3_0(uint32_t addr)
{
UpdateCtrl(0x01);
UpdateAddress_start_end(addr, 3, 0);
}
void CPLD::UpdateAddress_7_4(uint32_t addr)
{
UpdateCtrl(0x02);
UpdateAddress_start_end(addr, 7, 4);
}
void CPLD::UpdateAddress_17_8(uint32_t addr)
{
UpdateCtrl(0x03);
UpdateAddress_start_end(addr, 17, 8);
}
void CPLD::UpdateAddress_start_end(uint32_t addr, int16_t endBit, int16_t startBit)
{
int16_t i;
for (i = startBit; i <= endBit; ++i)
{
uint32_t mask = 1L << i;
digitalWrite(PIN_Din, (addr & mask) ? HIGH : LOW);
digitalWrite(PIN_Din, (addr & mask) ? HIGH : LOW); // delay
SUPER_SLO_MO();
PulseClk();
}
}
// Chip bits are:
// 3 drive id not nRD low, or read on rising edge
// 2 nCS
// 1 nWR
// 0 nRD
void CPLD::UpdateChip(int16_t chip)
{
int16_t i;
UpdateCtrl(0x07);
for (i = 0; i < 4; ++i)
{
digitalWrite(PIN_Din, (chip & 1) ? HIGH : LOW);
digitalWrite(PIN_Din, (chip & 1) ? HIGH : LOW); // delay
SUPER_SLO_MO();
PulseClk();
chip >>= 1;
}
PulseCtrl();
}
///////////////////////////////////////////////////////////////////////////////
//
// CPLD Control section
//
// Control register
void CPLD::UpdateCtrl(int16_t ctrl)
{
int16_t i;
digitalWrite(PIN_nCTRL, LOW);
SUPER_SLO_MO();
if (true || m_lastCtrl != ctrl)
{
m_lastCtrl = ctrl;
for (i = 0; i < 3; ++i)
{
int16_t bit = ctrl & 1;
ctrl = ctrl >> 1;
digitalWrite(PIN_Din, bit ? HIGH : LOW);
digitalWrite(PIN_Din, bit ? HIGH : LOW); // delay
SUPER_SLO_MO();
PulseClk();
}
}
else
{
delayMicroseconds(1);
}
digitalWrite(PIN_nCTRL, HIGH);
SUPER_SLO_MO();
}
// clock exchange 8 bits on 'data'->Din and Dout->return.
uint8_t CPLD::ReadWrite(uint8_t data)
{
int16_t i;
uint8_t outData = 0;
UpdateCtrl(0x00);
for (i = 0; i < 8; ++i)
{
digitalWrite(PIN_Din, (data & 1) ? HIGH : LOW);
digitalWrite(PIN_Din, (data & 1) ? HIGH : LOW); // delay
SUPER_SLO_MO();
PulseClk();
outData >>= 1;
if (digitalRead(PIN_Dout) == HIGH)
{
outData |= 0x80;
}
data >>= 1;
}
return outData;
}
// Brings clk high then low
void CPLD::PulseClk()
{
digitalWrite(PIN_CLK, HIGH);
digitalWrite(PIN_CLK, HIGH); // delay
SUPER_SLO_MO();
digitalWrite(PIN_CLK, LOW);
digitalWrite(PIN_CLK, LOW); // delay
SUPER_SLO_MO();
}
// Brings nCTRL low then high -- Use to strobe bus control
void CPLD::PulseCtrl()
{
digitalWrite(PIN_nCTRL, LOW);
digitalWrite(PIN_nCTRL, LOW); // delay
SUPER_SLO_MO();
digitalWrite(PIN_nCTRL, HIGH);
digitalWrite(PIN_nCTRL, HIGH); // delay
SUPER_SLO_MO();
}
///////////////////////////////////////////////////////////////////////////////
//
// Direct Arduino Pin Access section
//
bool CPLD::DirectWrite(uint16_t mask, uint16_t values)
{
for (int i = 0; i < 13; i++)
{
uint16_t bit = 1 << i;
if (mask & bit)
{
digitalWrite(i, (values & bit) ? (HIGH) : (LOW));
}
}
return true;
}
bool CPLD::DirectRead(uint16_t mask, uint16_t* pValues)
{
*pValues = 0;
for (int i = 0; i < 13; i++)
{
uint16_t bit = 1 << i;
if (mask & bit)
{
if (digitalRead(i))
{
*pValues |= bit;
}
}
}
return true;
}
Bus.h
#ifndef INCLUDE_BUS_H
#define INCLUDE_BUS_H
#include "CPLD.h"
// The Bus class provides access to the bus on the output of the CPLD
class Bus : public CPLD
{
public:
Bus();
~Bus();
// Sets the input/output pin mode
virtual bool EnablePins(bool enable);
// Resets the Bus
virtual bool Reset(bool force);
// Write data to *ptr.
// NOTE: This is a NOT toggle bit operation, just sends data to *ptr
// returns true if successful
void Write(uint32_t ptr, uint8_t data);
// Read data at *ptr into *pData
// returns true if successful
void Read(uint32_t, uint8_t* pData);
// Read data at last *ptr into *pData
// returns true if successful
void Read(uint8_t* pData);
// Updates entire address bus
void UpdateAddress(uint32_t addr);
protected:
// Update address bits only on parts that are different
void UpdateAddressDiff(uint32_t addr);
// Pulse RD
void PulseRD();
// Pulse WR
void PulseWR();
private:
// Keep track of last programmed address to know which parts to avoid shifting out
uint32_t m_lastAddr;
// Keep track of whether the CPLD has been reset
bool m_reset;
};
#endif
Bus.cpp
#include "Bus.h"
#define LAST_ADDR_INIT (0xffffffff)
Bus::Bus() : CPLD()
{
m_lastAddr = LAST_ADDR_INIT;
m_reset = false;
}
Bus::~Bus()
{
}
///////////////////////////////////////////////////////////////////////////////
//
// Reset section
//
bool Bus::Reset(bool force)
{
if (force || !m_reset)
{
ResetSequence();
m_lastAddr = LAST_ADDR_INIT;
m_reset = true;
}
return true;
}
bool Bus::EnablePins(bool enable)
{
if (enable)
{
pinMode(PIN_ENABLE, OUTPUT);
pinMode(PIN_nCTRL, OUTPUT);
pinMode(PIN_Dout, INPUT);
pinMode(PIN_Din, OUTPUT);
pinMode(PIN_CLK, OUTPUT);
}
else
{
// TODO when pullups are on board, make all these revert to INPUT
pinMode(PIN_ENABLE, INPUT_PULLUP);
pinMode(PIN_nCTRL, INPUT_PULLUP);
pinMode(PIN_Dout, INPUT);
pinMode(PIN_Din, INPUT_PULLUP);
pinMode(PIN_CLK, INPUT_PULLUP);
}
return true;
}
///////////////////////////////////////////////////////////////////////////////
//
// Basic Operation section
//
void Bus::Write(uint32_t addr, uint8_t data)
{
UpdateAddressDiff(addr);
ReadWrite(data);
PulseWR();
}
void Bus::Read(uint32_t addr, uint8_t* pData)
{
UpdateAddressDiff(addr);
PulseRD();
*pData = ReadWrite(0);
}
void Bus::Read(uint8_t* pData)
{
PulseRD();
*pData = ReadWrite(0);
}
///////////////////////////////////////////////////////////////////////////////
//
// Address Shift Register section
//
// Updates entire address bus
void Bus::UpdateAddress(uint32_t addr)
{
UpdateAddress_3_0(addr);
UpdateAddress_7_4(addr);
UpdateAddress_17_8(addr);
}
// Updates address bus shifting only those shift registers that have changed
void Bus::UpdateAddressDiff(uint32_t addr)
{
if (m_lastAddr == LAST_ADDR_INIT)
{
UpdateAddress(addr);
}
else
{
uint32_t diffs = (uint32_t)(addr ^ m_lastAddr);
if (diffs & 0x0000f)
{
UpdateAddress_3_0(addr);
}
if (diffs & 0x000f)
{
UpdateAddress_7_4(addr);
}
if (diffs & 0x3ff00UL)
{
UpdateAddress_17_8(addr);
}
}
}
///////////////////////////////////////////////////////////////////////////////
//
// Bus Control Control section
//
// D[7:0] -------------------------
// nCS ^^^\_________________/^^^
// nRD ^^^\_________________/^^^
// nWR ^^^^^^^^^^^^^^^^^^^^^^^^^
// read *
// Reads when drive goes high (*)
void Bus::PulseRD()
{
UpdateChip(0xa); // CS, RD
UpdateChip(0x2); // drive, CS, RD
UpdateChip(0xa); // CS, RD
UpdateChip(0xf); // done
}
// D[7:0] -[ ]-
// nCS ^^^\_________________/^^^
// nRD ^^^^^^^^^^^^^^^^^^^^^^^^^
// nWR ^^^^^^^\_________/^^^^^^^
// Writes when nWR goes low
void Bus::PulseWR()
{
UpdateChip(0x3); // drive, CS
UpdateChip(0x1); // drive, CS, WR
UpdateChip(0x3); // drive, CS
UpdateChip(0xf); // done
}
Flash.h
#ifndef INCLUDE_FLASH_H
#define INCLUDE_FLASH_H
#include "Bus.h"
// The Flash class handles application level interface to the flash
class Flash
{
public:
Flash(Bus& bus);
// Resets the CPLD
bool ForceReset();
// Resets the CPLD if it hasn't been reset yet
bool Reset();
// Programs data to *ptr.
// NOTE: This is a toggle bit operation
// i.e. it puts the flash into byte program mode
// and waits for the flash to finish
// returns true if successful
bool Program(uint32_t addr, uint8_t data);
// Read data at *ptr into *pData
// returns true if successful
bool Read(uint32_t addr, uint8_t* pData);
// Erases 4KB block with addr
// NOTE: This is a toggle bit operation
// returns true if successful
bool EraseSector(uint32_t addr);
// Erases entire chip
// NOTE: This is a toggle bit operation
// returns true if successful
bool EraseChip();
protected:
// Reads until the toggle bits stop toggling
// Returns true if the read data matches expected
// Use expected of 0xff for erase operations
bool Toggle(uint8_t expected);
private:
// Low level interface
Bus m_bus;
};
#endif
Flash.cpp
#include "Bus.h"
#include "Flash.h"
Flash::Flash(Bus& bus)
{
m_bus = bus;
}
///////////////////////////////////////////////////////////////////////////////
//
// Byte Access section
//
bool Flash::Program(uint32_t addr, uint8_t data)
{
m_bus.Write(0x5555, 0xaa);
m_bus.Write(0x2aaa, 0x55);
m_bus.Write(0x5555, 0xa0);
m_bus.Write(addr, data);
return Toggle(data);
}
bool Flash::Read(uint32_t addr, uint8_t* pData)
{
m_bus.Read(addr, pData);
return true;
}
///////////////////////////////////////////////////////////////////////////////
//
// Erase section
//
bool Flash::EraseSector(uint32_t addr)
{
m_bus.Write(0x5555, 0xaa);
m_bus.Write(0x2aaa, 0x55);
m_bus.Write(0x5555, 0x80);
m_bus.Write(0x5555, 0xaa);
m_bus.Write(0x2aaa, 0x55);
m_bus.Write(addr, 0x30);
return Toggle(0xff);
m_bus.Write(0x2aaa, 0xf0);
}
bool Flash::EraseChip()
{
m_bus.Write(0x5555, 0xaa);
m_bus.Write(0x2aaa, 0x55);
m_bus.Write(0x5555, 0x80);
m_bus.Write(0x5555, 0xaa);
m_bus.Write(0x2aaa, 0x55);
m_bus.Write(0x5555, 0x10);
return Toggle(0xff);
}
///////////////////////////////////////////////////////////////////////////////
//
// Reset section
//
bool Flash::Reset()
{
return m_bus.Reset(false);
}
bool Flash::ForceReset()
{
return m_bus.Reset(true);
}
///////////////////////////////////////////////////////////////////////////////
//
// Support section
//
bool Flash::Toggle(uint8_t expected)
{
bool toggling = true;
uint8_t data0;
uint8_t data1;
m_bus.Read(&data0);
while (toggling)
{
m_bus.Read(&data1);
if ((data1 ^ data0) & 0x40)
{
// toggle bit toggling
data0 = data1; // set up for next toggle check
}
else
{
toggling = false;
}
}
return data1 == expected;
}
MCUBus.h
#ifndef INCLUDE_MCUBUS_H
#define INCLUDE_MCUBUS_H
#include "Bus.h"
// The MCUBus class is used to allow the flash programmer to test the MCU chip before
// connecting the CPU and SRAM to the bus.
class MCUBus : public Bus
{
public:
MCUBus();
~MCUBus();
// Sets the input/output pin mode
virtual bool EnablePins(bool enable);
// Resets the Bus
virtual bool Reset(bool force);
// Writes 'data' to 16 bit address 'addr'
bool WriteMem(uint16_t addr, uint8_t data);
// Gets pData from 16 bit address 'addr'
bool FetchMem(uint16_t addr, uint8_t *pData);
// Gets pData from 16 bit address 'addr'
bool ReadMem(uint16_t addr, uint8_t *pData);
// Writes 'data' to io port 'port'
bool WriteIO(uint8_t port, uint8_t data);
// Reads 'data' from io port 'port'
bool ReadIO(uint8_t port, uint8_t *pData);
// Sets the HALT line
void HaltLine(bool level);
// Sets the BUSACK line
void BusAckLine(bool level);
// Sets the IOREQ line
void IOReqLine(bool level);
// Sets the MREQ line
void MemReqLine(bool level);
// Sets the M1 line
void M1Line(bool level);
// Sets the CLK line
void Clock(bool level);
protected:
void PulseIORD();
void PulseIOWR();
void PulseFetch();
void PulseMemRD();
void PulseMemWR();
public:
static const int PIN_IOREQ = 7;
static const int PIN_MREQ = 8;
static const int PIN_M1 = 9;
static const int PIN_HALT = 10;
static const int PIN_BUSACK = 11;
static const int PIN_CLOCK = 12;
};
#endif
MCUBus.cpp
#include "MCUBus.h"
//#define SUPER_SLO_MO() delay(1000)
#define SUPER_SLO_MO() delay(1)
//#define SUPER_SLO_MO()
MCUBus::MCUBus()
{
}
MCUBus::~MCUBus()
{
}
// Sets the input/output pin mode
bool MCUBus::EnablePins(bool enable)
{
if (enable)
{
digitalWrite(PIN_HALT, HIGH);
digitalWrite(PIN_MREQ, HIGH);
digitalWrite(PIN_IOREQ, HIGH);
digitalWrite(PIN_M1, HIGH);
digitalWrite(PIN_CLOCK, HIGH);
digitalWrite(PIN_BUSACK, HIGH);
pinMode(PIN_HALT, OUTPUT);
pinMode(PIN_MREQ, OUTPUT);
pinMode(PIN_IOREQ, OUTPUT);
pinMode(PIN_M1, OUTPUT);
pinMode(PIN_CLOCK, OUTPUT);
pinMode(PIN_BUSACK, OUTPUT);
}
else
{
// TODO when pullups are on board, make all these revert to INPUT
pinMode(PIN_HALT, INPUT_PULLUP);
pinMode(PIN_MREQ, INPUT_PULLUP);
pinMode(PIN_IOREQ, INPUT_PULLUP);
pinMode(PIN_M1, INPUT_PULLUP);
pinMode(PIN_CLOCK, INPUT_PULLUP);
pinMode(PIN_BUSACK, INPUT_PULLUP);
}
return Bus::EnablePins(enable);
}
// Resets the Bus
bool MCUBus::Reset(bool force)
{
Clock(HIGH);
Clock(LOW);
Clock(HIGH);
Clock(LOW);
Clock(HIGH);
Clock(LOW);
return Bus::Reset(force);
}
bool MCUBus::WriteMem(uint16_t addr, uint8_t data)
{
UpdateAddressDiff(addr);
ReadWrite(data);
PulseMemWR();
return true;
}
bool MCUBus::FetchMem(uint16_t addr, uint8_t *pData)
{
UpdateAddressDiff(addr);
PulseFetch();
*pData = ReadWrite(0);
return true;
}
bool MCUBus::ReadMem(uint16_t addr, uint8_t *pData)
{
UpdateAddressDiff(addr);
PulseMemRD();
*pData = ReadWrite(0);
return true;
}
bool MCUBus::WriteIO(uint8_t port, uint8_t data)
{
UpdateAddressDiff(port);
ReadWrite(data);
PulseIOWR();
return true;
}
bool MCUBus::ReadIO(uint8_t port, uint8_t *pData)
{
UpdateAddressDiff(port);
PulseIORD();
*pData = ReadWrite(0);
return true;
}
void MCUBus::HaltLine(bool level)
{
digitalWrite(PIN_HALT, level);
}
void MCUBus::BusAckLine(bool level)
{
digitalWrite(PIN_BUSACK, level);
}
void MCUBus::IOReqLine(bool level)
{
digitalWrite(PIN_IOREQ, level);
}
void MCUBus::MemReqLine(bool level)
{
digitalWrite(PIN_MREQ, level);
}
void MCUBus::M1Line(bool level)
{
digitalWrite(PIN_M1, level);
}
void MCUBus::Clock(bool level)
{
digitalWrite(PIN_CLOCK, level);
}
// D[7:0] -------------------------
// CLK ^^^^^^\___/^^^^\____/^^^^
// nIOREQ ^^^\_________________/^^^
// nCS ^^^\_________________/^^^
// nRD ^^^\_________________/^^^
// nWR ^^^^^^^^^^^^^^^^^^^^^^^^^
// read *
// Reads when drive goes high (*)
void MCUBus::PulseIORD()
{
Clock(LOW);
UpdateChip(0xe); // RD
IOReqLine(LOW);
SUPER_SLO_MO();
Clock(HIGH);
UpdateChip(0x6); // drive, RD
SUPER_SLO_MO();
Clock(LOW);
UpdateChip(0xe); // RD
SUPER_SLO_MO();
Clock(HIGH);
SUPER_SLO_MO();
Clock(LOW);
IOReqLine(HIGH);
UpdateChip(0xf); // done
SUPER_SLO_MO();
Clock(HIGH);
SUPER_SLO_MO();
}
// D[7:0] -[ ]-
// CLK ^^^^^^\___/^^^^\____/^^^^
// nIOREQ ^^^\_________________/^^^
// nCS ^^^\_________________/^^^
// nRD ^^^^^^^^^^^^^^^^^^^^^^^^^
// nWR ^^^^^^^\_________/^^^^^^^
// Writes when nWR goes low
void MCUBus::PulseIOWR()
{
Clock(LOW);
UpdateChip(0x7); // drive
IOReqLine(LOW);
SUPER_SLO_MO();
Clock(HIGH);
UpdateChip(0x5); // drive, WR
SUPER_SLO_MO();
Clock(LOW);
UpdateChip(0x7); // drive
UpdateChip(0xf); // done
SUPER_SLO_MO();
Clock(HIGH);
SUPER_SLO_MO();
Clock(LOW);
IOReqLine(HIGH);
SUPER_SLO_MO();
Clock(HIGH);
SUPER_SLO_MO();
}
// D[7:0] -------------------------
// CLK ^^^^^^\___/^^^^\____/^^^^
// nMREQ ^^^\_________________/^^^
// nM1 ^^^\_________________/^^^
// nCS ^^^\_________________/^^^
// nRD ^^^\_________________/^^^
// nWR ^^^^^^^^^^^^^^^^^^^^^^^^^
// read *
// Reads when drive goes high (*)
void MCUBus::PulseFetch()
{
Clock(LOW);
M1Line(LOW);
UpdateChip(0xe); // RD
MemReqLine(LOW);
SUPER_SLO_MO();
Clock(HIGH);
UpdateChip(0x6); // drive, RD
SUPER_SLO_MO();
Clock(LOW);
UpdateChip(0xe); // RD
M1Line(HIGH);
SUPER_SLO_MO();
Clock(HIGH);
SUPER_SLO_MO();
Clock(LOW);
MemReqLine(HIGH);
UpdateChip(0xf); // done
SUPER_SLO_MO();
Clock(HIGH);
SUPER_SLO_MO();
}
// D[7:0] -------------------------
// CLK ^^^^^^\___/^^^^\____/^^^^
// nMREQ ^^^\_________________/^^^
// nM1 ^^^^^^^^^^^^^^^^^^^^^^^^^
// nCS ^^^\_________________/^^^
// nRD ^^^\_________________/^^^
// nWR ^^^^^^^^^^^^^^^^^^^^^^^^^
// read *
// Reads when drive goes high (*)
void MCUBus::PulseMemRD()
{
Clock(LOW);
UpdateChip(0xe); // RD
MemReqLine(LOW);
SUPER_SLO_MO();
Clock(HIGH);
UpdateChip(0x6); // drive, RD
SUPER_SLO_MO();
Clock(LOW);
UpdateChip(0xe); // RD
SUPER_SLO_MO();
Clock(HIGH);
SUPER_SLO_MO();
Clock(LOW);
MemReqLine(HIGH);
UpdateChip(0xf); // done
SUPER_SLO_MO();
Clock(HIGH);
SUPER_SLO_MO();
}
// D[7:0] -[ ]-
// CLK ^^^^^^\___/^^^^\____/^^^^
// nMREQ ^^^\_________________/^^^
// nCS ^^^\_________________/^^^
// nRD ^^^^^^^^^^^^^^^^^^^^^^^^^
// nWR ^^^^^^^\_________/^^^^^^^
// Writes when nWR goes low
void MCUBus::PulseMemWR()
{
Clock(LOW);
UpdateChip(0x7); // drive
MemReqLine(LOW);
SUPER_SLO_MO();
Clock(HIGH);
UpdateChip(0x5); // drive, WR
SUPER_SLO_MO();
Clock(LOW);
UpdateChip(0x7); // drive
UpdateChip(0xf); // done
SUPER_SLO_MO();
Clock(HIGH);
SUPER_SLO_MO();
Clock(LOW);
MemReqLine(HIGH);
SUPER_SLO_MO();
Clock(HIGH);
SUPER_SLO_MO();
}
Exchanger.h
#ifndef INCLUDED_EXCHANGER_H
#define INCLUDED_EXCHANGER_H
#include "SerialIF.h"
// The exchanger handles communication between the PC and the Arduino
class Exchanger {
public:
Exchanger();
~Exchanger();
// Expect a command. User supplied buffer. It provides the actual length received. Returns true on success
bool WaitForCommand(uint8_t* receiveBuffer256, int* pLengthReceived);
// Send a response in sendBuffer256. 'lengthToSend' is 1-255 and 0 means 256
bool SendResponse(const uint8_t* sendBuffer256, uint8_t lengthToSend);
// Sends a payload part. packetId is sequential from 0. lengthToSend is 1-255 and 0 means 256
bool SendPayload(uint16_t packetId, const uint8_t* sendBuffer256, uint8_t lengthToSend);
// Waits for a payload part. pLengthReceived is 1-255 and 0 means 256
bool WaitForPayload(uint16_t expectedPacketId, uint8_t* receiveBuffer256, uint8_t* pLengthReceived);
// Sends a ready to indicate ready for the next payload part
bool SendReady(uint16_t packetId);
// Waits for ready to send next packet. buffer is a buffer that can be destroyed
bool WaitForReady(uint16_t packetId, uint8_t* buffer);
// Sends a text string (up to but not including the NUL terminator)
bool SendText(const char* text);
private:
SerialIF m_serial;
byte m_id;
};
#endif
Exchanger.cpp
#include "Exchanger.h"
Exchanger::Exchanger() : m_serial()
{
}
Exchanger::~Exchanger()
{
}
///////////////////////////////////////////////////////////////////////////////
//
// PC -> Arduiono Receive section
//
bool Exchanger::WaitForCommand(uint8_t* receiveBuffer256, int* pLengthReceived)
{
bool ok = false;
char c;
uint16_t packetId;
uint16_t length = m_serial.Receive(&c, receiveBuffer256, &m_id, &packetId);
if ((c == '>') & (length > 0))
{
*pLengthReceived = length;
ok = true;
}
return ok;
}
bool Exchanger::WaitForReady(uint16_t expectedPacketId, uint8_t* buffer)
{
bool ok = false;
char c;
uint16_t packetId;
int recv = m_serial.Receive(&c, buffer, &m_id, &packetId);
if (c == '.' && packetId == expectedPacketId && recv == 1)
{
ok = true;
}
return ok;
}
bool Exchanger::WaitForPayload(uint16_t expectedPacketId, uint8_t* receiveBuffer256, uint8_t* pLengthReceived)
{
bool ok = false;
char c;
uint16_t packetId;
uint16_t length = m_serial.Receive(&c, receiveBuffer256, &m_id, &packetId);
if (c == '$' && length > 0 && packetId == expectedPacketId)
{
*pLengthReceived = length;
ok = true;
}
return ok;
}
///////////////////////////////////////////////////////////////////////////////
//
// Arduoino -> PC section
//
bool Exchanger::SendResponse(const uint8_t* sendBuffer256, uint8_t lengthToSend)
{
return m_serial.Send('<', sendBuffer256, lengthToSend, m_id, 0);
}
bool Exchanger::SendReady(uint16_t packetId)
{
uint8_t buffer[1];
return m_serial.Send('.', buffer, 1, m_id, packetId);
}
bool Exchanger::SendPayload(uint16_t packetId, const uint8_t* sendBuffer256, uint8_t lengthToSend)
{
int length = lengthToSend;
if (length == 0)
{
length = 256;
}
bool ok = m_serial.Send('$', sendBuffer256, length, m_id, packetId);
return ok;
}
bool Exchanger::SendText(const char* text)
{
int16_t length = strlen(text);
bool ok = m_serial.Send('!', (uint8_t*)text, length, m_id, 0xdead);
return ok;
}
Interpreter.h
#ifndef INCLUDE_INTERPRETER_H
#define INCLUDE_INTERPRETER_H
#include "MCUBus.h"
#include "Flash.h"
#include "SerialIF.h"
#include "Exchanger.h"
class Interpreter
{
public:
Interpreter();
~Interpreter();
// Run the interpreter
void Loop();
// Execute a command
bool Execute(const uint8_t* command, int commmandLength, uint8_t* pResponse, int* pResponseLength);
// Send a diag message up to 100 chars
static void DiagnosticText(const char* format, ...);
protected:
bool CRC(uint32_t addr, uint32_t length, uint32_t* pCRC);
uint32_t IncrementalCRC(uint32_t crc, uint8_t data);
private:
static Interpreter* m_instance;
uint16_t m_configuration;
uint16_t m_status;
MCUBus m_bus;
SerialIF m_serialIF;
Flash m_fp;
Exchanger m_exch;
uint8_t m_id; // rotating transaction ID
};
#endif
Interpreter.cpp
#include "Interpreter.h"
#include "Exchanger.h"
#include "Flash.h"
#include "CRC32.h"
#include "CommandCodeEnum.h"
#include "Commands.h"
#include "Responses.h"
#define BLINK_ON_SUCCESS 0
#define BLINK_ON_FAILURE 0
#define VERBOSE 1
///////////////////////////////////////////////////////////////////////////////
//
// Object section
//
Interpreter::Interpreter() : m_fp(m_bus)
{
m_status = 0;
m_configuration = 0;
m_instance = this;
}
Interpreter::~Interpreter()
{
}
Interpreter* Interpreter::m_instance;
void Interpreter::Loop()
{
uint8_t command[256];
uint8_t response[256];
while (1)
{
int receivedLength;
int responseLength;
if (m_exch.WaitForCommand(command, &receivedLength) > 0)
{
m_fp.Reset();
bool ok = Execute(command, receivedLength, response, &responseLength);
if (ok)
{
m_exch.SendResponse(response, responseLength);
if (BLINK_ON_SUCCESS)
{
// half second beep bo beep
digitalWrite(13, HIGH);
delay(200);
digitalWrite(13, LOW);
delay(100);
digitalWrite(13, HIGH);
delay(200);
digitalWrite(13, LOW);
}
}
else
{
response[0] = '?';
response[1] = 0xde;
response[2] = 0xad;
response[3] = 0xbe;
response[4] = 0xef;
m_exch.SendResponse(response, 5);
if (BLINK_ON_FAILURE)
{
// flutter LED
for (int16_t i = 0; i < 10; ++i)
{
digitalWrite(13, HIGH);
delay(50);
digitalWrite(13, LOW);
delay(50);
}
}
}
}
}
}
void Interpreter::DiagnosticText(const char* format, ...)
{
#define DIAGNOSTIC_TEXT_SIZE 100
char text[DIAGNOSTIC_TEXT_SIZE];
va_list ap;
va_start(ap, format);
vsnprintf(text, DIAGNOSTIC_TEXT_SIZE, format, ap);
va_end(ap);
m_instance->m_exch.SendText(text);
}
///////////////////////////////////////////////////////////////////////////////
//
// Command Dispatch section
//
bool Interpreter::Execute(const uint8_t* command, int commmandLength, uint8_t* pResponse, int* pResponseLength)
{
bool ok = false;
switch (command[0])
{
case NOP:
{
CmdNOP cmd(command, commmandLength);
ok = true;
RespNOP resp(cmd, pResponse);
resp.SetResult(ok);
*pResponseLength = resp.Length();
}
break;
case Status:
{
CmdStatus cmd(command, commmandLength);
ok = true;
RespStatus resp(cmd, pResponse);
uint32_t status = m_configuration;
status <<= 16;
status |= m_status;
resp.SetStatus(status);
resp.SetResult(ok);
*pResponseLength = resp.Length();
}
break;
case Configure:
{
CmdConfigure cmd(command, commmandLength);
ok = true;
m_configuration = (uint16_t)cmd.GetConfig();
RespConfigure resp(cmd, pResponse);
resp.SetResult(resp.Length());
*pResponseLength = resp.Length();
}
break;
case ForceReset:
{
CmdForceReset cmd(command, commmandLength);
ok = m_fp.ForceReset();
RespForceReset resp(cmd, pResponse);
resp.SetResult(ok);
*pResponseLength = resp.Length();
}
break;
case EnablePins:
{
CmdEnablePins cmd(command, commmandLength);
bool enable = cmd.GetEnable();
ok = m_bus.EnablePins(enable);
RespEnablePins resp(cmd, pResponse);
resp.SetResult(ok);
*pResponseLength = resp.Length();
}
break;
case ReadByte:
{
CmdReadByte cmd(command, commmandLength);
uint8_t data;
ok = m_fp.Read(cmd.GetAddress(), &data);
RespReadByte resp(cmd, pResponse);
resp.SetData(data);
resp.SetResult(ok);
*pResponseLength = resp.Length();
}
break;
case WriteByte:
{
CmdWriteByte cmd(command, commmandLength);
m_bus.Write(cmd.GetAddress(), cmd.GetData());
ok = true;
//DiagnosticText("Write byte %05lx <- data-blogger-escaped--="" data-blogger-escaped-addr="cmd.GetAddress();" data-blogger-escaped-break="" data-blogger-escaped-case="" data-blogger-escaped-cmd.getaddress="" data-blogger-escaped-cmd.getdata="" data-blogger-escaped-cmd="" data-blogger-escaped-cmdprogrambyte="" data-blogger-escaped-cmdreadblock="" data-blogger-escaped-command="" data-blogger-escaped-commmandlength="" data-blogger-escaped-for="" data-blogger-escaped-if="" data-blogger-escaped-int32_t="" data-blogger-escaped-length="" data-blogger-escaped-load="" data-blogger-escaped-m_exch.waitforready="" data-blogger-escaped-offset="" data-blogger-escaped-ok="ok" data-blogger-escaped-packet="" data-blogger-escaped-packetid="" data-blogger-escaped-partlen="" data-blogger-escaped-presponse="" data-blogger-escaped-presponselength="resp.Length();" data-blogger-escaped-programbyte:="" data-blogger-escaped-readblock:="" data-blogger-escaped-ready="" data-blogger-escaped-resp.setresult="" data-blogger-escaped-resp="" data-blogger-escaped-respprogrambyte="" data-blogger-escaped-respwritebyte="" data-blogger-escaped-send="" data-blogger-escaped-to="" data-blogger-escaped-uint16_t="" data-blogger-escaped-uint32_t="" data-blogger-escaped-wait="" data-blogger-escaped-while="" data-blogger-escaped-x=""> 256)
{
partLen = 256;
}
for (int i = 0; i < partLen; ++i)
{
uint8_t b;
ok = ok && m_fp.Read(addr + offset + i, &b);
b = (byte)(addr + offset + i);
pResponse[i] = b;
}
// send it out
ok = ok && m_exch.SendPayload(packetId, pResponse, partLen);
// prepare for next packet
offset += partLen;
packetId++;
}
}
RespReadBlock resp(cmd, pResponse);
resp.SetResult(ok);
*pResponseLength = resp.Length();
}
break;
case ProgramBlock:
{
CmdReadBlock cmd(command, commmandLength);
uint32_t addr = cmd.GetAddress();
uint32_t length = cmd.GetLength();
uint32_t offset = 0;
uint16_t packetId = 0;
uint8_t buffer[256];
ok = true;
while (offset < length)
{
if (ok)
{
uint8_t partLen;
ok = ok && m_exch.SendReady(packetId);
ok = ok && m_exch.WaitForPayload(packetId, buffer, &partLen);
int len = partLen;
if (len == 0)
{
len = 256;
}
// program packet
for (int i = 0; i < len; ++i)
{
uint8_t b = buffer[i];
ok = ok && m_fp.Program(addr + offset + i, b);
}
// prepare for next packet
offset += len;
packetId++;
}
}
RespReadBlock resp(cmd, pResponse);
resp.SetResult(ok);
*pResponseLength = resp.Length();
}
break;
case EraseSector:
{
CmdEraseSector cmd(command, commmandLength);
int sector = cmd.GetSector();
int count = cmd.GetCount();
ok = sector >= 0 && sector < 64 && count >= 1 && (sector + count) < 64;
for (int i = sector; i < sector + count; ++i)
{
if (ok)
{
ok = m_fp.EraseSector(sector << 12);
}
}
RespEraseSector resp(cmd, pResponse);
resp.SetResult(ok);
*pResponseLength = resp.Length();
}
break;
case EraseChip:
{
CmdEraseChip cmd(command, commmandLength);
ok = m_fp.EraseChip();
RespEraseChip resp(cmd, pResponse);
resp.SetResult(ok);
*pResponseLength = resp.Length();
}
break;
case VerifyErase:
{
CmdVerifyErase cmd(command, commmandLength);
uint8_t data;
uint32_t errorCount = 0;
uint32_t addr = cmd.GetAddress();
uint32_t length = cmd.GetLength();
ok = true;
for (uint32_t i = 0; i < length; i++)
{
ok = ok && m_fp.Read(addr + i, &data);
if (data != 0xff)
{
//DiagnosticText("Error %d at %x", data, addr + i);
errorCount++;
}
}
RespVerifyErase resp(cmd, pResponse);
resp.SetErrorCount(errorCount);
resp.SetResult(ok);
*pResponseLength = resp.Length();
}
break;
case BlockCRC:
{
CmdBlockCRC cmd(command, commmandLength);
uint8_t data;
uint32_t addr = cmd.GetAddress();
uint32_t length = cmd.GetLength();
uint32_t crc = 0xffffffffUL;
ok = true;
for (uint32_t i = 0; i < length; i++)
{
ok = ok && m_fp.Read(addr + length, &data);
data = 0xff; // TODO remove after test
crc = CRC32::IncrementalCRC(crc, data);
}
RespBlockCRC resp(cmd, pResponse);
resp.SetCRC(crc ^ 0xffffffffUL);
resp.SetResult(ok);
*pResponseLength = resp.Length();
}
break;
case DirectPinRead:
{
CmdDirectPinRead cmd(command, commmandLength);
uint16_t levels;
ok = m_bus.DirectRead(cmd.GetMask(), &levels);
RespDirectPinRead resp(cmd, pResponse);
resp.SetPins(levels);
resp.SetResult(ok);
*pResponseLength = resp.Length();
}
break;
case DirectPinWrite:
{
CmdDirectPinWrite cmd(command, commmandLength);
ok = m_bus.DirectWrite(cmd.GetMask(), cmd.GetLevels());
RespDirectPinWrite resp(cmd, pResponse);
resp.SetResult(ok);
*pResponseLength = resp.Length();
}
break;
case DirectPinMode:
{
CmdDirectPinMode cmd(command, commmandLength);
uint8_t pin = cmd.GetPin();
uint8_t mode = cmd.GetMode();
ok = pin < 14 && (mode == INPUT || mode == INPUT_PULLUP || mode == OUTPUT);
if (ok)
{
pinMode(pin, mode);
}
RespDirectPinMode resp(cmd, pResponse);
resp.SetResult(ok);
*pResponseLength = resp.Length();
}
break;
case ReadMem:
{
CmdReadMem cmd(command, commmandLength);
uint8_t data;
ok = m_bus.ReadMem(cmd.GetAddress(), &data);
RespReadMem resp(cmd, pResponse);
resp.SetData(data);
resp.SetResult(ok);
*pResponseLength = resp.Length();
}
break;
case FetchMem:
{
CmdFetchMem cmd(command, commmandLength);
uint8_t data;
ok = m_bus.FetchMem(cmd.GetAddress(), &data);
RespFetchMem resp(cmd, pResponse);
resp.SetData(data);
resp.SetResult(ok);
*pResponseLength = resp.Length();
}
break;
case WriteMem:
{
CmdWriteMem cmd(command, commmandLength);
ok = m_bus.WriteMem(cmd.GetAddress(), cmd.GetData());
RespWriteMem resp(cmd, pResponse);
resp.SetResult(ok);
*pResponseLength = resp.Length();
}
break;
case ReadPort:
{
CmdReadPort cmd(command, commmandLength);
uint8_t data;
ok = m_bus.ReadIO(cmd.GetPort(), &data);
RespReadPort resp(cmd, pResponse);
resp.SetData(data);
resp.SetResult(ok);
*pResponseLength = resp.Length();
}
break;
case WritePort:
{
CmdWritePort cmd(command, commmandLength);
ok = m_bus.WriteIO(cmd.GetPort(), cmd.GetData());
RespWritePort resp(cmd, pResponse);
resp.SetResult(ok);
*pResponseLength = resp.Length();
}
break;
}
return ok;
}
ArgInfo.h
#ifndef INCLUDED_ARGINFO_H
#define INCLUDED_ARGINFO_H
#include "CommandCodeEnum.h"
struct ArgTypes
{
CommandCodes code;
const char* name;
int location;
int length;
};
// The ArgInfo class contains the information needed for commands and responses to location
// and extract the information in the communication packets
class ArgInfo
{
public:
ArgInfo();
~ArgInfo();
// Gets data from a command
bool CommandExtract(CommandCodes code, int argNo, const uint8_t* buffer, uint32_t* pData);
bool CommandExtract(CommandCodes code, int argNo, const uint8_t* buffer, uint16_t* pData);
bool CommandExtract(CommandCodes code, int argNo, const uint8_t* buffer, uint8_t* pData);
bool CommandExtract(CommandCodes code, int argNo, const uint8_t* buffer, int* pData);
bool CommandExtract(CommandCodes code, int argNo, const uint8_t* buffer, bool* pData);
// Inserts data into a response
bool ResponseInsert(CommandCodes code, int argNo, uint8_t* buffer, uint32_t data);
bool ResponseInsert(CommandCodes code, int argNo, uint8_t* buffer, uint16_t data);
bool ResponseInsert(CommandCodes code, int argNo, uint8_t* buffer, uint8_t data);
bool ResponseInsert(CommandCodes code, int argNo, uint8_t* buffer, int data);
bool ResponseInsert(CommandCodes code, int argNo, uint8_t* buffer, bool data);
// Gets the total length of the command
int CommandLength(CommandCodes code);
// Gets the total length of the response which is the length of the command, the status, and arguments
int ResponseLength(CommandCodes code);
protected:
// Gets the location and length of argument #'argNo' for command of 'commandCode'
bool GetCommandInfo(CommandCodes code, int argNo, int* pLocation, int* pLength);
// Gets the location and length of argument #'argNo' for response of 'commandCode'
bool GetResponseInfo(CommandCodes code, int argNo, int* pLocation, int* pLength);
// Gets the actual data at 'location'
bool ExtractFrom(const uint8_t* buffer, int location, int length, uint32_t* pData);
// Inserts the actual data at 'location'
bool InsertInto(uint8_t* buffer, int location, int length, uint32_t data);
// Number of ArgTypes in COMMAND_ARGS
static int COMMAND_ARGC;
// Number of ArgTypes in RESPONSE_ARGS
static int RESPONSE_ARGC;
// Array of info about command arguments
static ArgTypes COMMAND_ARGS[];
// Array of info abaout response arguments
static ArgTypes RESPONSE_ARGS[];
};
#endif
ArgInfo.cpp
#include "ArgInfo.h"
#include "Interpreter.h" // TODO for diag
// locations start at 0. THey will be set in the c'tor
ArgTypes ArgInfo::COMMAND_ARGS[] =
{
{ Configure, "Configure", 0, 2 },
{ ReadByte, "Address", 0, 3 },
{ WriteByte, "Address", 0, 3 },
{ WriteByte, "Data", 0, 1 },
{ ProgramByte, "Address", 0, 3},
{ ProgramByte, "Data", 0, 1},
{ ReadBlock, "Address", 0, 3},
{ ReadBlock, "Length", 0, 3},
{ ProgramBlock, "Address", 0, 3},
{ ProgramBlock, "Length", 0, 3},
{ EraseSector, "Sector", 0, 1},
{ EraseSector, "Count", 0, 1},
{ VerifyErase, "Address", 0, 3},
{ VerifyErase, "Length", 0, 3},
{ BlockCRC, "Address", 0, 3},
{ BlockCRC, "Length", 0, 3},
{ EnablePins, "Pin", 0, 1},
{ EnablePins, "Mode", 0, 1},
{ DirectPinWrite, "Mask", 0, 2},
{ DirectPinWrite, "Levels", 0, 2},
{ DirectPinRead, "Mask", 0, 2},
{ ReadMem, "Address", 0, 2},
{ FetchMem, "Address", 0, 2},
{ WriteMem, "Address", 0, 2},
{ WriteMem, "Data", 0, 1},
{ ReadPort, "Port", 0, 1},
{ WritePort, "Port", 0, 1},
{ WritePort, "Data", 0, 1},
};
// locations all default to 1. These may not be set in the c'tor
ArgTypes ArgInfo::RESPONSE_ARGS[] =
{
{ ReadByte, "Data", 1, 1 },
{ ReadMem, "Data", 1, 1 },
{ FetchMem, "Data", 1, 1 },
{ ReadPort, "Data", 1, 1 },
{ Status, "Status", 1, 4 },
{ VerifyErase, "ErrorCount", 1, 4 },
{ BlockCRC, "CRC", 1, 4 },
{ DirectPinRead, "Levels", 1, 2 },
};
// Gets sizes at compile time
int ArgInfo::COMMAND_ARGC = sizeof(COMMAND_ARGS) / sizeof(COMMAND_ARGS[0]);
int ArgInfo::RESPONSE_ARGC = sizeof(RESPONSE_ARGS) / sizeof(RESPONSE_ARGS[0]);
ArgInfo::ArgInfo()
{
// Figure out locations from sizes
CommandCodes lastCommandCode = (CommandCodes)-1;
int cumulativeLocation = 1;
for (int i = 0; i < COMMAND_ARGC; ++i)
{
if (COMMAND_ARGS[i].code != lastCommandCode)
{
// add into response
for (int j = 0; j < RESPONSE_ARGC; ++j)
{
if (RESPONSE_ARGS[j].code == lastCommandCode)
{
RESPONSE_ARGS[j].location = cumulativeLocation;
cumulativeLocation += RESPONSE_ARGS[j].length;
}
}
lastCommandCode = COMMAND_ARGS[i].code;
cumulativeLocation = 1;
}
COMMAND_ARGS[i].location = cumulativeLocation;
cumulativeLocation += COMMAND_ARGS[i].length;
}
}
ArgInfo::~ArgInfo()
{
}
int ArgInfo::CommandLength(CommandCodes code)
{
int cumulativeLength = 1;
for (int i = 0; i < COMMAND_ARGC; ++i)
{
CommandCodes thisCommandCode = COMMAND_ARGS[i].code;
if (thisCommandCode < code)
{
}
else if (thisCommandCode == code)
{
cumulativeLength += COMMAND_ARGS[i].length;
}
else
{
//break; // not in order--cannot break
}
}
return cumulativeLength;
}
int ArgInfo::ResponseLength(CommandCodes code)
{
int cumulativeLength = CommandLength(code) + 1; // +1 for result
for (int i = 0; i < RESPONSE_ARGC; ++i)
{
CommandCodes thisCommandCode = RESPONSE_ARGS[i].code;
if (thisCommandCode < code)
{
}
else if (thisCommandCode == code)
{
cumulativeLength += RESPONSE_ARGS[i].length;
}
else
{
//break; // not in order--cannot break
}
}
return cumulativeLength;
}
bool ArgInfo::CommandExtract(CommandCodes code, int argNo, const uint8_t* buffer, uint32_t* pData)
{
int location;
int length;
uint32_t data32 = 0;
bool ok = GetCommandInfo(code, argNo, &location, &length);
if (ok)
{
ok = ExtractFrom(buffer, location, length, &data32);
}
if (ok)
{
*pData = (uint32_t)data32;
}
return ok;
}
bool ArgInfo::CommandExtract(CommandCodes code, int argNo, const uint8_t* buffer, uint16_t* pData)
{
int location;
int length;
uint32_t data32 = 0;
bool ok = GetCommandInfo(code, argNo, &location, &length);
if (ok)
{
ok = ExtractFrom(buffer, location, length, &data32);
}
if (ok)
{
*pData = (uint16_t)data32;
}
return ok;
}
bool ArgInfo::CommandExtract(CommandCodes code, int argNo, const uint8_t* buffer, uint8_t* pData)
{
int location;
int length;
uint32_t data32 = 0;
bool ok = GetCommandInfo(code, argNo, &location, &length);
if (ok)
{
ok = ExtractFrom(buffer, location, length, &data32);
}
if (ok)
{
*pData = (uint8_t)data32;
}
return ok;
}
bool ArgInfo::CommandExtract(CommandCodes code, int argNo, const uint8_t* buffer, int* pData)
{
int location;
int length;
uint32_t data32 = 0;
bool ok = GetCommandInfo(code, argNo, &location, &length);
if (ok)
{
ok = ExtractFrom(buffer, location, length, &data32);
}
if (ok)
{
*pData = (int)data32;
}
return ok;
}
bool ArgInfo::CommandExtract(CommandCodes code, int argNo, const uint8_t* buffer, bool* pData)
{
int location;
int length;
uint32_t data32 = 0;
bool ok = GetCommandInfo(code, argNo, &location, &length);
if (ok)
{
ok = ExtractFrom(buffer, location, length, &data32);
}
if (ok)
{
*pData = data32 != 0;
}
return ok;
}
bool ArgInfo::ResponseInsert(CommandCodes code, int argNo, uint8_t* buffer, uint32_t data)
{
int location;
int length;
uint32_t data32 = data;
bool ok = GetResponseInfo(code, argNo, &location, &length);
if (ok)
{
ok = InsertInto(buffer, location, length, data32);
}
return ok;
}
bool ArgInfo::ResponseInsert(CommandCodes code, int argNo, uint8_t* buffer, uint16_t data)
{
int location;
int length;
uint32_t data32 = data;
bool ok = GetResponseInfo(code, argNo, &location, &length);
if (ok)
{
ok = InsertInto(buffer, location, length, data32);
}
return ok;
}
bool ArgInfo::ResponseInsert(CommandCodes code, int argNo, uint8_t* buffer, uint8_t data)
{
int location;
int length;
uint32_t data32 = data;
bool ok = GetResponseInfo(code, argNo, &location, &length);
if (ok)
{
ok = InsertInto(buffer, location, length, data32);
}
return ok;
}
bool ArgInfo::ResponseInsert(CommandCodes code, int argNo, uint8_t* buffer, int data)
{
int location;
int length;
uint32_t data32 = data;
bool ok = GetResponseInfo(code, argNo, &location, &length);
if (ok)
{
ok = InsertInto(buffer, location, length, data32);
}
return ok;
}
bool ArgInfo::ResponseInsert(CommandCodes code, int argNo, uint8_t* buffer, bool data)
{
int location;
int length;
uint32_t data32 = data;
bool ok = GetResponseInfo(code, argNo, &location, &length);
if (ok)
{
ok = InsertInto(buffer, location, length, data32 ? 1 : 0);
}
return ok;
}
bool ArgInfo::GetCommandInfo(CommandCodes code, int argNo, int* pLocation, int* pLength)
{
int i = 0;
while (i < COMMAND_ARGC && COMMAND_ARGS[i].code != code)
{
++i;
}
if (i == COMMAND_ARGC)
{
return false;
}
int argC = 0;
while (i < COMMAND_ARGC && COMMAND_ARGS[i].code == code && argC < argNo)
{
++i;
++argC;
}
if (i == COMMAND_ARGC || COMMAND_ARGS[i].code != code)
{
return false;
}
*pLocation = COMMAND_ARGS[i].location;
*pLength = COMMAND_ARGS[i].length;
return true;
}
bool ArgInfo::GetResponseInfo(CommandCodes code, int argNo, int* pLocation, int* pLength)
{
int i = 0;
while (i < RESPONSE_ARGC && RESPONSE_ARGS[i].code != code)
{
++i;
}
if (i == RESPONSE_ARGC)
{
return false;
}
int argC = 0;
while (i < RESPONSE_ARGC && RESPONSE_ARGS[i].code == code && argC < argNo)
{
++i;
++argC;
}
if (i == RESPONSE_ARGC || RESPONSE_ARGS[i].code != code)
{
return false;
}
*pLocation = RESPONSE_ARGS[i].location;
*pLength = RESPONSE_ARGS[i].length;
return true;
}
bool ArgInfo::ExtractFrom(const uint8_t* buffer, int location, int length, uint32_t* pData)
{
bool ok = length <= 4 && location >= 0 && location < 256;
if (ok)
{
uint32_t data = 0;
for (int i = location; i < location + length; ++i)
{
data <<= 8;
data |= buffer[i];
}
*pData = data;
}
return ok;
}
bool ArgInfo::InsertInto(uint8_t* buffer, int location, int length, uint32_t data)
{
bool ok = length <= 4 && location >= 0 && (location+length) < 256;
if (ok)
{
for (int i = location + length - 1; i >= location; --i)
{
buffer[i] = (uint8_t)data;
data >>= 8;
}
}
return ok;
}
Commands.h
#ifndef INCLUDED_COMMANDS_H
#define INCLUDED_COMMANDS_H
#include "CmdResp.h"
#include "ArgInfo.h"
// Abstract base class for all commands
class Command : public CmdResp
{
public:
// Gets the CommandCode for the command
CommandCodes Code();
// Gets the length of the buffer
int Length();
// Gets the buffer
const byte* Buffer();
protected:
Command(const byte* buffer, int length);
const byte* m_buffer;
int m_length;
//static ArgInfo argInfo;
};
// The rest of these are derived command classes
class CmdNOP : public Command
{
public:
CmdNOP(const byte* buffer, int length);
protected:
static const CommandCodes MY_CODE = NOP;
};
class CmdStatus : public Command
{
public:
CmdStatus(const byte* buffer, int length);
protected:
static const CommandCodes MY_CODE = Status;
};
class CmdConfigure : public Command
{
public:
CmdConfigure(const byte* buffer, int length);
uint16_t GetConfig();
protected:
static const CommandCodes MY_CODE = Configure;
};
class CmdForceReset : public Command
{
public:
CmdForceReset(const byte* buffer, int length);
protected:
static const CommandCodes MY_CODE = ForceReset;
};
class CmdEnablePins : public Command
{
public:
CmdEnablePins(const byte* buffer, int length);
bool GetEnable();
protected:
static const CommandCodes MY_CODE = EnablePins;
};
class CmdReadByte : public Command
{
public:
CmdReadByte(const byte* buffer, int length);
uint32_t GetAddress();
protected:
static const CommandCodes MY_CODE = ReadByte;
};
class CmdWriteByte : public Command
{
public:
CmdWriteByte(const byte* buffer, int length);
uint32_t GetAddress();
uint8_t GetData();
protected:
static const CommandCodes MY_CODE = WriteByte;
};
class CmdProgramByte : public Command
{
public:
CmdProgramByte(const byte* buffer, int length);
uint32_t GetAddress();
uint8_t GetData();
protected:
static const CommandCodes MY_CODE = ProgramByte;
};
class CmdReadBlock : public Command
{
public:
CmdReadBlock(const byte* buffer, int length);
uint32_t GetAddress();
uint32_t GetLength();
protected:
static const CommandCodes MY_CODE = ReadBlock;
};
class CmdProgramBlock : public Command
{
public:
CmdProgramBlock(const byte* buffer, int length);
uint32_t GetAddress();
uint32_t GetLength();
protected:
static const CommandCodes MY_CODE = ProgramBlock;
};
class CmdEraseSector : public Command
{
public:
CmdEraseSector(const byte* buffer, int length);
uint8_t GetSector();
uint8_t GetCount();
protected:
static const CommandCodes MY_CODE = EraseSector;
};
class CmdEraseChip : public Command
{
public:
CmdEraseChip(const byte* buffer, int length);
protected:
static const CommandCodes MY_CODE = EraseChip;
};
class CmdVerifyErase : public Command
{
public:
CmdVerifyErase(const byte* buffer, int length);
uint32_t GetAddress();
uint32_t GetLength();
protected:
static const CommandCodes MY_CODE = VerifyErase;
};
class CmdBlockCRC : public Command
{
public:
CmdBlockCRC(const byte* buffer, int length);
uint32_t GetAddress();
uint32_t GetLength();
protected:
static const CommandCodes MY_CODE = BlockCRC;
};
class CmdDirectPinRead : public Command
{
public:
CmdDirectPinRead(const byte* buffer, int length);
uint16_t GetMask();
protected:
static const CommandCodes MY_CODE = DirectPinRead;
};
class CmdDirectPinWrite : public Command
{
public:
CmdDirectPinWrite(const byte* buffer, int length);
uint16_t GetMask();
uint16_t GetLevels();
protected:
static const CommandCodes MY_CODE = DirectPinWrite;
};
class CmdDirectPinMode : public Command
{
public:
CmdDirectPinMode(const byte* buffer, int length);
uint8_t GetPin();
uint8_t GetMode();
protected:
static const CommandCodes MY_CODE = DirectPinMode;
};
class CmdReadMem : public Command
{
public:
CmdReadMem(const byte* buffer, int length);
uint16_t GetAddress();
protected:
static const CommandCodes MY_CODE = ReadMem;
};
class CmdFetchMem : public Command
{
public:
CmdFetchMem(const byte* buffer, int length);
uint16_t GetAddress();
protected:
static const CommandCodes MY_CODE = FetchMem;
};
class CmdWriteMem : public Command
{
public:
CmdWriteMem(const byte* buffer, int length);
uint16_t GetAddress();
uint8_t GetData();
protected:
static const CommandCodes MY_CODE = WriteMem;
};
class CmdReadPort : public Command
{
public:
CmdReadPort(const byte* buffer, int length);
uint8_t GetPort();
protected:
static const CommandCodes MY_CODE = ReadPort;
};
class CmdWritePort : public Command
{
public:
CmdWritePort(const byte* buffer, int length);
uint8_t GetPort();
uint8_t GetData();
protected:
static const CommandCodes MY_CODE = WritePort;
};
#endif
Commands.cpp
#include "Commands.h"
Command::Command(const byte* buffer, int length) : m_buffer(buffer), m_length(length)
{
}
CommandCodes Command::Code()
{
return (CommandCodes)m_buffer[0];
}
int Command::Length()
{
return m_length;
}
const byte* Command::Buffer()
{
return m_buffer;
}
ArgInfo CmdResp::argInfo;
CmdNOP::CmdNOP(const byte* buffer, int length) : Command(buffer, length) { }
CmdStatus::CmdStatus(const byte* buffer, int length) : Command(buffer, length) { }
CmdConfigure::CmdConfigure(const byte* buffer, int length) : Command(buffer, length) { }
uint16_t CmdConfigure::GetConfig()
{
uint16_t data;
argInfo.CommandExtract(MY_CODE, 0, m_buffer, &data);
return data;
}
CmdForceReset::CmdForceReset(const byte* buffer, int length) : Command(buffer, length) { }
CmdEnablePins::CmdEnablePins(const byte* buffer, int length) : Command(buffer, length) { }
bool CmdEnablePins::GetEnable()
{
bool data;
argInfo.CommandExtract(MY_CODE, 0, m_buffer, &data);
return data;
}
CmdReadByte::CmdReadByte(const byte* buffer, int length) : Command(buffer, length) { }
uint32_t CmdReadByte::GetAddress()
{
uint32_t data;
argInfo.CommandExtract(MY_CODE, 0, m_buffer, &data);
return data;
}
CmdWriteByte::CmdWriteByte(const byte* buffer, int length) : Command(buffer, length) { }
uint32_t CmdWriteByte::GetAddress()
{
uint32_t data;
argInfo.CommandExtract(MY_CODE, 0, m_buffer, &data);
return data;
}
uint8_t CmdWriteByte::GetData()
{
uint8_t data;
argInfo.CommandExtract(MY_CODE, 1, m_buffer, &data);
return data;
}
CmdProgramByte::CmdProgramByte(const byte* buffer, int length) : Command(buffer, length) { }
uint32_t CmdProgramByte::GetAddress()
{
uint32_t data;
argInfo.CommandExtract(MY_CODE, 0, m_buffer, &data);
return data;
}
uint8_t CmdProgramByte::GetData()
{
uint8_t data;
argInfo.CommandExtract(MY_CODE, 1, m_buffer, &data);
return data;
}
CmdReadBlock::CmdReadBlock(const byte* buffer, int length) : Command(buffer, length) { }
uint32_t CmdReadBlock::GetAddress()
{
uint32_t data;
argInfo.CommandExtract(MY_CODE, 0, m_buffer, &data);
return data;
}
uint32_t CmdReadBlock::GetLength()
{
uint32_t data;
argInfo.CommandExtract(MY_CODE, 1, m_buffer, &data);
return data;
}
CmdProgramBlock::CmdProgramBlock(const byte* buffer, int length) : Command(buffer, length) { }
uint32_t CmdProgramBlock::GetAddress()
{
uint32_t data;
argInfo.CommandExtract(MY_CODE, 0, m_buffer, &data);
return data;
}
uint32_t CmdProgramBlock::GetLength()
{
uint32_t data;
argInfo.CommandExtract(MY_CODE, 1, m_buffer, &data);
return data;
}
CmdEraseSector::CmdEraseSector(const byte* buffer, int length) : Command(buffer, length) { }
uint8_t CmdEraseSector::GetSector()
{
uint8_t data;
argInfo.CommandExtract(MY_CODE, 0, m_buffer, &data);
return data;
}
uint8_t CmdEraseSector::GetCount()
{
uint8_t data;
argInfo.CommandExtract(MY_CODE, 1, m_buffer, &data);
return data;
}
CmdEraseChip::CmdEraseChip(const byte* buffer, int length) : Command(buffer, length) { }
CmdVerifyErase::CmdVerifyErase(const byte* buffer, int length) : Command(buffer, length) { }
uint32_t CmdVerifyErase::GetAddress()
{
uint32_t data;
argInfo.CommandExtract(MY_CODE, 0, m_buffer, &data);
return data;
}
uint32_t CmdVerifyErase::GetLength()
{
uint32_t data;
argInfo.CommandExtract(MY_CODE, 1, m_buffer, &data);
return data;
}
CmdBlockCRC::CmdBlockCRC(const byte* buffer, int length) : Command(buffer, length) { }
uint32_t CmdBlockCRC::GetAddress()
{
uint32_t data;
argInfo.CommandExtract(MY_CODE, 0, m_buffer, &data);
return data;
}
uint32_t CmdBlockCRC::GetLength()
{
uint32_t data;
argInfo.CommandExtract(MY_CODE, 1, m_buffer, &data);
return data;
}
CmdDirectPinRead::CmdDirectPinRead(const byte* buffer, int length) : Command(buffer, length) { }
uint16_t CmdDirectPinRead::GetMask()
{
uint16_t data;
argInfo.CommandExtract(MY_CODE, 0, m_buffer, &data);
return data;
}
CmdDirectPinWrite::CmdDirectPinWrite(const byte* buffer, int length) : Command(buffer, length) { }
uint16_t CmdDirectPinWrite::GetMask()
{
uint16_t data;
argInfo.CommandExtract(MY_CODE, 0, m_buffer, &data);
return data;
}
uint16_t CmdDirectPinWrite::GetLevels()
{
uint16_t data;
argInfo.CommandExtract(MY_CODE, 1, m_buffer, &data);
return data;
}
CmdDirectPinMode::CmdDirectPinMode(const byte* buffer, int length) : Command(buffer, length) { }
uint8_t CmdDirectPinMode::GetPin()
{
uint8_t data;
argInfo.CommandExtract(MY_CODE, 0, m_buffer, &data);
return data;
}
uint8_t CmdDirectPinMode::GetMode()
{
uint8_t data;
argInfo.CommandExtract(MY_CODE, 1, m_buffer, &data);
return data;
}
CmdReadMem::CmdReadMem(const byte* buffer, int length) : Command(buffer, length) { }
uint16_t CmdReadMem::GetAddress()
{
uint16_t data;
argInfo.CommandExtract(MY_CODE, 0, m_buffer, &data);
return data;
}
CmdFetchMem::CmdFetchMem(const byte* buffer, int length) : Command(buffer, length) { }
uint16_t CmdFetchMem::GetAddress()
{
uint16_t data;
argInfo.CommandExtract(MY_CODE, 0, m_buffer, &data);
return data;
}
CmdWriteMem::CmdWriteMem(const byte* buffer, int length) : Command(buffer, length) { }
uint16_t CmdWriteMem::GetAddress()
{
uint16_t data;
argInfo.CommandExtract(MY_CODE, 0, m_buffer, &data);
return data;
}
uint8_t CmdWriteMem::GetData()
{
uint8_t data;
argInfo.CommandExtract(MY_CODE, 1, m_buffer, &data);
return data;
}
CmdReadPort::CmdReadPort(const byte* buffer, int length) : Command(buffer, length) { }
uint8_t CmdReadPort::GetPort()
{
uint8_t data;
argInfo.CommandExtract(MY_CODE, 0, m_buffer, &data);
return data;
}
CmdWritePort::CmdWritePort(const byte* buffer, int length) : Command(buffer, length) { }
uint8_t CmdWritePort::GetPort()
{
uint8_t data;
argInfo.CommandExtract(MY_CODE, 0, m_buffer, &data);
return data;
}
uint8_t CmdWritePort::GetData()
{
uint8_t data;
argInfo.CommandExtract(MY_CODE, 1, m_buffer, &data);
return data;
}
Responses.h
#ifndef INCLUDED_RESPONSES_H
#define INCLUDED_RESPONSES_H
#include "Commands.h"
#include "CommandCodeEnum.h"
#include "CmdResp.h"
// Abstract base class for all responses
class Response : public CmdResp
{
protected:
Response(Command& command, uint8_t* buffer256);
public:
void SetResult(int result);
int Length();
CommandCodes Code();
protected:
Command& m_command;
uint8_t* m_buffer256;
//static ArgInfo argInfo;
};
// The rest of these are derived response classes
class RespNOP : public Response
{
public:
RespNOP(CmdNOP& cmd, uint8_t* buffer256);
};
class RespStatus : public Response
{
public:
RespStatus(CmdStatus& cmd, uint8_t* buffer256);
bool SetStatus(uint32_t data);
};
class RespConfigure : public Response
{
public:
RespConfigure(CmdConfigure& cmd, uint8_t* buffer256);
};
class RespForceReset : public Response
{
public:
RespForceReset(CmdForceReset& cmd, uint8_t* buffer256);
};
class RespEnablePins : public Response
{
public:
RespEnablePins(CmdEnablePins& cmd, uint8_t* buffer256);
};
class RespReadByte : public Response
{
public:
RespReadByte(CmdReadByte& cmd, uint8_t* buffer256);
bool SetData(uint8_t data);
};
class RespWriteByte : public Response
{
public:
RespWriteByte(CmdWriteByte& cmd, uint8_t* buffer256);
};
class RespProgramByte : public Response
{
public:
RespProgramByte(CmdProgramByte& cmd, uint8_t* buffer256);
};
class RespReadBlock : public Response
{
public:
RespReadBlock(CmdReadBlock& cmd, uint8_t* buffer256);
};
class RespProgramBlock : public Response
{
public:
RespProgramBlock(CmdProgramBlock& cmd, uint8_t* buffer256);
};
class RespEraseSector : public Response
{
public:
RespEraseSector(CmdEraseSector& cmd, uint8_t* buffer256);
};
class RespEraseChip : public Response
{
public:
RespEraseChip(CmdEraseChip& cmd, uint8_t* buffer256);
};
class RespVerifyErase : public Response
{
public:
RespVerifyErase(CmdVerifyErase& cmd, uint8_t* buffer256);
bool SetErrorCount(uint32_t data);
};
class RespBlockCRC : public Response
{
public:
RespBlockCRC(CmdBlockCRC& cmd, uint8_t* buffer256);
bool SetCRC(uint32_t crc);
};
class RespDirectPinRead : public Response
{
public:
RespDirectPinRead(CmdDirectPinRead& cmd, uint8_t* buffer256);
bool SetPins(uint16_t pins);
};
class RespDirectPinWrite : public Response
{
public:
RespDirectPinWrite(CmdDirectPinWrite& cmd, uint8_t* buffer256);
};
class RespDirectPinMode : public Response
{
public:
RespDirectPinMode(CmdDirectPinMode& cmd, uint8_t* buffer256);
};
class RespReadMem : public Response
{
public:
RespReadMem(CmdReadMem& cmd, uint8_t* buffer256);
bool SetData(uint8_t data);
};
class RespFetchMem : public Response
{
public:
RespFetchMem(CmdFetchMem& cmd, uint8_t* buffer256);
bool SetData(uint8_t data);
};
class RespWriteMem : public Response
{
public:
RespWriteMem(CmdWriteMem& cmd, uint8_t* buffer256);
};
class RespReadPort : public Response
{
public:
RespReadPort(CmdReadPort& cmd, uint8_t* buffer256);
bool SetData(uint8_t data);
};
class RespWritePort : public Response
{
public:
RespWritePort(CmdWritePort& cmd, uint8_t* buffer256);
};
#endif
Responses.cpp
#include "Responses.h"
Response::Response(Command& command, uint8_t* buffer256) : m_command(command), m_buffer256(buffer256)
{
memcpy(m_buffer256, m_command.Buffer(), m_command.Length());
}
void Response::SetResult(int result)
{
int length = Length();
m_buffer256[length - 1] = result;
}
int Response::Length()
{
return argInfo.ResponseLength(m_command.Code());
}
CommandCodes Response::Code()
{
return m_command.Code();
}
RespNOP::RespNOP(CmdNOP& cmd, uint8_t* buffer256) : Response(cmd, buffer256) {}
RespStatus::RespStatus(CmdStatus& cmd, uint8_t* buffer256) : Response(cmd, buffer256) {}
RespConfigure::RespConfigure(CmdConfigure& cmd, uint8_t* buffer256) : Response(cmd, buffer256) {}
RespForceReset::RespForceReset(CmdForceReset& cmd, uint8_t* buffer256) : Response(cmd, buffer256) {}
RespEnablePins::RespEnablePins(CmdEnablePins& cmd, uint8_t* buffer256) : Response(cmd, buffer256) {}
RespReadByte::RespReadByte(CmdReadByte& cmd, uint8_t* buffer256) : Response(cmd, buffer256) {}
RespWriteByte::RespWriteByte(CmdWriteByte& cmd, uint8_t* buffer256) : Response(cmd, buffer256) {}
RespProgramByte::RespProgramByte(CmdProgramByte& cmd, uint8_t* buffer256) : Response(cmd, buffer256) {}
RespReadBlock::RespReadBlock(CmdReadBlock& cmd, uint8_t* buffer256) : Response(cmd, buffer256) {}
RespProgramBlock::RespProgramBlock(CmdProgramBlock& cmd, uint8_t* buffer256) : Response(cmd, buffer256) {}
RespEraseSector::RespEraseSector(CmdEraseSector& cmd, uint8_t* buffer256) : Response(cmd, buffer256) {}
RespEraseChip::RespEraseChip(CmdEraseChip& cmd, uint8_t* buffer256) : Response(cmd, buffer256) {}
RespVerifyErase::RespVerifyErase(CmdVerifyErase& cmd, uint8_t* buffer256) : Response(cmd, buffer256) {}
RespBlockCRC::RespBlockCRC(CmdBlockCRC& cmd, uint8_t* buffer256) : Response(cmd, buffer256) {}
RespDirectPinRead::RespDirectPinRead(CmdDirectPinRead& cmd, uint8_t* buffer256) : Response(cmd, buffer256) {}
RespDirectPinWrite::RespDirectPinWrite(CmdDirectPinWrite& cmd, uint8_t* buffer256) : Response(cmd, buffer256) {}
RespDirectPinMode::RespDirectPinMode(CmdDirectPinMode& cmd, uint8_t* buffer256) : Response(cmd, buffer256) {}
RespReadMem::RespReadMem(CmdReadMem& cmd, uint8_t* buffer256) : Response(cmd, buffer256) {}
RespFetchMem::RespFetchMem(CmdFetchMem& cmd, uint8_t* buffer256) : Response(cmd, buffer256) {}
RespWriteMem::RespWriteMem(CmdWriteMem& cmd, uint8_t* buffer256) : Response(cmd, buffer256) {}
RespReadPort::RespReadPort(CmdReadPort& cmd, uint8_t* buffer256) : Response(cmd, buffer256) {}
RespWritePort::RespWritePort(CmdWritePort& cmd, uint8_t* buffer256) : Response(cmd, buffer256) {}
bool RespStatus::SetStatus(uint32_t data)
{
return argInfo.ResponseInsert(Code(), 0, m_buffer256, data);
}
bool RespReadByte::SetData(uint8_t data)
{
return argInfo.ResponseInsert(Code(), 0, m_buffer256, data);
}
bool RespReadMem::SetData(uint8_t data)
{
return argInfo.ResponseInsert(Code(), 0, m_buffer256, data);
}
bool RespFetchMem::SetData(uint8_t data)
{
return argInfo.ResponseInsert(Code(), 0, m_buffer256, data);
}
bool RespReadPort::SetData(uint8_t data)
{
return argInfo.ResponseInsert(Code(), 0, m_buffer256, data);
}
bool RespVerifyErase::SetErrorCount(uint32_t data)
{
return argInfo.ResponseInsert(Code(), 0, m_buffer256, data);
}
bool RespBlockCRC::SetCRC(uint32_t crc)
{
return argInfo.ResponseInsert(Code(), 0, m_buffer256, crc);
}
bool RespDirectPinRead::SetPins(uint16_t pins)
{
return argInfo.ResponseInsert(Code(), 0, m_buffer256, pins);
}
CmdResp.h
#ifndef INCLUDED_CMDRESP_H
#define INCLUDED_CMDRESP_H
#include "ArgInfo.h"
class CmdResp
{
protected:
static ArgInfo argInfo;
};
#endif
CommandCodeEnum.h
#ifndef INCLUDED_COMMANDCODEENUM_H
#define INCLUDED_COMMANDCODEENUM_H
enum CommandCodes
{
NOP = 0x00,
Status = 0x01,
Configure = 0x02,
ForceReset = 0x08,
EnablePins = 0x09,
ReadByte = 0x10,
WriteByte = 0x11,
ProgramByte = 0x12,
ReadBlock = 0x20,
ProgramBlock = 0x22,
EraseSector = 0x30,
EraseChip = 0x33,
VerifyErase = 0x40,
BlockCRC = 0x41,
DirectPinRead = 0x80,
DirectPinWrite = 0x81,
DirectPinMode = 0x82,
ReadMem = 0x90,
FetchMem = 0x91,
WriteMem = 0x92,
ReadPort = 0x98,
WritePort = 0x99
};
#endif
No comments:
Post a Comment