Temperature Sensor

August 25, 2009 by Matthew

It’s the on-going saga of my MX-6. The other day I drilled and tapped a hole for the second temperature sensor. The J-Spec motor I put in the car only had a port for 1 sensor while the ’93 A-Spec motor requires two. The work was pretty straight forward, but since I’d never tapped a screw hole before I had to practice on the old J-Spec throttle body. Once confident, I proceeded to drill the hole in the radiator return block on the motor. All went smoothly except the pictures!

The radiator return block, prep’d for drilling:


The sensor hole is drilled out to the right size, ready for tapping:


Sensor hole is tapped (too bad you can’t see the threads due the blurry picture):


The finished product! No leaks and the engine runs great!


CoCo3 Memory Upgrade

August 25, 2009 by Matthew



Like many of you old CoCo users out there, I’ve longed for better hardware and more memory. Recently, I downloaded Paul Barton’s 512k schematic from coco3.com and decided to build the circuit. The motivation for the project came from cloud9tech.com, but due to the notice on their website, I felt my time would be better spent building the upgrade as opposed to waiting for them to do it and ship it. The success of my project came from the documentation on how to install their upgrade, which I assumed was very closely related to Paul Barton’s board.

I began by purchasing a perfboard with solder points from Vetco Electronics, here in Bellevue. Next, I ordered the 30 pin SIMM sockets from Jameco electronics online. The SIMM modules were in a bag of old 486 parts I had in storage, and luckily for me, there were 4 of the 9 chip modules. I measured the board for the SIMM sockets and cut it with a butter knife (I’m low on tool resources as I’m in the process of moving) and a spiral saw bit on my dremel. Then I mounted the wire wrap strip-posts in the appropriate locations. I guess I got lucky with the parts, because everything lined up and the board could be easily inserted/removed from the CoCo3 memory expansion headers.

Not having any way to manufacture an etched circuit board, I decided that wire-wrapping was my best option, which took the better part of the weekend. After many blurry, crosseyed moments and near burns from the soldering iron, I completed the expansion board. Double checking the wire-wraps took about 4 hours, but I verified them by visual cross reference with the schematic, and then with a volt meter to make sure all the connections were good from the expansion headers to the SIMM module pins. Again, another stroke of luck, because not one wire was misplaced! I hope your projects go as smoothly as mine did!

Once the board was tested and the memory modules were snapped into place, I nervously mounted the board in the machine and connected the power. Nothing. Nada. No Disk Basic screen to greet me. In fact, I seemed to be pushing the GIME chip into some rather bizarre contortions, as the poor machine attempted to do something with the electricity I was giving it. Alas, I nearly gave up when I happened to remember reading something about cloud9tech.com’s install directions. And yes, there it was, on the last page: remove the existing memory and bust out 2 filter caps. Easy! Once I removed the memory and the offending capacitors, I plugged everything back in and – voila! My heart jumped at the familiar psychedelic cursor and disk basic welcome message! Success! All my years of failed analog projects, burned IC’s and smoking resistors had paid off in a resounding success.

Included you will find pictures of the memory expansion board. There is one note of caution that I will try to pass on: make sure to measure correctly! While my board may fit horizontally, the memory is too tall and prevents from fitting. Seems like my next project will be to mount everything in a mini-tower PC case. Mod central, here I come!

I hope you enjoyed reading my article, and hopefully I’ll have many more experiences to share with the growing revival of this wonderful little machine.

I’d also like to recommend that you purchase a copy of Portal-9 from Roger Taylor at coco3.com. The IDE is great, and the CCASM support is outstanding. I highly recommend the 6809 for anybody who is interested in learning micro processor programming and assembly language.

Matthew Potter
matthew@synapseware.com

Synchronized Dictionary

August 31, 2007 by Matthew

