public bool sendObject(UAVObject obj, bool acked, bool allInstances) {
		    if (acked) {
                return objectTransaction(obj, uavConsts.TYPE_OBJ_ACK, allInstances);
		    } else {
                return objectTransaction(obj, uavConsts.TYPE_OBJ, allInstances);
		    }
	    }
 TreeNode addNode(UAVObject b)
 {
     if (InvokeRequired)
         return (TreeNode)this.Invoke(new addnodeDelegate(addNode), b);
     else
     {
         TreeNode n = treeView1.Nodes.Add(b.name);
         foreach (var prop in b.GetType().GetFields().Where(j => j.FieldType.BaseType == typeof(UAVObjectField)))
         {
             UAVObjectField f = (UAVObjectField)prop.GetValue(b);
             TreeNode newnode = n.Nodes.Add(f.getName());
             if (f.getNumElements() > 1)
             {
                 for (int i = 0; i < f.getNumElements(); i++)
                 {
                     newnode.Nodes.Add(i.ToString());
                 }
             }
             /*if (fields.ContainsKey(f))
             {
                 int n = f.getNumElements();
                 if (n == 1)
                     fields[f] = f.getValue();
                 else
                 {
                     object[] vals = new object[n];
                     for (int i = 0; i < n; i++)
                         vals[i] = f.getValue(i);
                     fields[f] = vals;
                 }
             }*/
         }
         return n;
     }
 }
        private bool objectTransaction(UAVObject obj, int type, bool allInstances) {
            if (type == uavConsts.TYPE_OBJ_ACK || type == uavConsts.TYPE_OBJ_REQ || type == uavConsts.TYPE_OBJ)
            {
			    return transmitObject(obj, type, allInstances);
		    } else {
			    return false;
		    }
	    }
        public UAVMetaObject(long objID, String name, UAVDataObject parent) : base(objID, true, name) {
		    this.parent = parent;

		    ownMetadata = new Metadata();

		    ownMetadata.flags = 0; // TODO: Fix flags
		    ownMetadata.gcsTelemetryUpdatePeriod = 0;
		    ownMetadata.loggingUpdatePeriod = 0;


		    List<String> modesBitField = new List<String>();
		    modesBitField.Add("FlightReadOnly");
		    modesBitField.Add("GCSReadOnly");
		    modesBitField.Add("FlightTelemetryAcked");
		    modesBitField.Add("GCSTelemetryAcked");
		    modesBitField.Add("FlightUpdatePeriodic");
		    modesBitField.Add("FlightUpdateOnChange");
		    modesBitField.Add("GCSUpdatePeriodic");
		    modesBitField.Add("GCSUpdateOnChange");

            List<UAVObjectField> fields = new List<UAVObjectField>();
		    fields.Add( new UAVObjectField<bool>("Modes", "", 1, modesBitField, parent) );
            fields.Add(new UAVObjectField<UInt16>("Flight Telemetry Update Period", "ms", 1, null, parent));
            fields.Add(new UAVObjectField<UInt16>("GCS Telemetry Update Period", "ms", 1, null, parent));
            fields.Add(new UAVObjectField<UInt16>("Logging Update Period", "ms", 1, null, parent));

		    int numBytes = fields.Sum(j=>j.getNumBytes());
		    
		    // Initialize object

		    // Initialize parent
		    base.initialize(0);
		    initializeFields(fields, new ByteBuffer(numBytes), numBytes);

		    // Setup metadata of parent
		    parentMetadata = parent.getDefaultMetadata();
	    }
 public abstract void initialize(UAVObject obj);
 public abstract void TransactionFailed(UAVObject data);
 public abstract void TransactionSucceeded(UAVObject data);
        public bool sendObjectRequest(UAVObject obj, bool allInstances) {
		    return objectTransaction(obj, uavConsts.TYPE_OBJ_REQ, allInstances);
	    }
        private void updateObjReq(UAVObject obj) {
		    bool succeeded = false;

		    // The lock on UAVTalk must be release before the transaction succeeded signal is sent
		    // because otherwise if a transaction timeout occurs at the same time we can get a
		    // deadlock:
		    // 1. processInputStream -> updateObjReq (locks uavtalk) -> tranactionCompleted (locks transInfo)
		    // 2. transactionTimeout (locks transInfo) -> sendObjectRequest -> ? -> setupTransaction (locks uavtalk)
            lock (updateObjReqSyncLock)
            {
			    if(respObj != null && respType == uavConsts.TYPE_OBJ_REQ && respObj.getObjID() == obj.getObjID() &&
					    ((respObj.getInstID() == obj.getInstID() || !respAllInstances))) {

				    // Indicate complete
				    respObj = null;
				    succeeded = true;
			    }
		    }

		    // Notify listener
		    if (succeeded && transactionListener != null)
				    transactionListener.TransactionSucceeded(obj);
	    }
        /**
	     * UAVTalk takes care of it's own transactions but if the caller knows
	     * it wants to give up on one (after a timeout) then it can cancel it
	     * @return True if that object was pending, False otherwise
	     */
        public bool cancelPendingTransaction(UAVObject obj) {
		    lock (respObj) {
			    if(respObj != null && respObj.getObjID() == obj.getObjID()) {
				    if(transactionListener != null) {
					   Debug.WriteLine("Canceling transaction: " + respObj.getName());
					    transactionListener.TransactionFailed(respObj);
				    }
				    respObj = null;
				    return true;
			    } else
				    return false;
		    }
	    }
        /**
	     * This is the code that sets up a new UAVTalk packet that expects a response.
	     */
        private void setupTransaction(UAVObject obj, bool allInstances, int type) {
            lock(this)
            {
			    // Only cancel if it is for a different object
			    if(respObj != null && respObj.getObjID() != obj.getObjID())
				    cancelPendingTransaction(obj);

			    respObj = obj;
			    respAllInstances = allInstances;
			    respType = type;
		    }
	    }
        /**
	     * Send an object through the telemetry link.
	     * @throws IOException
	     * @param[in] obj Object handle to send
	     * @param[in] type Transaction type \return Success (true), Failure (false)
	     */
        private bool transmitSingleObject(UAVObject obj, int type, bool allInstances)
        {
            int length;
            int allInstId = uavConsts.ALL_INSTANCES;

            ByteBuffer bbuf = new ByteBuffer(uavConsts.MAX_PACKET_LENGTH);
            
            // Determine data length
            if (type == uavConsts.TYPE_OBJ_REQ || type == uavConsts.TYPE_ACK)
            {
                length = 0;
            }
            else
            {
                length = obj.getNumBytes();
            }

            // Setup type and object id fields
            bbuf.put((byte)(uavConsts.SYNC_VAL & 0xff));
            bbuf.put((byte)(type & 0xff));
            bbuf.putShort((UInt16)(length + 2 /* SYNC, Type */+ 2 /* Size */+ 4 /* ObjID */+ (obj
                            .isSingleInstance() ? 0 : 2)));
            bbuf.putUint32((UInt32)obj.getObjID());

            // Setup instance ID if one is required
            if (!obj.isSingleInstance())
            {
                // Check if all instances are requested
                if (allInstances)
                    bbuf.putShort((UInt16)(allInstId & 0xffff));
                else
                    bbuf.putShort((UInt16)(obj.getInstID() & 0xffff));
            }

            // Check length
            if (length >= uavConsts.MAX_PAYLOAD_LENGTH)
                return false;

            // Copy data (if any)
            if (length > 0)
                try
                {
                    if (obj.pack(bbuf) == 0)
                        return false;
                }
                catch (Exception e)
                {
                    // TODO Auto-generated catch block
                    Debug.Write(e.Message);
                    return false;
                }

            // Calculate checksum
            bbuf.put((byte)(CRC.updateCRC(0, bbuf.array(), bbuf.position()) & 0xff));

            int packlen = bbuf.position();
            bbuf.position(0);
            byte[] dst = new byte[packlen];
            bbuf.get(dst, 0, packlen);

            if (type == uavConsts.TYPE_OBJ_ACK || type == uavConsts.TYPE_OBJ_REQ)
            {
                // Once we send a UAVTalk packet that requires an ack or object let's set up
                // the transaction here
                setupTransaction(obj, allInstances, type);
            }

            ch.write(dst);


            // Update stats
            ++txStats.Objects;
            txStats.Bytes += bbuf.position();
            txStats.ObjectBytes += length;

            // Done
            return true;
        }
        /**
	     * Send an object through the telemetry link.
	     * @param[in] obj Object to send
	     * @param[in] type Transaction type
	     * @param[in] allInstances True is all instances of the object are to be sent
	     * @return Success (true), Failure (false)
	     * @throws IOException
	     */
	    private bool transmitObject(UAVObject obj, int type, bool allInstances) 
        {
		    // If all instances are requested on a single instance object it is an
		    // error
		    if (allInstances && obj.isSingleInstance()) {
			    allInstances = false;
		    }

		    // Process message type
            if (type == uavConsts.TYPE_OBJ || type == uavConsts.TYPE_OBJ_ACK)
            {
			    if (allInstances) {
				    // Get number of instances
				    int numInst = objMgr.getNumInstances(obj.getObjID());
				    // Send all instances
				    for (int instId = 0; instId < numInst; ++instId) {
					    // TODO: This code is buggy probably.  We should send each request
					    // and wait for an ack in the case of an TYPE_OBJ_ACK
                        Debug.Assert(type != uavConsts.TYPE_OBJ_ACK); // catch any buggy calls

					    UAVObject inst = objMgr.getObject(obj.getObjID(), instId);
					    transmitSingleObject(inst, type, false);
				    }
				    return true;
			    } else {
				    return transmitSingleObject(obj, type, false);
			    }
            }
            else if (type == uavConsts.TYPE_OBJ_REQ)
            {
                return transmitSingleObject(obj, uavConsts.TYPE_OBJ_REQ, allInstances);
            }
            else if (type == uavConsts.TYPE_ACK)
            {
			    if (!allInstances) {
                    return transmitSingleObject(obj, uavConsts.TYPE_ACK, false);
			    } else {
				    return false;
			    }
		    } else {
			    return false;
		    }
	    }
	    private void updateAck(UAVObject obj) {
            lock (updateAckSyncLock)
            {
                Debug.WriteLine("Received ack: " + obj.getName());
                //Assert.assertNotNull(obj);
                if (respObj != null && respObj.getObjID() == obj.getObjID()
                        && (respObj.getInstID() == obj.getInstID() || respAllInstances))
                {

                    // Indicate complete
                    respObj = null;

                    // Notify listener
                    if (transactionListener != null)
                        transactionListener.TransactionSucceeded(obj);
                }
            }
	    }
	    private void receivedNack(UAVObject obj)
	    {
            lock (receivedNackSyncLock)
            {
                if (respObj != null && (respType == uavConsts.TYPE_OBJ_REQ || respType == uavConsts.TYPE_OBJ_ACK) &&
                        respObj.getObjID() == obj.getObjID())
                {

                    Debug.WriteLine("NAK: " + obj.getName());

                    // Indicate complete
                    respObj = null;

                    // Notify listener
                    if (transactionListener != null)
                        transactionListener.TransactionFailed(obj);
                }
            }
	    }