Main Page | Class Hierarchy | Class List | File List | Class Members

SmartDeviceGUIClient/Segment.cs

00001 using System;
00002 
00003 namespace SmartDeviceGUIClient
00004 {
00009         public class Segment {
00010 
00011                 private SegmentHeaders headers;
00012                 private SegmentData data;
00013 
00014                 public SegmentHeaders Headers {
00015                         get { return headers; }
00016                         set { headers = value; }
00017                 }
00018 
00019                 public SegmentData Data {
00020                         get { return data; }
00021                         set { data = value; }
00022                 }
00023 
00028                 public bool IsRetransmission {
00029                         get { return headers.IsRetransmission; }
00030                         set { headers.IsRetransmission = value; }
00031                 }
00032 
00033                 public Segment() {}
00034                 
00035                 public Segment(byte[] data) : base() {
00036             this.FromByteArray(data);
00037                 }
00038 
00039                 public Segment(SegmentHeaders headers, SegmentData data) {
00040                         this.headers = headers;
00041                         this.data = data;
00042                         // TODO: Add more Segment constructor logic.
00043                 }
00044 
00045                 public byte[] ToByteArray(){
00046                         byte[] result = new byte[headers.Length + data.Length];
00047                         headers.ToByteArray().CopyTo(result, 0);
00048                         data.ToByteArray().CopyTo(result, headers.Length);
00049                         return result;
00050                 }
00051 
00052                 public void FromByteArray(byte[] src) {
00053                         int index = 0;
00054                         headers = new SegmentHeaders();
00055                         data = new SegmentData();
00056 
00057                         headers.FromByteArray(ref src, ref index);
00058                         data.FromByteArray(ref src, ref index);
00059                 }
00060 
00061         }
00062 
00063         public class SegmentDataTooBig : Exception {}
00064 
00068         public class SegmentData {
00069                 private byte[] data;
00070                 public static readonly int MAX_DATA_SIZE = 471; 
00071                 // was 476 before adding in the 2 byte size field.
00072                 // 01/04/2002 Removed another 3 when I increased the size of the headers
00073 
00074                 public SegmentData() {}
00075 
00076                 public SegmentData(byte[] data) {
00077                         Data = data;
00078                 }
00079 
00080                 public byte[] Data {
00081                         get { return data; }
00082                         set { if (value.Length <= MAX_DATA_SIZE) {
00083                                           data = value; } 
00084                                   else {
00085                                           throw new SegmentDataTooBig();
00086                                   }
00087                         }
00088                 }
00089 
00093                 public ushort DataLength {
00094                         get { if (data != null) {
00095                                           return (ushort)data.Length;
00096                                   } else {
00097                                           return 0;
00098                                   }
00099                         }
00100                 }
00101 
00105                 public ushort Length {
00106                         get {  return (ushort)(DataLength + 2); } // the 1st 2 bytes is the data size.
00107                 }
00108 
00109                 public byte[] ToByteArray() {
00110                         byte[] result = new byte[Length]; 
00111                         BitConverter.GetBytes(DataLength).CopyTo(result, 0);
00112                         Data.CopyTo(result, 2);
00113                         return result;
00114                 }
00115 
00121                 public void FromByteArray(ref byte[] src, ref int currentPos) {
00122                         int tempLength;
00123                         tempLength = BitConverter.ToUInt16(src, currentPos); 
00124                         currentPos += 2;
00125                         Data = new byte[tempLength];
00126                         for (int i = 0; i < tempLength; i++, currentPos++) {
00127                                 Data[i] = src[currentPos];
00128                         }
00129                 }
00130 
00131                 public void Test() {
00132                         Data = new byte[] {1,2,3,4,5,6,7,8,9,10};
00133                 }
00134 
00140                 public static SegmentData[] FromMessage(Message msg) {
00141                         return FromMessage(msg, MAX_DATA_SIZE);
00142                 }
00143 
00144                 public static SegmentData[] FromMessage(Message msg, int maxDataSize) {
00145                         SegmentData[] result;
00146                         int segmentCount = 0; 
00147                         long copyLength = 0;
00148                         uint currentPos = 0;
00149                         byte[] segmentDataBuffer = Message.SerialiseMessage(msg).GetBuffer();
00150 
00151                         segmentCount = (int)(Math.Ceiling((double)segmentDataBuffer.Length / maxDataSize));
00152                         result = new SegmentData[segmentCount];
00153                         for (int i = 0; i < segmentCount; i++) {
00154                                 result[i] = new SegmentData();
00155                                 // if what we have to put in, minus what we have put in already, is bigger than a segment
00156                                 if ((segmentDataBuffer.Length - currentPos) > maxDataSize) {
00157                                         copyLength = maxDataSize; }// then we're copying a whole segment
00158                                 else { // we're copying a bit of a segment - could be out by one or two here.
00159                                         copyLength = segmentDataBuffer.Length - currentPos;
00160                                 }
00161                                 result[i].Data = new byte[copyLength];
00162                                 Array.Copy(segmentDataBuffer, (int)currentPos, result[i].Data, 0, (int)copyLength);
00163                                 currentPos += (uint)copyLength;
00164                         }
00165                         return result;
00166                 }
00172                 public static byte[] ArrayToByteArray(SegmentData[] src) {
00173                         // concatenate segments into huge byte array
00174                         int numSegments = src.Length;
00175                         int byteCount = 0;
00176                         int bufferPtr = 0;
00177                         byte[] buffer;
00178                         // (crude but effective)
00179                         for (int i = 0; i < numSegments; i++) {
00180                                 byteCount += src[i].DataLength; // TODO: (4) Make this nicer
00181                         }
00182                         buffer = new byte[byteCount - 1]; // correct for 1st type byte, we don't need that
00183                                 
00184                         // copy into the huge buffer
00185                         for (int i = 0; i < numSegments; i++) {
00186                                 // note correction for 1st segment data bit as type entry
00187                                 Array.Copy(src[i].Data, (i == 0) ? 1 : 0, buffer, bufferPtr, (i == 0) ? src[i].DataLength - 1 : src[i].DataLength);
00188                                 bufferPtr += src[i].DataLength - ((i == 0) ? 1 : 0); // data Length is actaully data Length -1 for 1st segment
00189                         }
00190                         return buffer;
00191                 }
00192         }
00193 
00194         public class SegmentHeaders {
00195                 SegmentFlags flags;
00196                 // some list of segment headers
00197                 uint synchOrRate; // 32 but synchronisation or rate information
00198                 ushort srcDeviceID; // 16 bit device ID of source
00199                 bool isRetransmission;
00200 
00201                 uint sequenceNumber; // 32 bit segment sequence number
00202                 DateTime sent; // filled in just before Tx.
00203                 DateTime received; // only used when the segment arrives at Rx
00204 
00205                 uint ACK_SequenceNumberACKd; // 32 bit Sequence number of segment to ACK
00206 
00207                 uint NACK_SequenceNumberNACKd; // 32 bit seq number of segment to NACK
00208                 uint NACK_Range; // 32 bits. Number of segments after the one specify to consider NACK'd too
00209                 
00210                 public SegmentHeaders() {
00211                         flags = new SegmentFlags();
00212                 }
00213 
00218                 public bool IsRetransmission {
00219                         get { return isRetransmission; }
00220                         set { isRetransmission = value; }
00221                 }
00222 
00223                 public DateTime TimeSent {
00224                         get { return sent; }
00225                         set { sent = value; }
00226                 }
00227 
00228                 public DateTime TimeReceived {
00229                         get { return received; }
00230                         set { received = value; }
00231                 
00232                 }
00233 
00237                 public int Length {
00238                         get {
00239                                 int runningTotal = 0; // how many bytes are there so far...
00240                                 runningTotal += flags.Length; // add the flags at the start
00241                                 // sizeOf synchOrRate
00242                                 runningTotal += BitConverter.GetBytes(synchOrRate).Length;
00243                                 // sizeOf Src Device ID
00244                                 runningTotal += BitConverter.GetBytes(srcDeviceID).Length;
00245                                 // sizeOf SegmentNumber
00246                                 runningTotal += BitConverter.GetBytes(sequenceNumber).Length;
00247                                 // sizeOf Send Timestamp
00248                                 runningTotal += BitConverter.GetBytes(sent.Ticks).Length;
00249 
00250                                 // we don't care that it's ackable - that's not our concern right now.
00251                                 if (flags.isACK) { // if it's an ACK, then it will have the segment number of the segment it's ACKing
00252                                         runningTotal += BitConverter.GetBytes(ACK_SequenceNumberACKd).Length; 
00253                                 }
00254                                 if (flags.isNACK) { // NACK headers
00255                                         runningTotal += BitConverter.GetBytes(NACK_SequenceNumberNACKd).Length;
00256                                         if (flags.isRangedNACK) {
00257                                                 runningTotal += BitConverter.GetBytes(NACK_Range).Length;
00258                                         }
00259                                 }
00260                                 return runningTotal;
00261                         }
00262                 }
00263 
00268                 public byte[] ToByteArray() {
00269                         byte[] result = new byte[Length];
00270                         byte[] buffer;
00271                         int currentPos = 0;
00272                         buffer = flags.ToByteArray();
00273                         buffer.CopyTo(result, currentPos);
00274                         currentPos += buffer.Length;
00275 
00276                         buffer = BitConverter.GetBytes(synchOrRate);
00277                         buffer.CopyTo(result, currentPos);
00278                         currentPos += buffer.Length; 
00279 
00280                         buffer = BitConverter.GetBytes(srcDeviceID);
00281                         buffer.CopyTo(result, currentPos);
00282                         currentPos += buffer.Length;
00283 
00284                         buffer = BitConverter.GetBytes(sequenceNumber);
00285                         buffer.CopyTo(result, currentPos);
00286                         currentPos += buffer.Length;
00287 
00288                         buffer = BitConverter.GetBytes(sent.Ticks);
00289                         buffer.CopyTo(result, currentPos);
00290                         currentPos += buffer.Length;
00291 
00292                         if (flags.isACK) {
00293                                 buffer = BitConverter.GetBytes(ACK_SequenceNumberACKd);
00294                                 buffer.CopyTo(result, currentPos);
00295                                 currentPos += buffer.Length;
00296                         }
00297 
00298                         if (flags.isNACK) {
00299                                 buffer = BitConverter.GetBytes(NACK_SequenceNumberNACKd);
00300                                 buffer.CopyTo(result, currentPos);
00301                                 currentPos += buffer.Length;
00302                                 if (flags.isRangedNACK) {
00303                                         buffer = BitConverter.GetBytes(NACK_Range);
00304                                         buffer.CopyTo(result, currentPos);
00305                                         currentPos += buffer.Length;
00306                                 }
00307                         }
00308                         return result;
00309                 }
00310 
00318                 public void FromByteArray(ref byte[] src, ref int currentPos) {
00319                         flags = new SegmentFlags();
00320                         flags.FromByte(src[currentPos]); // construct flags
00321                         currentPos += 1;
00322 
00323                         synchOrRate = BitConverter.ToUInt32(src, currentPos); // construct Sychronisation Offset / Rate Info
00324                         currentPos += 4;
00325 
00326                         srcDeviceID = BitConverter.ToUInt16(src, currentPos);
00327                         currentPos += 2;
00328 
00329                         sequenceNumber = BitConverter.ToUInt32(src, currentPos);
00330                         currentPos += 4;
00331 
00332                         sent = new DateTime(BitConverter.ToInt64(src, currentPos));
00333                         currentPos += 8;
00334 
00335                         if (flags.isACK) {
00336                                 ACK_SequenceNumberACKd = BitConverter.ToUInt32(src, currentPos);
00337                                 currentPos += 4;
00338                         }
00339 
00340                         if (flags.isNACK) {
00341                                 NACK_SequenceNumberNACKd = BitConverter.ToUInt32(src, currentPos);
00342                                 currentPos += 4;
00343                                 if (flags.isRangedNACK) {
00344                                         NACK_Range = BitConverter.ToUInt32(src, currentPos);
00345                                         currentPos += 4;
00346                                 }
00347                         }
00348                 }
00349 
00350 
00351                 public void SetNACKStatus(NackInfo nackInfo) {
00352                         flags.isNACK = true;
00353                         NACK_SequenceNumberNACKd = nackInfo.SequenceNumber;
00354                         flags.isRangedNACK = nackInfo.IsRanged;
00355                         NACK_Range = (nackInfo.IsRanged ? nackInfo.Range : 0);
00356                 }
00357 
00358                 public void ClearNACKStatus() {
00359                         flags.isNACK = false;
00360                         NACK_SequenceNumberNACKd = 0;
00361                         flags.isRangedNACK = false;
00362                         NACK_Range = 0;
00363                 }
00364                 
00365                 public void SetAck(AckInfo ackInfo) {
00366                         flags.isACK = true;
00367                         ACK_SequenceNumberACKd = ackInfo.SequenceNumber;
00368                 }
00369 
00370                 public void ClearAck() {
00371                         flags.isACK = false;
00372                         ACK_SequenceNumberACKd = 0;
00373                 }
00374 
00375                 public bool IsAckable {
00376                         get { return flags.isACKable; }
00377                         set { flags.isACKable = value; }
00378                 }
00379 
00383                 public bool IsAck {
00384                         get { return flags.isACK; }
00385                 }
00386 
00390                 public uint ACKdSequenceNumber {
00391                         // TODO: Throw exception if flags.isAck is false?
00392                         get { return ACK_SequenceNumberACKd; }
00393                 }
00394                 
00395                 public bool IsResynch {
00396                         get { return flags.isSynchedPacket; }
00397                         set { flags.isSynchedPacket = value; }
00398                 }
00399 
00400                 public bool IsFirstInMessage {
00401                         get { return flags.isFirstMessageSegment; }
00402                         set { flags.isFirstMessageSegment= value; }
00403                 }
00404                 public bool IsLastInMessage {
00405                         get { return flags.isLastMessageSegment; }
00406                         set { flags.isLastMessageSegment = value; }
00407                 }
00408 
00409                 public ushort SourceDeviceID {
00410                         get { return srcDeviceID; }
00411                         set { srcDeviceID = value; }
00412                 }
00413 
00414                 public uint SequenceNumber {
00415                         get {return sequenceNumber; }
00416                         set {sequenceNumber = value; }
00417                 }
00418 
00419                 public uint SynchOrRate {
00420                         get { return synchOrRate; }
00421                         set { synchOrRate = value; }
00422 
00423                 }
00424 
00425                 public bool IsNACK {
00426                         get { return flags.isNACK; }
00427 
00428                 }
00429 
00430                 public bool IsRangedNACK {
00431                         get { return flags.isRangedNACK; }
00432                 }
00433 
00434                 public NackInfo NackInfo {
00435                         get { return new NackInfo(NACK_SequenceNumberNACKd, NACK_Range); }
00436                 }
00437 
00438                 public void Test() {
00439                         flags = new SegmentFlags();
00440                         flags.Test();
00441                         srcDeviceID = 1234;
00442                         sequenceNumber = 2;
00443                         NACK_Range = 42;
00444                         NACK_SequenceNumberNACKd = 314159;
00445                         ACK_SequenceNumberACKd = 76;
00446                         sent = DateTime.Now;
00447                 }
00448 
00449 
00450         }
00451 
00455         public class SegmentFlags {
00459                 public int Length {
00460                         get { return 1; }
00461                 } 
00462 
00463                 // TODO: Convert these into properties
00464                 public bool isACK;
00465                 public bool isACKable;
00466                 public bool isNACK;
00467                 public bool isRangedNACK;
00468                 public bool isSynchedPacket; 
00469                 /* or 'isNotRateData'. The SynchOffset 8 bit field has 2 purposes:
00470                  * It is either the offset from 1st packet of new timestamp'd segemnt
00471                  * or is rate control information, depending on the value of this bit. A zero 
00472                  * in rate control info indicaes no change.*/
00473                 public bool isFirstMessageSegment;
00474                 public bool isLastMessageSegment;
00475 
00476 
00477                 public byte[] ToByteArray() {
00478                         byte temp = 0;
00479                         temp += (byte)(isACK ? 1 : 0);
00480                         temp += (byte)(isACKable ? 1 << 1 : 0);
00481                         temp += (byte)(isNACK ? 1 << 2 : 0);
00482                         temp += (byte)(isRangedNACK ? 1 << 3: 0);
00483                         temp += (byte)(isSynchedPacket ? 1 << 4: 0);
00484                         temp += (byte)(isFirstMessageSegment ? 1 << 5: 0);
00485                         temp += (byte)(isLastMessageSegment ? 1 << 6: 0);
00486                         temp += (byte)(false ? 1 << 7: 0); // for future expansion.
00487                         return new byte[] {temp};
00488                 }
00489 
00494                 public void FromByteArray(byte[] src) {
00495                         this.FromByte(src[0]);
00496                 }
00497 
00502                 public void FromByte(byte src) {
00503                         isACK = ((src & (1 << 0)) != 0);
00504                         isACKable = ((src & (1 << 1)) != 0);
00505                         isNACK = ((src & (1 << 2)) != 0);
00506                         isRangedNACK = ((src & (1 << 3)) != 0);
00507                         isSynchedPacket = ((src & (1 << 4)) != 0);
00508                         isFirstMessageSegment = ((src & (1 << 5)) != 0);
00509                         isLastMessageSegment = ((src & (1 << 6)) != 0);
00510                 }
00511 
00512                 public void Test() {
00513                         isACK = true;
00514                         isACKable = true;
00515                         isNACK = true;
00516                         isRangedNACK = true;
00517                         isSynchedPacket = false;
00518                         isFirstMessageSegment = false;
00519                         isLastMessageSegment = false;
00520                 }
00521         }
00522 
00523 
00524 }

Generated on Mon May 8 22:07:27 2006 by  doxygen 1.3.9.1