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

ProtocolStack/Segment.cs

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

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