From kenr@xis.xerox.com Mon Mar 22 12:39:10 1993 Return-Path: Posted-Date: Mon, 22 Mar 1993 06:10:35 PST Date: Mon, 22 Mar 1993 06:10:35 PST From: kenr@xis.xerox.com (Ken Rice) To: nmra@linus.mitre.org Subject: Computer command station. Cc: kenr@xis.xerox.com Content-Length: 9447 X-Lines: 296 Status: RO This is the code to convert the bytes that make up a packet into a stream of bytes to send out the serial port to make the nmra signal. It should compile with any ansi C compiler. I will make the booster schematic available as soon as I find the best way - it's a 350K postscript file. Ken (Rice) =========================================================================== /* makepacket.c * * Send an nmra packet out the serial port in such a way that the signal can * just be amplified and put on the track. * * Copyright 1993 Kenneth Rice * * You may freely distribute this source code, and use all or part of * this source code in all software including commercial, freeware, * shareware and private applications. * * Please report bugs, fixes, etc to me at kenr@xis.xerox.com, * or 73577,1653 (compuserve) * * Created 02/08/93 * 03/05/93 Finally works for all 3 byte packets. * Still errors for 4 byte. */ #include #include #define PREAMBLE_LENGTH 15 /* This MUST be a multiple of 5. */ #define MAX_PACKET_BYTES 10 /* somewhat arbitrary. */ #define BITSTREAM_BITS_PER_BYTE 9 /* counts start bit */ int TranslateByte(int *pBS, int validBits, int *pBitsUsed); void MakeBitValuesFromByte(int *pBitStream, int byte); /* MakePacket * * This routine generates a string of bytes to be sent out the serial port from * the bytes that make up an nmra packet. * * Arguments: * pSerialBuf - Ptr to place to put serial bytes. * pSerialBufCnt - Ptr to place to put num of serial bytes put in pSerialBuf. * ... - The bytes that make up the packet, terminated by a -1. * * The serial bytes should be sent out a serial port set to somewhere between * 19.2K baud and 14.7K baud. I use 16.4K baud on my mac, which works out to 61 * micro second half ones. The serial port must be set to 8 data bits, 1 stop * bit, and no parity. * * Example code fragment to call this function for a baseline packet: * * char serialBuf[1000]; * int serialBufCnt; * int addr = 3; * int speed = 0x75; * * if (MakePacket(serialBuf, &serialBufCnt, addr, speed, addr^speed, -1) < 0) * * handle error - should never happen for 3 byte packets. * * else * * send bytes in serialBuf out serial port repeatedly. * */ int MakePacket(char *pSerialBuf, int *pSerialBufCnt, ...) { int i; int byte; va_list ap; int bitsInStream = 0; int bitStream[MAX_PACKET_BYTES*9+PREAMBLE_LENGTH+1+1+2]; /* 1 stop 1 end 2 zeros */ int bitsUsed; int serialByte; *pSerialBufCnt = 0; /* First, make into an array of ints for easier processing. */ /* do preamble */ for (bitsInStream=0; bitsInStream> 1); } } /* TranslateByte * * This routine determines which of the following bits patterns * most best fits the leftmost bits in the stream of bits passed in (pBS). * The stream contains validBits bits, and this routine sets *pBitsUsed * to the number of bits we converted into the serial byte returned. * Returns -1 on error. * * Notes - this routine has been tested with all possible 3 byte packets * and proved to work. It is known to fail on some four byte packets. * I plan on adding a tree-based backtracking scheme to allow it * to work reliably with longer packets. * * Warnings - The order of everything in this routine is important. Shuffling * almost anything around will probably result in some errors * generating 3 byte packets. This routine is also fairly dependent * on there being a multiple of 5 preamble bits, and at least one * zero bit at the end of the bit stream. If you do change anything * in this routine, you should run exhautive tests to prove that * it still works. Testing all three byte packets takes a sparc 10 * about 45 minutes. * * nmra s01234567s (hex equiv - note that in signal, 0 bit is left) * 0 _____----- (0xF0) * 00 __--___--- (0xC6) * 01 ____----_- (0x78) * 10 _-____---- (0xE1) * 010 __--_-__-- (0x96) * 011 ___---_-_- (0x5C) * 100 _-__--__-- (0x99) * 101 _-___---_- (0x71) * 110 _-_-___--- (0xC5) * 0111 __--_-_-_- (0x56) * 1011 _-__--_-_- (0x59) * 1101 _-_-__--_- (0x65) * 1110 _-_-_-__-- (0x95) * 11111 _-_-_-_-_- (0x55) * * Return -1 on error, otherwise serial byte. */ int TranslateByte(int *pBS, int validBits, int *pBitsUsed) { int i; if (validBits >= 5) { /* try 5 bits * 11111 _-_-_-_-_- (0x55) */ *pBitsUsed = 5; if (pBS[0] && pBS[1] && pBS[2] && pBS[3] && pBS[4]) return 0x55; } if (validBits >= 4) { /* try 4 bits * 0111 __--_-_-_- (0x56) * 1011 _-__--_-_- (0x59) * 1101 _-_-__--_- (0x65) * 1110 _-_-_-__-- (0x95) */ *pBitsUsed = 4; for (i=0; pBS[4+i]; i++) /* safe - we know bitstream ends with 0's. */ ; /* make sure we don't leave four 1's followed by a zero, possibly * after some multiple of five 1's. */ if ((i-4) % 5 != 0) { /* other i != tests are to prefer converting a string of 5 ones * into a single byte. */ if (! pBS[0] && pBS[1] && pBS[2] && pBS[3] && ! (i >= 2 && i < 5)) return 0x56; else if (pBS[0] && ! pBS[1] && pBS[2] && pBS[3] && ! (i>=3 && i<5)) return 0x59; else if (pBS[0] && pBS[1] && ! pBS[2] && pBS[3]) return 0x65; else if (pBS[0] && pBS[1] && pBS[2] && ! pBS[3]) return 0x95; } } if (validBits >= 3) { /* 011 ___---_-_- (0x5C) Moved up before 2. */ *pBitsUsed = 3; for (i=0; pBS[3+i]; i++) /* safe - we know bitstream ends with 0's. */ ; if ((i-4) % 5 != 0) { if (! pBS[0] && pBS[1] && pBS[2] && ! (i >= 3 && i < 5)) return 0x5C; } } if (validBits >= 2) { /* try 2 bits * 01 ____----_- (0x78) * 10 _-____---- (0xE1) * NOTE: Doing 2 zeros in a row increases the chance of error. */ *pBitsUsed = 2; for (i=0; pBS[2+i]; i++) /* safe - we know bitstream ends with 0's. */ ; if ((i-4) % 5 != 0) { if (! pBS[0] && pBS[1]) return 0x78; if (pBS[0] && ! pBS[1]) return 0xE1; } } if (validBits >= 3) { /* try 3 bits * 010 __--_-__-- (0x96) * 011 ___---_-_- (0x5C) Moved up before 2. * 100 _-__--__-- (0x99) * 101 _-___---_- (0x71) * 110 _-_-___--- (0xC5) */ *pBitsUsed = 3; for (i=0; pBS[3+i]; i++) /* safe - we know bitstream ends with 0's. */ ; if ((i-4) % 5 != 0) { if (! pBS[0] && pBS[1] && ! pBS[2]) return 0x96; if (! pBS[0] && pBS[1] && pBS[2] && ! (i >= 3 && i < 5)) return 0x5C; if (pBS[0] && ! pBS[1] && ! pBS[2]) return 0x99; if (pBS[0] && ! pBS[1] && pBS[2]) return 0x71; if (pBS[0] && pBS[1] && ! pBS[2]) return 0xC5; } } if (validBits >= 1) { /* try 1 bits * 0 _____----- (0xF0) */ *pBitsUsed = 1; if (! pBS[0]) return 0xF0; } *pBitsUsed = 1; /* set to 1 so we don't get an infinate loop on error. */ return -1; }