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

SmartDeviceClient/SmartProtocolStack/Segment.cs

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

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