--- /dev/null
+default: test
+
+*.o:*.hh
+
+test: test.o tape_block.o silent_code.o data_block.cpp data_block_0.o
+ g++ -o$@ $^
+
+
+clean:
+ rm -rf test *.o *~
\ No newline at end of file
--- /dev/null
+#include <stdlib.h>
+#include <string.h>
+
+#include "data_block.hh"
+#include "data_block_0.hh"
+
+
+data_block::data_block(tape_block& idol)
+ :tape_block(idol)
+{
+}
+
+data_block::~data_block(){
+}
+
+int data_block::get_type(){
+ if ((init_state==TBS_OK)&&word_data)
+ return (word_data[0]&0xf000)>>12;
+ else
+ return block_type;
+}
+
+int data_block::get_subtype(){
+ if (get_type()==0)
+ return (new data_block_0(*this))->get_subtype();
+ else return 0;
+}
--- /dev/null
+#ifndef DATA_BLOCK_HH
+#define DATA_BLOCK_HH
+
+#include "tape_block.hh"
+
+class data_block
+ : public tape_block
+{
+ //private:
+ //data_block(); // Private constructor!
+
+public:
+ data_block(tape_block&);
+ ~data_block();
+
+virtual int get_type();
+virtual int get_subtype();
+
+};
+
+
+#endif
--- /dev/null
+#include "data_block_0.hh"
+#include "data_block.hh"
+
+data_block_0::data_block_0(data_block & org)
+ :data_block(org)
+{
+}
+
+data_block_0::~data_block_0()
+{
+}
+
+int data_block_0::get_subtype(){
+ if ((init_state==TBS_OK)&&word_size&&(data_block::get_type()==0)){
+ return (word_data[0]&0x0fc0)>>6;
+ }
+ else return data_block::get_subtype();
+}
+
--- /dev/null
+#ifndef DATA_BLOCK_0_H
+#define DATA_BLOCK_0_H
+
+#include "data_block.hh"
+
+class data_block_0
+ : public data_block
+{
+ public:
+ data_block_0(data_block&);
+ virtual ~data_block_0();
+
+ int get_subtype();
+
+};
+
+#endif
--- /dev/null
+#ifndef HW_CONSTANTS_H
+#define HW_CONSTANTS_H
+
+/* Block start delimiter */
+#define BLOCK_START_DELIMITER 0x81
+
+#define MINIMUM_DATA_BLOCK_WORDSIZE 1
+
+/* Block end delimiters */
+#define EOB_LENGTH 1
+#define BLOCK_END_DELIMITER_1 0223
+#define BLOCK_END_DELIMITER_2 0223
+
+/* End of Tape sequence
+ * If EOT_LENGTH is set to 2, EOT_1 becomes insignificant and so on
+ */
+#define EOT_LENGTH 3
+#define EOT_SEQ_1 0x83
+#define EOT_SEQ_2 0x93
+#define EOT_SEQ_3 0xff
+
+
+#endif
--- /dev/null
+#include "silent_code.hh"
+
+//#include <stdio.h>
+
+unsigned char silent_demangle (unsigned char in)
+{
+ if (in & 64)
+ switch (in) {
+ case 0174:
+ return 05;
+ break;
+ case 0374:
+ return 045;
+ break;
+ case 0175:
+ return 012;
+ break;
+ case 0375:
+ return 052;
+ break;
+ case 0176:
+ return 021;
+ break;
+ case 0376:
+ return 061;
+ break;
+ case 0177:
+ return 023;
+ break;
+ case 0377:
+ return 063;
+ break;
+ default: // Illegal branch
+ return 0;
+ break;
+ } else {
+ if (in & 128)
+ in |= 32;
+ return in;
+ }
+ return 0; // Never executed
+}
+
+unsigned short combine466 (unsigned char *raw) {
+ unsigned short r1, r2, r3;
+ unsigned short result=0;
+ r1 = silent_demangle ((raw)[0]) & 017;
+ r2 = silent_demangle ((raw)[1]) & 077;
+ r3 = silent_demangle ((raw)[2]) & 077;
+
+ result=r3;
+ result|=r2<<6;
+ result|=r1<<12;
+ // printf ("data: %02x %02x %02x %04x \n",r1,r2,r3,result);
+ return result;
+}
+
--- /dev/null
+#ifndef SILENT_CODE_H
+#define SILENT_CODE_H
+
+/*!
+ *\brief Demangle silent code frames to 6 bit frames
+ */
+extern unsigned char silent_demangle(unsigned char in);
+
+/*!
+ * Combine three mangled paper tape frames into
+ * one 16 bit machine word
+ */
+extern unsigned short combine466(unsigned char* in);
+
+#endif
--- /dev/null
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "tape_block.hh"
+#include "data_block.hh"
+
+#include "silent_code.hh"
+#include "hw_constants.hh"
+
+tape_block::tape_block()
+{
+}
+
+tape_block::tape_block(tape_block & org){
+ block_type=org.block_type;
+ init_state=org.init_state;
+ data_read=org.data_read;
+ raw_data=0;
+ raw_size=org.raw_size;
+ word_data=0;
+ word_size=org.word_size;
+ if (raw_size){
+ raw_data=(unsigned char *)malloc(raw_size);
+ memcpy(raw_data,org.raw_data,raw_size);
+ }
+ if (word_size){
+ word_data=(unsigned short *)malloc(word_size*sizeof(unsigned short));
+ memcpy(word_data,org.word_data,word_size*sizeof(unsigned short));
+ }
+}
+
+tape_block::tape_block (int fd,
+ void(*input_start)(void *),
+ void (*input_stop)(void *),
+ void * start_stop_arg
+ )
+{
+ unsigned char buffer;
+ int retval;
+ int eot_needed=EOT_LENGTH;
+ int eob_needed=EOB_LENGTH;
+ int block_complete=0;
+
+ block_type= TBT_DISCARD;
+ init_state= TBS_DEFAULT;
+ data_read = 0;
+ raw_data = 0;
+ raw_size = 0;
+ word_data = 0;
+ word_size = 0;
+
+ if (input_start) input_start (start_stop_arg);
+
+ /* Look for block start in input stream */
+ do {
+ retval=read(fd, &buffer, 1);
+ if (retval == 0){ // End of file
+ block_type=TBT_DISCARD;
+ init_state=TBS_EOF_LEGAL;
+ return;
+ }
+ if (retval == -1){ // Error reading from fd
+ block_type=TBT_DISCARD;
+ init_state=TBS_IOERR;
+ return;
+ }
+ data_read++;
+
+ /* Look for end ot tape sequence */
+ switch(eot_needed){
+ case 3:
+ if (buffer==EOT_SEQ_1) eot_needed--;
+ else eot_needed=EOT_LENGTH;
+ break;
+ case 2:
+ if (buffer==EOT_SEQ_2) eot_needed--;
+ else eot_needed=EOT_LENGTH;
+ break;
+ case 1:
+ if (buffer==EOT_SEQ_3){
+ raw_data=(unsigned char*)malloc(3);
+ raw_size=3;
+ raw_data[0]=EOT_SEQ_1;
+ raw_data[1]=EOT_SEQ_2;
+ raw_data[2]=EOT_SEQ_3;
+ block_type =TBT_EOT;
+ init_state =TBS_OK;
+ return;
+ }
+ else eot_needed=EOT_LENGTH;
+ break;
+ }
+ } while (buffer != (unsigned char) BLOCK_START_DELIMITER);
+
+
+ /* Now input the block data */
+ block_complete = 0;
+ do {
+ retval = read (fd, &buffer, 1);
+
+ if (retval == 0){ // End of file
+ block_type=TBT_DISCARD;
+ init_state=TBS_EOF_ILLEGAL;
+ return;
+ }
+ if (retval == -1){ // Error reading from fd
+ block_type=TBT_DISCARD;
+ init_state=TBS_IOERR;
+ return;
+ }
+ data_read++; // We have consumed a byte
+
+ /* sort in the new byte */
+ raw_size++;
+ raw_data=(unsigned char*)realloc(raw_data,raw_size);
+ raw_data[raw_size-1]=buffer;
+
+ /* Look for end ot block sequence */
+ switch(eob_needed){
+ case 2:
+ if (buffer==BLOCK_END_DELIMITER_1) eob_needed--;
+ else eob_needed=EOB_LENGTH;
+ break;
+ case 1:
+ if (buffer==BLOCK_END_DELIMITER_2){
+ raw_size-=EOB_LENGTH; // Don't want the delimiter(s) in the data!
+ raw_data=(unsigned char*)realloc(raw_data,raw_size);
+ block_complete=1;
+ }
+ else eob_needed=EOB_LENGTH;
+ break;
+ }
+ }while (!block_complete);
+ if (input_stop) input_stop (start_stop_arg);
+
+ /* Now we have the data in. */
+
+ if (init_words()!=0){
+ init_state=TBS_CHECKSUM;
+ return;
+ }
+
+ if (test_checksum()!=0){
+ init_state=TBS_CHECKSUM;
+ return;
+ }
+
+ block_type=TBT_DATA;
+ init_state=TBS_OK;
+}
+
+tape_block::~tape_block(){
+ free(raw_data);
+ free(word_data);
+}
+
+tape_block::tb_state_t tape_block::get_state(){
+ return init_state;
+}
+
+int tape_block::get_raw_size(){
+ return raw_size;
+}
+
+unsigned char * tape_block::get_raw_data(){
+ return raw_data;
+}
+
+int tape_block::get_type(){
+ int result=block_type;
+ if (block_type==TBT_DATA){
+ data_block * mb=new data_block(*this);
+ result=mb->get_type();
+ }
+ return result;
+}
+
+int tape_block::get_subtype(){
+ int result=0;
+ if (block_type==TBT_DATA){
+ data_block * mb=new data_block(*this);
+ result=mb->get_subtype();
+ }
+ return result;
+}
+
+int tape_block::init_words(){
+ word_size=raw_size/3;
+ if (word_size<MINIMUM_DATA_BLOCK_WORDSIZE) return 1; // Block too short!
+ word_data=(unsigned short *)malloc(raw_size*sizeof(unsigned short));
+ for (int pos=0; pos<word_size; pos++)
+ word_data[pos]=combine466(raw_data+3*pos);
+ return 0;
+}
+
+int tape_block::test_checksum(){
+ unsigned short sum=0;
+ for (int pos=0; pos<word_size-1;pos++)
+ // sum^=word_data[pos];
+ sum+=word_data[pos];
+
+ // printf("cs:%04x\n",word_data[word_size-1]);
+ if (sum==word_data[word_size-1]) return 0;
+ else return 1;
+}
--- /dev/null
+#ifndef TAPE_BLOCK_H
+#define TAPE_BLOCK_H
+
+
+/*!
+ *\brief Tape data block base class
+ *
+ * This class represents a Honeywell paper tape block.
+ * That may be some kind of data block or a end of tape mark.
+ */
+class tape_block{
+
+public: // types
+
+ /*!
+ * The block's initialisation state
+ */
+ typedef enum {
+ TBS_OK, //!< Block successfully initialised
+ TBS_EOF_LEGAL, //!< Legal EOF while initialising
+ TBS_EOF_ILLEGAL, //!< Illegal EOF while initialising
+ TBS_CHECKSUM, //!< Checksum error
+ TBS_IOERR, //!< I/O-Error while reading
+ TBS_DEFAULT //!< Block not initialised.
+ } tb_state_t;
+
+ /*!
+ * Tape block types
+ */
+ typedef enum {
+ TBT_DATA=0x10, //!< Data block
+ TBT_EOT, //!< End of tape block
+ TBT_DISCARD //!< Invalid block, check block_type
+ } tb_type_t;
+
+protected: // methods
+ /*!
+ *\brief Protected default constructor
+ */
+ tape_block();
+
+public: // methods
+
+ tape_block(tape_block &);
+
+ /*!
+ *\brief Read-in constructor for file descriptor
+ *
+ * This constructor is used to read in the block's data via a file
+ * descriptor.\\
+ * This is done in the following way:\\
+ * - input_start() is called.\\
+ * - Data is read from fd. Stops on end of file or end of block
+ * or IO error. On EOF or IO error input_stop() is NOT called.\\
+ * - If there was no IO error the block's checksum is calculated
+ * and checked.\
+ * - The block's type field is initialised.\\
+ * - input_stop() is called.\\
+ *\param fd_p A pointer to the device descriptor where
+ * the data is taken from \\
+ *\param input_stop A pointer to a function called at the end of input\\
+ *\param input_start A pointer to a function called at the beginning
+ * of input\\
+ *\param start_stop_arg A pointer passed to input_start and input_stop().
+ */
+ tape_block (int fd_p,
+ void(*input_start)(void *)=0,
+ void (*input_stop)(void *)=0,
+ void * start_stop_arg=0
+ );
+
+ /*!
+ * The virtual destructor
+ */
+ virtual ~tape_block();
+
+ /*!
+ *\brief Query the block's state.
+ *
+ * If the state is not TBS_OK, the block must be discarded.
+ *\return The block's initialisation state
+ */
+ tb_state_t get_state();
+
+ /*!
+ *\brief Get size of the internal raw data buffer
+ *\return The size of the internal raw data buffer
+ */
+ int get_raw_size();
+
+ /*!
+ *\brief Access internal raw data buffer
+ *
+ * The raw data buffer contains all block data except the \\
+ * block start delimiter and block end delimiter.
+ *\return Pointer to internal raw data buffer of the block
+ */
+ unsigned char * get_raw_data();
+
+ /*
+ *\brief Determine the block's type
+ *
+ * This routine returns the block's type.\\
+ *\retval TBT_DATA if it's a data block
+ *\retval TBT_EOT if it's an end of tape mark
+ *\retval TBR_DISCARD if the block is unusable
+ *
+ *\note This function is virtual. That means that if the tape block in
+ * question is of the subtype data_block which overwrites this method,
+ * it will return the block type contained in the upper 4 bits of the
+ * first data word! Try to avoid testing for TBT_DATA.
+ */
+ virtual int get_type();
+
+ /*!
+ *\brief Determine the block's subtype
+ *
+ * Some data block types have a subtype. This can be determined this way.
+ *\return Block subtype if the block object is of a suitable subclass
+ */
+ virtual int get_subtype();
+
+private: // methods
+ /*!
+ *\brief Initialize word representation of data
+ *\retval 0 on success
+ *\retval 1 on error
+ */
+ int init_words(void);
+
+ /*!
+ *\brief Calculate and check checksum
+ *\retval 0 on success
+ *\retval 1 on error
+ */
+ int test_checksum();
+
+protected: // members
+ int block_type; //!< type of this block
+ tb_state_t init_state; //!< Initialisation state
+ int data_read; //!< Total data consumption during intialisation
+ unsigned char * raw_data; //!< Raw block data in bytes
+ int raw_size; //!< Size of the raw data
+ unsigned short * word_data; //!< Data organized in machine words
+ int word_size; //!< Size of the blocks in machine words
+
+}; // tape_block
+
+
+#endif
--- /dev/null
+#include <vector>
+
+#include "tape_block.hh"
+#include "data_block.hh"
+#include "tape_block_0.hh"
+
+class tape_block_vector
+ : protected vector<tape_block>
+{
+public:
+ tape_block_vector();
+ tape_block_vector(tape_block_vector&);
+
+};
--- /dev/null
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include "tape_block.hh"
+
+void tape_start(void* m){
+ printf("tape_start\n");
+}
+
+void tape_stop(void* m){
+ printf("tape_stop\n");
+}
+
+int main(){
+ tape_block * myblock=0;
+ do{
+ if (myblock) delete myblock;
+ myblock=new tape_block(0);
+ printf ("Block type:%2o-%o\n",myblock->get_type(),myblock->get_subtype());
+ } while (myblock->get_state()==tape_block::TBS_OK);
+ printf("---");
+ printf("State:%i\n",myblock->get_state());
+ printf("raw size:%i\n",myblock->get_raw_size());
+ return 0;
+}