This is just a simple dictionary object, which derives from System.Collections.Generic.Dictionary<TKey, TValue>.  The idea is to simply provide an efficient and thread-safe dictionary, where 99% of the access methods are reads.  The real-world application of this object is in a web-app: The application maintains a collection of all the valid user objects, for all users that are logged in.

   1: using System;
   2: using System.Collections;
   3: using System.Collections.Generic;
   4: using System.Threading;
   5:  
   6: namespace Utilities
   7: {
   8:     /// <summary>
   9:     /// Provides a thread-safe and lock-efficient dictionary.  Key must
  10:     /// implement the generic IComparable interface, and the value must
  11:     /// be a reference type.
  12:     /// Enumerations are thread-safe, but will block changes to the
  13:     /// dictionary.
  14:     /// The Keys and Values properties are NOT thread-safe and will throw
  15:     /// exceptions if the dictionary is modified while enumerating those
  16:     /// objects.
  17:     /// 
  18:     /// Matthew Potter
  19:     /// 2007-08-31
  20:     /// matthew@synapseware.com
  21:     /// 
  22:     /// You are free to use this code, as long as you leave my author
  23:     /// information intact.
  24:     /// </summary>
  25:     public class SyncLockDictionary<TKey, UValue> : Dictionary<TKey, UValue>
  26:         where TKey: IComparable<TKey>
  27:         where UValue: class
  28:     {
  29:         /// <summary>
  30:         /// Defines the read-lock timeout, in milliseconds.
  31:         /// </summary>
  32:         protected const int READLOCK_TIMEOUT = 100;
  33:  
  34:         /// <summary>
  35:         /// Defines the write-lock timeout, in milliseconds.
  36:         /// </summary>
  37:         protected const int WRITELOCK_TIMEOUT = 250;
  38:  
  39:         /// <summary>
  40:         /// The locking mechanism that provides the thread-safety
  41:         /// </summary>
  42:         private ReaderWriterLock _lock = new ReaderWriterLock ();
  43:  
  44:         /// <summary>
  45:         /// Default Constructor
  46:         /// </summary>
  47:         public SyncLockDictionary ()
  48:             : base ()
  49:         {}
  50:  
  51:         /// <summary>
  52:         /// Copy Constructor
  53:         /// </summary>
  54:         /// <param name="copy"></param>
  55:         public SyncLockDictionary (Dictionary<TKey, UValue> copy)
  56:             : base (copy)
  57:         {}
  58:  
  59:         /// <summary>
  60:         /// Constructor
  61:         /// </summary>
  62:         /// <param name="comparer"></param>
  63:         public SyncLockDictionary (IEqualityComparer<TKey> comparer)
  64:             : base (comparer)
  65:         {}
  66:  
  67:         /// <summary>
  68:         /// Constructor
  69:         /// </summary>
  70:         /// <param name="capacity"></param>
  71:         public SyncLockDictionary (int capacity)
  72:             : base (capacity)
  73:         {}
  74:  
  75:         /// <summary>
  76:         /// Constructor
  77:         /// </summary>
  78:         /// <param name="capacity"></param>
  79:         /// <param name="comparer"></param>
  80:         public SyncLockDictionary (int capacity, IEqualityComparer<TKey> comparer)
  81:             : base (capacity, comparer)
  82:         {
  83:         }
  84:  
  85:         /// <summary>
  86:         /// Add a new value to the dictionary.
  87:         /// </summary>
  88:         /// <param name="key"></param>
  89:         /// <param name="value"></param>
  90:         public new void Add (TKey key, UValue value)
  91:         {
  92:             try
  93:             {
  94:                 _lock.AcquireWriterLock (READLOCK_TIMEOUT);
  95:                 if (base.ContainsKey (key))
  96:                     base [key] = value;
  97:                 else
  98:                     base.Add (key, value);
  99:             }
 100:             finally
 101:             {
 102:                 // release reader lock
 103:                 _lock.ReleaseWriterLock ();
 104:             }
 105:         }
 106:  
 107:         /// <summary>
 108:         /// Remove a value from the dictionary.
 109:         /// </summary>
 110:         /// <param name="key"></param>
 111:         public new void Remove (TKey key)
 112:         {
 113:             try
 114:             {
 115:                 // get read lock and return if nothing to remove
 116:                 _lock.AcquireReaderLock (READLOCK_TIMEOUT);
 117:                 if (!base.ContainsKey (key))
 118:                     return;
 119:  
 120:                 // upgrade to writer lock so we can safely remove the item
 121:                 LockCookie lc = _lock.UpgradeToWriterLock (WRITELOCK_TIMEOUT);
 122:  
 123:                 // remove the item
 124:                 base.Remove (key);
 125:  
 126:                 // downgrade writer lock
 127:                 _lock.DowngradeFromWriterLock (ref lc);
 128:             }
 129:             finally
 130:             {
 131:                 // release reader lock
 132:                 _lock.ReleaseReaderLock ();
 133:             }
 134:         }
 135:  
 136:         /// <summary>
 137:         /// Returns true if the specified key exists in the collection.
 138:         /// </summary>
 139:         /// <param name="key"></param>
 140:         /// <returns></returns>
 141:         public new bool ContainsKey (TKey key)
 142:         {
 143:             try
 144:             {
 145:                 _lock.AcquireReaderLock (READLOCK_TIMEOUT);
 146:  
 147:                 return base.ContainsKey (key);
 148:             }
 149:             finally
 150:             { _lock.ReleaseReaderLock (); }
 151:         }
 152:  
 153:         /// <summary>
 154:         /// Returns true if the specified value exists in the collection.
 155:         /// </summary>
 156:         /// <param name="value"></param>
 157:         /// <returns></returns>
 158:         public new bool ContainsValue (UValue value)
 159:         {
 160:             try
 161:             {
 162:                 _lock.AcquireReaderLock (READLOCK_TIMEOUT);
 163:  
 164:                 return base.ContainsValue (value);
 165:             }
 166:             finally
 167:             { _lock.ReleaseReaderLock (); }
 168:         }
 169:  
 170:         /// <summary>
 171:         /// Gets the value associated with the specified key.  Returns
 172:         /// false if the specified key does not exist in the dictionary.
 173:         /// </summary>
 174:         /// <param name="key"></param>
 175:         /// <param name="value"></param>
 176:         /// <returns></returns>
 177:         public new bool TryGetValue (TKey key, out UValue value)
 178:         {
 179:             try
 180:             {
 181:                 _lock.AcquireReaderLock (READLOCK_TIMEOUT);
 182:  
 183:                 return base.TryGetValue (key, out value);
 184:             }
 185:             finally
 186:             { _lock.ReleaseReaderLock (); }
 187:         }
 188:  
 189:         /// <summary>
 190:         /// Returns the number of items currently in the dictionary.
 191:         /// </summary>
 192:         public new int Count
 193:         {
 194:             get
 195:             {
 196:                 try
 197:                 {
 198:                     _lock.AcquireReaderLock (READLOCK_TIMEOUT);
 199:  
 200:                     return base.Count;
 201:                 }
 202:                 finally
 203:                 { _lock.ReleaseReaderLock (); }
 204:             }
 205:         }
 206:  
 207:         /// <summary>
 208:         /// Returns a thread-safe enumerator for this dictionary (changes
 209:         /// to the dictionary will not be reflected during an enumeration).
 210:         /// </summary>
 211:         /// <returns></returns>
 212:         public new SafeEnumerator GetEnumerator ()
 213:         {
 214:             try
 215:             {
 216:                 _lock.AcquireReaderLock (READLOCK_TIMEOUT);
 217:  
 218:                 ArrayList items = new ArrayList ();
 219:                 Enumerator en = base.GetEnumerator ();
 220:                 while (en.MoveNext ())
 221:                     items.Add (en.Current);
 222:  
 223:                 return new SafeEnumerator (items);
 224:             }
 225:             finally
 226:             { _lock.ReleaseReaderLock (); }
 227:         }
 228:  
 229:         /// <summary>
 230:         /// Returns a reference to the Keys collection.
 231:         /// </summary>
 232:         public new SafeEnumerator Keys
 233:         {
 234:             get
 235:             {
 236:                 try
 237:                 {
 238:                     _lock.AcquireReaderLock (READLOCK_TIMEOUT);
 239:  
 240:                     ArrayList items = new ArrayList ();
 241:                     foreach (object key in base.Keys)
 242:                         items.Add (key.ToString ());
 243:  
 244:                     return new SafeEnumerator (items);
 245:                 }
 246:                 finally
 247:                 { _lock.ReleaseReaderLock (); }
 248:             }
 249:         }
 250:  
 251:         /// <summary>
 252:         /// Returns a reference to the Values collection.
 253:         /// </summary>
 254:         public new SafeEnumerator Values
 255:         {
 256:             get
 257:             {
 258:                 try
 259:                 {
 260:                     _lock.AcquireReaderLock (READLOCK_TIMEOUT);
 261:  
 262:                     ArrayList items = new ArrayList ();
 263:                     foreach (object key in base.Values)
 264:                         items.Add (key);
 265:  
 266:                     return new SafeEnumerator (items);
 267:                 }
 268:                 finally
 269:                 { _lock.ReleaseReaderLock (); }
 270:             }
 271:         }
 272:  
 273:         /// <summary>
 274:         /// Thread-safe accessor property.
 275:         /// </summary>
 276:         /// <param name="key"></param>
 277:         /// <returns></returns>
 278:         public new UValue this [TKey key]
 279:         {
 280:             get
 281:             {
 282:                 try
 283:                 {
 284:                     _lock.AcquireReaderLock (READLOCK_TIMEOUT);
 285:  
 286:                     UValue value = null;
 287:                     if (base.TryGetValue (key, out value))
 288:                         return value;
 289:  
 290:                     return null;
 291:                 }
 292:                 finally
 293:                 { _lock.ReleaseReaderLock (); }
 294:             }
 295:             set
 296:             {
 297:                 try
 298:                 {
 299:                     _lock.AcquireWriterLock (WRITELOCK_TIMEOUT);
 300:                     try
 301:                     {
 302:                         if (base.ContainsKey (key))
 303:                             base [key] = value;
 304:                         else
 305:                             base.Add (key, value);
 306:                     }
 307:                     finally
 308:                     { _lock.ReleaseWriterLock (); }
 309:                 }
 310:                 finally
 311:                 {}
 312:             }
 313:         }
 314:  
 315:         /// <summary>
 316:         /// Gets an object that can be used to synchronize
 317:         /// access to the dictionary.
 318:         /// </summary>
 319:         public object SyncRoot
 320:         {
 321:             get
 322:             { return this; }
 323:         }
 324:     }
 325:  
 326:     /// <summary>
 327:     /// Provides a thread-safe enumerator for a SyncLockDictionary object.
 328:     /// </summary>
 329:     public class SafeEnumerator : System.Collections.IEnumerator, IEnumerable
 330:     {
 331:         private IList    _items;
 332:         private int        _current;
 333:  
 334:  
 335:         /// <summary>
 336:         /// 
 337:         /// </summary>
 338:         /// <param name="synclock"></param>
 339:         public SafeEnumerator (IList items)
 340:         {
 341:             _items        = items;
 342:             _current    = -1;
 343:         }
 344:  
 345:         /// <summary>
 346:         /// 
 347:         /// </summary>
 348:         public object Current
 349:         {
 350:             get
 351:             {
 352:                 if (_current < 0 || 0 == _items.Count)
 353:                     return null;
 354:  
 355:                 return _items [_current];
 356:             }
 357:         }
 358:  
 359:         /// <summary>
 360:         /// 
 361:         /// </summary>
 362:         public void Dispose ()
 363:         {}
 364:  
 365:         /// <summary>
 366:         /// 
 367:         /// </summary>
 368:         object IEnumerator.Current
 369:         {
 370:             get
 371:             {
 372:                 return this.Current;
 373:             }
 374:         }
 375:  
 376:         /// <summary>
 377:         /// 
 378:         /// </summary>
 379:         /// <returns></returns>
 380:         public bool MoveNext ()
 381:         {
 382:             if (_current >= _items.Count)
 383:                 return false;
 384:  
 385:             _current++;
 386:             if (_current < _items.Count)
 387:                 return true;
 388:  
 389:             return false;
 390:         }
 391:  
 392:         /// <summary>
 393:         /// 
 394:         /// </summary>
 395:         public void Reset ()
 396:         {
 397:             _current = -1;
 398:         }
 399:  
 400:         /// <summary>
 401:         /// 
 402:         /// </summary>
 403:         /// <returns></returns>
 404:         IEnumerator IEnumerable.GetEnumerator ()
 405:         {
 406:             return _items.GetEnumerator ();
 407:         }
 408:     }
 409: }

