Source code: com/synchrona/jred/irlap/AsyncFrameWrapper.java
1 /*
2 **************************************************************************
3 ** $Header: /cvsroot/jred/jred/src/com/synchrona/jred/irlap/AsyncFrameWrapper.java,v 1.1.1.1 2000/07/05 04:41:52 mpatters Exp $
4 **
5 ** Copyright (C) 2000 Synchrona, Inc. All rights reserved.
6 **
7 ** This file is part of JRed, a 100% Java implementation of the IrDA
8 ** infrared communications protocols.
9 **
10 ** This file may be distributed under the terms of the Synchrona Public
11 ** License as defined by Synchrona, Inc. and appearing in the file
12 ** LICENSE included in the packaging of this file. The Synchrona Public
13 ** License is based on the Q Public License as defined by Troll Tech AS
14 ** of Norway; it differs only in its use of the courts of Florida, USA
15 ** rather than those of Oslo, Norway.
16 **************************************************************************
17 */
18 package com.synchrona.jred.irlap;
19
20 import com.synchrona.util.Log;
21 import java.io.DataInputStream;
22 import java.io.DataOutputStream;
23 import java.io.IOException;
24 import java.io.PrintWriter;
25
26 /**
27 * Implements asynchronous frame wrapping, which IrLAP uses at
28 * 9600bps - 115200bps
29 */
30 class AsyncFrameWrapper implements iFrameWrapper {
31 /**
32 * Users of AsyncFrameWrapper can safely size frame buffers
33 * at MAX_FRAME_LENGTH (255 bytes).
34 */
35 public static final int MAX_FRAME_LENGTH = 255;
36
37 private static final byte BOF = (byte) 0xC0;
38 private static final byte CE = (byte) 0x7D;
39 private static final int DEFAULT_BOF_COUNT = 11;
40 private static final byte EOF = (byte) 0xC1;
41 private static final byte XBOF = (byte) 0xFF;
42
43 private byte [] m_ayInputFrame = new byte[MAX_FRAME_LENGTH * 2];;
44 private byte [] m_ayOutputFrame = new byte[MAX_FRAME_LENGTH * 2];;
45 private CheckCRC m_crc = new CheckCRC();
46 private DataInputStream m_in;
47 private Log m_log;
48 private int m_nBOFCount = DEFAULT_BOF_COUNT;
49 private DataOutputStream m_out;
50
51 public AsyncFrameWrapper(Log log, DataInputStream in, DataOutputStream out) {
52 m_in = in;
53 m_log = log;
54 m_out = out;
55 }
56
57 //----------------------------------------------------------------
58 // Implementation of iFrameWrapper
59 //----------------------------------------------------------------
60
61 /**
62 * @param ayDestination destination frame
63 * @param nOffset offset into destination frame at which writing should begin
64 * @param nLength maximum number of bytes that can be written into destination frame
65 *
66 * @return Number of bytes written into destination frame (0 if no data was available)
67 */
68 public int receive(byte [] ayDestination, int nOffset, int nLength) throws Exception {
69 verifyFrameArgs(ayDestination, nOffset, nLength);
70 if ( null == m_in ) {
71 throw new Exception("DataInputStream is null");
72 }
73 int nBytesRead = 0;
74 try {
75 nBytesRead = reallyReceive(ayDestination, nOffset, nLength);
76 } catch ( Exception e ) {
77 nBytesRead = 0;
78 }
79 return nBytesRead;
80 }
81
82 public void send(byte [] aySource, int nOffset, int nLength) throws Exception {
83 verifyFrameArgs(aySource, nOffset, nLength);
84 if ( null == m_out ) {
85 throw new Exception("DataOutputStream is null");
86 }
87 reallySend(aySource, nOffset, nLength);
88 }
89
90 public void setLog(PrintWriter log) {
91 }
92
93 public void setLogging(boolean bDoLogging) {
94 }
95
96 public void setNumberOfBOFs(int nBOFCount) {
97 m_nBOFCount = nBOFCount;
98 }
99
100 //----------------------------------------------------------------
101 // End of iFrameWrapper implementation
102 //----------------------------------------------------------------
103
104 /**
105 * @return Number of bytes written into destination buffer
106 */
107 private int reallyReceive(byte [] ayDestination, int nOffset, int nLength) throws Exception {
108 // Read the inter-frame filler (0xFF). If your port speed is higher
109 // than JavaComm supports, JavaComm claims to read nothing but 0xFF,
110 // which is why you need to be able to break out of this loop.
111 byte yBOF = XBOF;
112 byte nXBOFCount = -1;
113 while ( (BOF != yBOF) && (nXBOFCount < (m_nBOFCount * 2)) ) {
114 yBOF = m_in.readByte();
115 nXBOFCount++;
116 }
117 if ( nXBOFCount >= m_nBOFCount ) {
118 throw new Exception("Expected to get " + m_nBOFCount + " XBOF characters, got " + nXBOFCount + " instead.");
119 }
120 if ( BOF != yBOF ) {
121 throw new Exception("Expected IrLAP BOF, got " + yBOF + " instead.");
122 }
123
124 int nPosition = 0;
125 boolean bContinue = true;
126 while ( bContinue ) {
127 byte b = m_in.readByte();
128 if ( EOF == b ) {
129 // got an EOF, drop out before we store this byte
130 bContinue = false;
131 } else if ( nPosition >= m_ayInputFrame.length ) {
132 throw new Exception("Data exceeds internal buffer length.");
133 } else {
134 if ( CE == b ) {
135 b = m_in.readByte();
136 b ^= (byte) 0x20;
137 }
138 m_ayInputFrame[nPosition++] = b;
139 }
140 }
141
142 //---------------------------------------------------------------
143 // TBD: Verify Frame Check Sequence. So far my version of the
144 // algorithm is more incorrect than the stuff coming over
145 // the wire, so I'm not too worried about what other devices
146 // send us.
147 //---------------------------------------------------------------
148
149 // Decrement position so we don't copy the Frame Check Sequence
150 nPosition -= 2;
151
152 for ( int i = 0; (i < nPosition) && ((nOffset + i) < nLength); i++ ) {
153 ayDestination[nOffset + i] = m_ayInputFrame[i];
154 }
155
156 m_log.debugBytes("AsyncFrameWrapper", "recv'd this: ", ayDestination, nOffset, nOffset + nPosition);
157 return nPosition;
158 }
159
160 private void reallySend(byte [] ayFrame, int nOffset, int nLength) throws Exception {
161 m_log.debugBytes("AsyncFrameWrapper", "got this: ", ayFrame, nOffset, nLength);
162 int i = 0;
163 int nPosition = 0;
164
165 for ( i = 0; i < (m_nBOFCount -1); i++ ) {
166 m_ayOutputFrame[nPosition++] = XBOF;
167 }
168 m_ayOutputFrame[nPosition++] = BOF;
169
170 for ( i = 0; i < nLength; i++ ) {
171 byte yCurrent = ayFrame[nOffset + i];
172
173 switch ( yCurrent ) {
174 case BOF:
175 // fall through
176 case EOF:
177 // fall through
178 case CE:
179 yCurrent ^= (byte) 0x20;
180 m_ayOutputFrame[nPosition++] = CE;
181 // fall through
182 default:
183 m_ayOutputFrame[nPosition++] = yCurrent;
184 break;
185 }
186 }
187
188 // XBOF and BOF are not part of CRC calculation
189 int fcs = m_crc.getCRC(ayFrame, nOffset, nLength);
190
191 m_ayOutputFrame[nPosition++] = (byte) (fcs & 0x000000FF);
192 m_ayOutputFrame[nPosition++] = (byte) ((fcs & 0x0000FF00) >> 8);
193
194 m_ayOutputFrame[nPosition++] = EOF;
195
196 m_log.debugBytes("AsyncFrameWrapper", "sending this: ", m_ayOutputFrame, 0, nPosition);
197
198 m_out.write(m_ayOutputFrame, 0, nPosition);
199 }
200
201 private void verifyFrameArgs(byte [] ayFrame, int nOffset, int nLength) throws Exception {
202 if ( null == ayFrame ) {
203 throw new Exception("The frame is null.");
204 } else if ( nOffset < 0 ) {
205 throw new Exception("The frame offset is negative.");
206 } else if ( nOffset >= nLength ) {
207 throw new Exception("The frame offset is greater than or equal to the frame length.");
208 } else if ( nLength > MAX_FRAME_LENGTH ) {
209 throw new Exception("The frame's length is greater than or equal to the maximum frame length (" + MAX_FRAME_LENGTH + ").");
210 } else if ( ayFrame.length < (nOffset + nLength) ) {
211 throw new Exception("The frame's length and offset are inconsistent with array bounds.");
212 }
213 }
214 }