C# HTTP Client

May 14, 2007 by Matthew

This is just a quick class I threw together for SQL Server 2005 – we needed a way to download XML from a web site within a stored procedure. On the surface, this sounds like a gross over-use of the CLR, but it was an elegant solution to an otherwise difficult problem for the specific case we were working on. The code is linked to this post.

HTTP Client code (download ZIP)

   1: using System;
   2: using System.Collections.Generic;
   3: using System.IO;
   4: using System.Net;
   5: using System.Net.Sockets;
   6: using System.Text;
   7: using System.Threading;
   8: using System.Xml;
   9:  
  10: namespace Synapseware.Web
  11: {
  12:     /// <summary>
  13:     /// HttpClient class
  14:     /// </summary>
  15:     public static class HttpClient
  16:     {
  17:         /// <summary>
  18:         /// Calls the target site using an HTTP/1.0 GET.
  19:         /// </summary>
  20:         /// <param name="url">Request URL</param>
  21:         /// <param name="timeOut">Timeout to wait for response, in milliseconds.</param>
  22:         /// <returns></returns>
  23:         public static string GetString (string url, int timeOut)
  24:         {
  25:             Socket        sock            = null;
  26:             string        host            = null;                // host name of request
  27:             string        path            = null;                // path portion of request
  28:             string        request            = null;
  29:             string        response        = null;                // body of HTTP response
  30:             string []    data            = null;                // header block converted to string []
  31:             string []    parts            = null;
  32:             int            pos                = 0;
  33:             int            status            = 0;                // HTTP response code
  34:             int            hdrLen            = 0;                // length of header block
  35:             SocketState    state            = null;
  36:             Dictionary<string, string>
  37:                         headers            = null;                // HTTP headers
  38:  
  39:             try
  40:             {
  41:                 // we don't support SSL!
  42:                 if (url.StartsWith ("https://"))
  43:                     return null;
  44:  
  45:                 // parse up the request string
  46:                 if (url.StartsWith ("http://"))
  47:                     host = url.Substring (7);
  48:                 else
  49:                     host = url;
  50:  
  51:                 // split at the first path delimiter
  52:                 if (-1 != (pos = host.IndexOf ('/')))
  53:                 {
  54:                     path = host.Substring (pos);
  55:                     host = host.Substring (0, pos);
  56:                 }
  57:  
  58:                 // make sure path is correct
  59:                 if (String.IsNullOrEmpty (path) || !path.StartsWith ("/"))
  60:                     path = String.Concat ("/", (path ?? ""));
  61:  
  62:                 // connect to server
  63:                 sock = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  64:                 sock.Blocking = true;
  65:                 sock.Connect (host, 80);
  66:  
  67:                 // create state object
  68:                 state = new SocketState (sock);
  69:  
  70:                 // build request
  71:                 request = String.Format (
  72: @"GET {0} HTTP/1.0
  73: HOST: {1}
  74: Accept: text/\*
  75: Accept-Language: en-us
  76: Cache-Control: no-cache
  77: Content-Length: 0
  78:  
  79: ", path, host);
  80:  
  81:                 // send request and wait for it to complete
  82:                 Send (state, request);
  83:                 state.Done.WaitOne (5000, false);
  84:                 state.Done.Reset ();
  85:  
  86:                 // get the response
  87:                 StartReceive (state);
  88:                 state.Done.WaitOne ();
  89:  
  90:                 // convert the response bytes
  91:                 response = state.Data.ToString ();
  92:  
  93:                 // check for HTTP header end
  94:                 if (-1 == (hdrLen = response.IndexOf ("\r\n\r\n")))
  95:                     return null;
  96:  
  97:                 // parse out header data
  98:                 data = response.Substring (0, hdrLen).Replace ("\r\n", "\n").Split ('\n');
  99:                 if (null == data || 0 == data.Length)
 100:                     return null;
 101:  
 102:                 // get response status code
 103:                 parts = data [0].Split (' ');
 104:                 status = Int32.Parse (parts [1]);
 105:                 if (200 != status)
 106:                     return null;
 107:  
 108:                 // turn header array collection into a collection
 109:                 headers = new Dictionary<string, string> ();
 110:                 foreach (string hdr in data)
 111:                 {
 112:                     if (-1 == (pos = hdr.IndexOf (' ')))
 113:                         continue;
 114:                     if (hdr.StartsWith ("HTTP"))
 115:                         continue;
 116:                     headers.Add (hdr.Substring (0, pos), hdr.Substring (pos + 1));
 117:                 }
 118:  
 119:                 return response.Substring (hdrLen + 4);
 120:             }
 121:             catch
 122:             {
 123:                 return null;
 124:             }
 125:             finally
 126:             {
 127:                 // close the connection
 128:                 if (null != sock && sock.Connected)
 129:                 {
 130:                     sock.Disconnect (false);
 131:                     sock.Close ();
 132:                 }
 133:             }
 134:         }
 135:  
 136:         /// <summary>
 137:         /// Sends string data over the socket.
 138:         /// </summary>
 139:         /// <param name="client"></param>
 140:         /// <param name="data"></param>
 141:         private static void Send (SocketState state, string data)
 142:         {
 143:             // Convert the string data to byte data using ASCII encoding.
 144:             byte [] byteData = Encoding.ASCII.GetBytes (data);
 145:  
 146:             // Begin sending the data to the remote device.
 147:             state.Socket.BeginSend (byteData, 0, byteData.Length, 0,
 148:                 new AsyncCallback (SendCallback), state);
 149:         }
 150:  
 151:         /// <summary>
 152:         /// Send data callback.
 153:         /// </summary>
 154:         /// <param name="ar"></param>
 155:         private static void SendCallback (IAsyncResult ar)
 156:         {
 157:             SocketState    state        = null;
 158:             Socket        client        = null;
 159:  
 160:             try
 161:             {
 162:                 // Retrieve the socket from the state object.
 163:                 state = ar.AsyncState as SocketState;
 164:                 client = state.Socket;
 165:  
 166:                 // Complete sending the data to the remote device.
 167:                 client.EndSend (ar);
 168:  
 169:                 // Signal that all bytes have been sent.
 170:                 state.Done.Set ();
 171:             }
 172:             catch
 173:             { }
 174:         }
 175:  
 176:         /// <summary>
 177:         /// Main receive thread entry point
 178:         /// </summary>
 179:         /// <param name="stateInfo"></param>
 180:         private static void StartReceive (SocketState state)
 181:         {
 182:             if (null == state)
 183:                 return;
 184:  
 185:             state.Socket.BeginReceive (
 186:                   state.ReadBuffer,
 187:                   0,
 188:                   state.ReadBuffer.Length,
 189:                   SocketFlags.None,
 190:                   new AsyncCallback (OnReceiveData),
 191:                   state
 192:             );
 193:         }
 194:  
 195:         /// <summary>
 196:         /// Receive data callback.
 197:         /// </summary>
 198:         /// <param name="stateInfo"></param>
 199:         private static void OnReceiveData (IAsyncResult result)
 200:         {
 201:             SocketState        state        = null;
 202:             Socket            sock        = null;
 203:             int                read        = 0;
 204:  
 205:             if (null == result)
 206:                 return;
 207:  
 208:             if (null == (state = result.AsyncState as SocketState))
 209:                 return;
 210:  
 211:             // get socket
 212:             sock = state.Socket;
 213:  
 214:             // end the read
 215:             if (0 != (read = sock.EndReceive (result)))
 216:             {
 217:                 state.Data.Append (Encoding.ASCII.GetString (state.ReadBuffer, 0, read));
 218:  
 219:                 // start another read
 220:                 sock.BeginReceive (
 221:                        state.ReadBuffer,
 222:                        0,
 223:                        state.ReadBuffer.Length,
 224:                        SocketFlags.None,
 225:                        new AsyncCallback (OnReceiveData),
 226:                        state
 227:                 );
 228:             }
 229:             else
 230:             {
 231:                 if (state.Data.Length > 0)
 232:                 {
 233:                     state.Socket.Close ();
 234:                     state.Done.Set ();
 235:                 }
 236:             }
 237:         }
 238:     }
 239:  
 240:     /// <summary>
 241:     /// SocketState class
 242:     /// 
 243:     /// Used to track an async TCP/IP data, and maintain all data received over the async operation.
 244:     /// </summary>
 245:     internal class SocketState
 246:     {
 247:         /// <summary>
 248:         /// Constructor
 249:         /// </summary>
 250:         public SocketState ()
 251:         {
 252:             Socket        = null;
 253:             ReadBuffer    = new byte [BUFFER_SIZE];
 254:             Data        = new StringBuilder ();
 255:             Done        = new ManualResetEvent (false);
 256:         }
 257:  
 258:         /// <summary>
 259:         /// Constructor
 260:         /// </summary>
 261:         /// <param name="socket"></param>
 262:         public SocketState (Socket socket)
 263:             : this ()
 264:         {
 265:             Socket = socket;
 266:         }
 267:  
 268:         /// <summary>
 269:         /// TCP/IP socket.
 270:         /// </summary>
 271:         public Socket Socket = null;
 272:  
 273:         /// <summary>
 274:         /// Size of download buffer.
 275:         /// </summary>
 276:         public const int BUFFER_SIZE = 1024;
 277:  
 278:         /// <summary>
 279:         /// Download buffer.
 280:         /// </summary>
 281:         public byte [] ReadBuffer;
 282:  
 283:         /// <summary>
 284:         /// Downloaded data converted to a string builder.
 285:         /// </summary>
 286:         public StringBuilder Data;
 287:  
 288:         /// <summary>
 289:         /// Reset event for synchronization.
 290:         /// </summary>
 291:         public ManualResetEvent Done;
 292:     }
 293: }