示例#1
0
        /// <summary>
        /// Convert raw message to BabelMessage.
        /// Called by a port with an incoming raw message.
        /// Must return as soon as possible, so convert and put on incoming Q for later relay.
        /// Caller frees the underlying raw message.
        /// TODO: Process long message if necessary: start a long list.
        /// </summary>
        /// <param name="exchange"></param>
        /// <param name="mtx"></param>
        /// <returns></returns>
        public static byte ProcessIncomingRawMesssage(MessageExchange exchange, MessageTransaction mtx)
        {
            PacketBuffer g = mtx.MsgBuffer;
            BabelMessage m = new BabelMessage(exchange);

            m.Pid                = (byte)(g.flagsPid & ProtocolConstants.PID_MASK);
            m.Verified           = (m.Pid == ProtocolConstants.PID_GENERAL_V);
            m.Receiver           = ProtocolConstants.ADRS_LOCAL;
            m.FlagsRS            = g.flagsRS();
            m.IncomingNetIfIndex = mtx.ONetIfIndex;
            m.OutgoingNetIfIndex = ProtocolConstants.NETIF_UNSET;
            m.Cmd                = 0;
            switch (m.Pid)
            {
            case ProtocolConstants.PID_GENERAL:
            case ProtocolConstants.PID_GENERAL_V:
                m.IsGeneral   = true;
                m.IsHandshake = false;
                m.Receiver    = g.receiver();
                m.Cmd         = g.command();
                m.FlagsRS     = g.flagsRS();
                break;

            default:
                return(1);
            }
            m.Sender   = g.sender();
            m.SenderId = g.senderId();
            m.DataLen  = g.dataLength();
            m.DataAry  = mtx.CopyMessageData();
            // Now submit message to be relayed later.
            exchange.SubmitIncomingMessage(m);
            return(0);
        }
示例#2
0
        public static List <double> ProcessReadVarMessageViaOffsets(BabelMessage msg, List <long> offsetTable)
        {
            int           n = offsetTable.Count;
            List <double> p;

            if (n == 0)
            {
                return(null);
            }
            p = new List <double>(n);
            for (int k = 0; k < n; k++)
            {
                long v = offsetTable[k];
                // (paramIndex<<24) | (((int)paramVarKind) << 16) | (dataSize << 8) | idx)
                int idx = (int)(v & 0xff);
                v >>= 8;
                int len = (int)(v & 0xff);
                v >>= 8;
                VariableKind paramVarKind = (VariableKind)(v & 0xff);
                try {
                    p.Add(VariableValue.GetDouble(paramVarKind, msg.DataAry, idx, len));
                } catch (Exception) {
                    // Index out of range.
                    return(null);
                }
            }
            return(p);
        }
示例#3
0
 /// <summary>
 /// Incoming messages get routed to here by the MediatorNetIf.
 /// </summary>
 /// <param name="message"></param>
 public void SubmitIncomingMessage(BabelMessage message)
 {
     if (message != null)
     {
         IncomingQueue.Add(message);
     }
 }
示例#4
0
 // Waits for incoming data messages to add to cache.
 protected override void ServiceTask()
 {
     if (Hub == null)
     {
         ProtocolCommands.Commander.Exchanges.TryGetValue(ExchangeName, out Hub);
     }
     if (Hub != null)
     {
         if (Hub.Exchange.IsClosingState())
         {
             Hub = null;
             OffsetTable.Clear();
         }
         else
         {
             BabelMessage b = Hub.GetMessageFromQueue(MessageId);
             if (b != null)
             {
                 if (OffsetTable.Count == 0)
                 {
                     ParameterManager.ProcessReadVarMessage(b, null, null, null, null, OffsetTable);
                 }
                 AddPoint(ParameterManager.ProcessReadVarMessageViaOffsets(b, OffsetTable));
                 return;
             }
         }
     }
     Thread.Sleep(1000);
 }
示例#5
0
 /**
  * Asynchronously send a message using activity context.
  *
  * @param message
  *            The message to send.
  * @param handler
  *            Optional handler for reply. A new Activity Ui thread is used to invoke handler.
  * @param activity
  *            The activity to post replies to.
  * Returns true if message was submitted successfully.
  */
 public bool SubmitMessage(BabelMessage message, IMessageHandler handler, Shell shell, int numReplies)
 {
     if (message != null && (OutgoingQueue.Size() < OutgoingCapacity))
     {
         OutgoingQueue.Add(new MessageBinder(this, message, handler, MessageHandlerKind.Shell, shell, message.SenderId, numReplies));
         return(true);
     }
     return(false);
 }
示例#6
0
 /**
  * Asynchronously send a message using server context.
  *
  * @param message
  *            The message to send.
  * @param handler
  *            Optional handler for reply.
  * @param createThread.
  *            Either use a new thread or service receiver thread to invoke handler.
  * Returns true if message was submitted successfully.
  */
 public bool SubmitMessage(BabelMessage message, IMessageHandler handler, bool createThread, int numReplies)
 {
     if (message != null && (OutgoingQueue.Size() < OutgoingCapacity))
     {
         OutgoingQueue.Add(new MessageBinder(this, message, handler, createThread ? MessageHandlerKind.Thread : MessageHandlerKind.Normal, null, message.SenderId, numReplies));
         return(true);
     }
     return(false);
 }
示例#7
0
        public void AddToQueue(int id, BabelMessage m)
        {
            LinkedBlockingCollection <BabelMessage> q = GetQueue(id);

            if (q == null)
            {
                q = new LinkedBlockingCollection <BabelMessage>();
                IncomingQueues.TryAdd(id, q);
            }
            q.Add(m);
        }
示例#8
0
 public MessageBinder(MessageExchange exchange, BabelMessage message,
                      MessageExchange.IMessageHandler handler,
                      MessageExchange.MessageHandlerKind kind, Object context, byte ident, int numReplies)
 {
     Exchange    = exchange;
     Message     = message;
     Reply       = null;
     Handler     = handler;
     Kind        = kind;
     Context     = context;
     Ident       = ident;
     NumReplies  = numReplies;
     ElapsedTime = DateTime.UtcNow.Ticks;
 }
示例#9
0
        public static BabelMessage CreateHandshakeMessage(MessageExchange exchange,
                                                          Router.RouterAction dispatch, byte postNetIfIndex, byte pid, byte arg)
        {
            BabelMessage m = new BabelMessage(exchange);

            m.IsHandshake        = true;
            m.IsGeneral          = false;
            m.Pid                = pid;
            m.Arg                = arg;
            m.PostNetIfIndex     = postNetIfIndex;
            m.Dispatch           = dispatch;
            m.IncomingNetIfIndex = ProtocolConstants.NETIF_UNSET;
            m.OutgoingNetIfIndex = ProtocolConstants.NETIF_UNSET;
            return(m);
        }
示例#10
0
        public static BabelMessage CreateCommandMessage(MessageExchange exchange, bool verified,
                                                        Router.RouterAction dispatch, byte postNetIfIndex, byte cmd, ushort receiver,
                                                        ushort sender, byte flagsRS, byte ident, byte dataLen, byte dataOffset, byte[] dataAry)
        {
            BabelMessage m;

            if (dataLen >= ProtocolConstants.GENERAL_TAIL_SIZE)
            {
                return(null); // Longer messages not implemented yet.
            }
            m                    = new BabelMessage(exchange);
            m.IsHandshake        = false;
            m.IsGeneral          = true;
            m.Verified           = verified;
            m.PostNetIfIndex     = postNetIfIndex;
            m.Dispatch           = dispatch;
            m.IncomingNetIfIndex = ProtocolConstants.NETIF_UNSET;
            m.OutgoingNetIfIndex = ProtocolConstants.NETIF_UNSET;
            m.Cmd                = cmd;
            m.Receiver           = receiver;
            m.Sender             = sender;
            m.FlagsRS            = flagsRS;
            m.SenderId           = ident;
            m.DataLen            = dataLen;
            if (dataOffset <= 0)
            {
                m.DataAry = dataAry;
            }
            else
            {
                byte[] ary = new byte[dataAry.Length + dataOffset];
                Array.Copy(dataAry, 0, ary, dataOffset, dataAry.Length);
                m.DataAry = ary;
            }
            return(m);
        }
示例#11
0
        // Log a message to Log port (default isNETIF_USB_DEV_0).
        // Prefixes BabelMilliTicker binary value to start.
        // Truncates message if too long.
        // Returns zero on success.
        public static int Logger(MessageExchange exchange, byte logNetIfIndex, byte[] buffer)
        {
            byte len = Primitives.Strlen(buffer);
            byte max = (byte)(exchange.Manager.MaxPacketSize - ProtocolConstants.GENERAL_OVERHEADS_SIZE - ProtocolConstants.TICKER_SIZE);

            if (len > max)
            {
                len = max;
            }
            BabelMessage message = BabelMessage.CreateCommandMessage(exchange, false,
                                                                     Router.RouterAction.PostToNetIf, logNetIfIndex,
                                                                     ProtocolConstants.MEDIATOR_DEVICE_LOG,
                                                                     ProtocolConstants.ADRS_LOCAL,
                                                                     ProtocolConstants.ADRS_LOCAL, 0,
                                                                     ProtocolConstants.IDENT_MEDIATOR, len, ProtocolConstants.TICKER_SIZE, buffer);

            byte[] tmp = Primitives.UIntToByteArray(Primitives.GetBabelMilliTicker());
            Array.Copy(tmp, message.DataAry, tmp.Length);
            if (!message.Exchange.SubmitMessage(message, null, false, 0))
            {
                return(1);
            }
            return(0);
        }
示例#12
0
        // Process read variable reply.
        // <cmd,> {readId, cmdFlags, page, numRead:numToRead, {parameterIndex}+ } [data]*.
        // Store results in tables.
        public static int ProcessReadVarMessage(BabelMessage msg,
                                                ParameterManager manager,
                                                Dictionary <int, DeviceParameter> indexTable,
                                                Dictionary <string, DeviceParameter> nameTable,
                                                Dictionary <int, String> indexToNameTable,
                                                List <long> offsetTable = null)
        {
            int numProcessed = 0;

            if (msg.DataLen > 5)
            {
                DeviceParameter d;
                String          name;
                bool            hasRamValue, hasEEPromValue, hasDefaultValue;
                bool            hasMinMaxValue, hasDataFlags;
                bool            isNewParam, notInNameTable, notInIndexTable;
                bool            hasMeta, hasKindOnly;
                VariableKind    paramVarKind;
                VariableValue   ramValue, eepromValue, defaultValue;
                VariableValue   minValue, maxValue;
                int             readId, cmdFlags, pageNum, pIdx, numRead, numToRead, dataSize, dataFlags, argsFlags;
                int             idx = 0, n = msg.DataLen, offsetIndex = 0;
                readId    = (msg.DataAry[idx++] & 0xff);
                cmdFlags  = (msg.DataAry[idx++] & 0xff);
                pageNum   = (msg.DataAry[idx++] & 0xff);
                numToRead = (msg.DataAry[idx] & 0x0f);
                numRead   = (msg.DataAry[idx++] & 0xf0) >> 4;
                pIdx      = idx;
                idx      += numToRead;
                if (numRead == 0)
                {
                    return(numProcessed);
                }
                hasKindOnly = ((cmdFlags & ProtocolConstants.MEDIATOR_DEVICE_RWV_FLAGS_PACK_KIND) != 0);
                hasMeta     = hasKindOnly || ((cmdFlags & ProtocolConstants.MEDIATOR_DEVICE_RWV_FLAGS_PACK) == 0);
                // Now read in values.
                while (idx < n)
                {
                    int paramIndex = msg.DataAry[pIdx++];
                    d               = null;
                    name            = null;
                    hasRamValue     = false;
                    hasEEPromValue  = false;
                    hasDefaultValue = false;
                    hasMinMaxValue  = false;
                    hasDataFlags    = false;
                    isNewParam      = false;
                    notInNameTable  = true;
                    notInIndexTable = true;
                    dataFlags       = 0;
                    defaultValue    = null;
                    eepromValue     = null;
                    ramValue        = null;
                    minValue        = null;
                    maxValue        = null;
                    // First get VariableKind.
                    if (hasMeta)
                    {
                        paramVarKind = (VariableKind)(msg.DataAry[idx++] & 0xff);
                    }
                    else
                    {
                        if (indexTable == null)
                        {
                            return(numProcessed);
                        }
                        indexTable.TryGetValue(paramIndex, out d);
                        notInIndexTable = (d == null);
                        if (d == null)
                        {
                            return(numProcessed);
                        }
                        paramVarKind = d.ParamVarKind;
                    }
                    dataSize = VariableValue.DataSize(paramVarKind);
                    if (paramVarKind != VariableKind.VK_None)
                    {
                        if (dataSize == 0)
                        {
                            return(numProcessed);
                        }
                        if (hasMeta && !hasKindOnly)
                        {
                            // Next read StorageFlags.
                            if ((idx + 1) <= n)
                            {
                                hasDataFlags = true;
                                dataFlags    = (msg.DataAry[idx++] & 0xff);
                            }
                            else
                            {
                                return(numProcessed);
                            }
                            // Next read ArgsFlags.
                            if ((idx + 1) <= n)
                            {
                                argsFlags = (msg.DataAry[idx++] & 0xff);
                            }
                            else
                            {
                                return(numProcessed);
                            }
                            offsetIndex = idx;
                        }
                        else
                        {
                            if (hasKindOnly)
                            {
                                offsetIndex = idx;
                            }
                            hasDataFlags = true;
                            dataFlags    = (int)StorageFlags.SF_Dynamic;
                            argsFlags    = ProtocolConstants.MEDIATOR_DEVICE_RWV_FLAGS_RAM;
                        }
                        // Then work through cmdFlags:
                        if ((argsFlags & ProtocolConstants.MEDIATOR_DEVICE_RWV_FLAGS_RAM) != 0)
                        {
                            if ((idx < n) && (paramVarKind == VariableKind.VK_String))
                            {
                                dataSize = (msg.DataAry[idx++] & 0xff);
                            }
                            if ((idx + dataSize) <= n)
                            {
                                hasRamValue = true;
                                ramValue    = new VariableValue(paramVarKind, msg.DataAry, idx, dataSize);
                                idx        += dataSize;
                            }
                            else
                            {
                                return(numProcessed);
                            }
                        }
                        if ((argsFlags & ProtocolConstants.MEDIATOR_DEVICE_RWV_FLAGS_EEPROM) != 0)
                        {
                            if ((idx < n) && (paramVarKind == VariableKind.VK_String))
                            {
                                dataSize = (msg.DataAry[idx++] & 0xff);
                            }
                            if ((idx + dataSize) <= n)
                            {
                                hasEEPromValue = true;
                                eepromValue    = new VariableValue(paramVarKind, msg.DataAry, idx, dataSize);
                                idx           += dataSize;
                            }
                            else
                            {
                                return(numProcessed);
                            }
                        }
                        if ((argsFlags & ProtocolConstants.MEDIATOR_DEVICE_RWV_FLAGS_DEFAULT) != 0)
                        {
                            if ((idx + dataSize) <= n)
                            {
                                hasDefaultValue = true;
                                defaultValue    = new VariableValue(paramVarKind, msg.DataAry, idx, dataSize);
                                idx            += dataSize;
                            }
                            else
                            {
                                return(numProcessed);
                            }
                        }
                        if ((argsFlags & ProtocolConstants.MEDIATOR_DEVICE_RWV_FLAGS_RANGE) != 0)
                        {
                            // Read in dataSize, category, min, max.
                            if ((idx + 2 + 2 * dataSize) <= n)
                            {
                                idx++; // Skip dataSize.
                                idx++; // Skip category.
                                hasMinMaxValue = true;
                                minValue       = new VariableValue(paramVarKind, msg.DataAry, idx, dataSize);
                                idx           += dataSize;
                                maxValue       = new VariableValue(paramVarKind, msg.DataAry, idx, dataSize);
                                idx           += dataSize;
                            }
                            else
                            {
                                return(numProcessed);
                            }
                        }
                        // Finally check for name.
                        if ((argsFlags & ProtocolConstants.MEDIATOR_DEVICE_RWV_FLAGS_NAME) != 0)
                        {
                            byte[] buffer = new byte[msg.DataAry.Length];
                            byte   b;
                            int    k = 0, len = 0;
                            if (idx < n)   // Get len byte.
                            {
                                len = (msg.DataAry[idx++] & 0xff);
                            }
                            while (idx < n)
                            {
                                if (len-- == 0)
                                {
                                    break;
                                }
                                b = (byte)(msg.DataAry[idx++] & 0xff);
                                if (b == 0)
                                {
                                    break;
                                }
                                buffer[k++] = b;
                            }
                            try {
                                name = Encoding.UTF8.GetString(buffer, 0, k);
                            } catch (Exception) {
                                name = null;
                            }
                            if (name != null)
                            {
                                name = name.Trim().ToUpper();
                                if (name.Length < 2 || name.Length > 8)
                                {
                                    name = null;
                                }
                            }
                        }
                    }
                    if (hasMeta && (offsetTable != null) && (offsetIndex < idx))
                    {
                        offsetTable.Add((paramIndex << 24) | (((int)paramVarKind) << 16) | (dataSize << 8) | offsetIndex);
                    }
                    // Now update device profile.
                    if (name == null && indexToNameTable != null)
                    {
                        indexToNameTable.TryGetValue(paramIndex, out name);
                        if (name == null)
                        {
                            Log.w(TAG, "ProcessReadVarMessage: no name for device parameter:" + paramIndex + ".");
                        }
                    }
                    // First look for parameter by name:
                    if (name != null && nameTable != null)
                    {
                        nameTable.TryGetValue(name, out d);
                        notInNameTable = (d == null);
                    }
                    if (d == null && indexTable != null)
                    {
                        indexTable.TryGetValue(paramIndex, out d);
                        notInIndexTable = (d == null);
                    }
                    if (d != null && name != null)
                    {
                        d.ParamName = name;
                    }
                    if (d == null)
                    {
                        d          = new DeviceParameter(name, paramIndex, paramVarKind, (StorageFlags)dataFlags, dataSize, hasMinMaxValue, minValue, maxValue, defaultValue);
                        isNewParam = true;
                    }
                    if (hasDataFlags)
                    {
                        d.ParamStorageFlags = (StorageFlags)dataFlags;
                        d.IsDynamic         = ((dataFlags & (int)StorageFlags.SF_Dynamic) != 0);
                        d.IsReadOnly        = ((dataFlags & (int)StorageFlags.SF_ReadOnly) != 0);
                        d.IsEEProm          = ((dataFlags & (int)StorageFlags.SF_EEPROM) != 0);
                        if (!d.IsEEProm)
                        {
                            hasEEPromValue = false;
                        }
                    }
                    if (hasRamValue)
                    {
                        if (isNewParam || !VariableValue.Equal(ramValue, d.RamValue))
                        {
                            d.HasChanged = true;
                        }
                        d.RamValue    = ramValue;
                        d.HasRamValue = true;
                    }
                    if (hasEEPromValue)
                    {
                        if (isNewParam || !VariableValue.Equal(eepromValue, d.EEPromValue))
                        {
                            d.HasChanged = true;
                        }
                        d.EEPromValue    = eepromValue;
                        d.HasEEPromValue = true;
                    }
                    if (hasDefaultValue)
                    {
                        if (isNewParam || !VariableValue.Equal(defaultValue, d.DefaultValue))
                        {
                            d.HasChanged = true;
                        }
                        d.DefaultValue    = defaultValue;
                        d.HasDefaultValue = true;
                    }
                    if (hasMinMaxValue)
                    {
                        if (isNewParam || (d.MinValue != minValue) || (d.MaxValue != maxValue))
                        {
                            d.HasChanged = true;
                        }
                        if (!isNewParam)
                        {
                            d.UpdateMinAndMax(true, minValue, maxValue);
                        }
                    }
                    // Finally, make sure it's in the tables:
                    if (notInNameTable && nameTable != null && (name != null))
                    {
                        nameTable[name] = d;
                    }
                    if (notInIndexTable && indexTable != null)
                    {
                        indexTable[paramIndex] = d;
                    }
                    d.RequiresRefresh = false;
                    if (manager != null)
                    {
                        manager.NotifyChangeListeners(d);
                        manager.CheckVerifiedWrites(d);
                    }
                    ++numProcessed;
                }
            }
            return(numProcessed);
        }
示例#13
0
        // Process Port commands.
        // Returns zero on success.
        public override byte CommandHandler(MessageTransaction mtx)
        {
            PacketBuffer g       = mtx.MsgBuffer;
            Boolean      isReply = ((g.flagsRS() & ProtocolConstants.MESSAGE_FLAGS_IS_REPLY) != 0);

            if (((!isReply) && (g.command() < ProtocolConstants.MEDIATOR_CONTROL_CMD_BASE)) ||
                (isReply && (g.senderId() == ProtocolConstants.IDENT_MEDIATOR)))
            {
                byte   dataIndex = ProtocolConstants.GENERAL_DATA_ARRAY_OFFSET;
                byte[] tmp;
                switch (g.command())
                {
                // Standard device commands.
                case ProtocolConstants.MEDIATOR_DEVICE_RESET:     // Reset the module.
                    Manager.AppBabelDeviceReset();
                    break;

                case ProtocolConstants.MEDIATOR_DEVICE_STATUS:     // Get device status.
                    if (isReply)
                    {
                        return(1);
                    }
                    g.dataLength(Diagnostics.GetDeviceStatus(Manager, g.buffer));
                    mtx.ChangeDir = true;
                    mtx.Finish    = MessageTransaction.FinishAction.Normal;
                    break;

                case ProtocolConstants.MEDIATOR_DEVICE_TICKER:     // Get device ticker count.
                    if (isReply)
                    {
                        return(1);             // We've been sent a ticker count.
                    }
                    // Sender wants to know ticker count.
                    tmp = Primitives.UIntToByteArray(Primitives.GetBabelMilliTicker());
                    return(mtx.StoreMessageValue(tmp, (byte)(tmp.Length)));

                case ProtocolConstants.MEDIATOR_DEVICE_ERASE:     // TODO: erase eeprom and restart.
                    return(2);

                case ProtocolConstants.MEDIATOR_DEVICE_READVAR:
                    return((MediatorReadCommand(mtx) == 0) ? (byte)1 : (byte)0);

                case ProtocolConstants.MEDIATOR_DEVICE_WRITEVAR:
                    return((MediatorWriteCommand(mtx) == 0) ? (byte)1 : (byte)0);

                case ProtocolConstants.MEDIATOR_DEVICE_ISOVAR:
                    return((MediatorIsoCommand(mtx) == 0) ? (byte)1 : (byte)0);

                case ProtocolConstants.MEDIATOR_DEVICE_ISOMONVAR:
                    return((MediatorIsoCommand(mtx) == 0) ? (byte)1 : (byte)0);

                case ProtocolConstants.MEDIATOR_DEVICE_ISOMSG:
                    return((MediatorIsoCommand(mtx) == 0) ? (byte)1 : (byte)0);

                case ProtocolConstants.MEDIATOR_DEVICE_LOG:
                    if (!isReply)
                    {
                        if (Settings.LogOn)
                        {
                            uint   ticks = (uint)Primitives.GetArrayValueU(g.buffer, dataIndex, 4);
                            string s;
                            byte   logType = g.buffer[dataIndex + 4];
                            if (Settings.LogBinary || logType == 'B')
                            {
                                int start = dataIndex + 5;
                                int last  = dataIndex + g.dataLength();
                                s = "(";
                                for (int k = start; k < last; k++)
                                {
                                    s = s + g.buffer[k].ToString("X2") + " ";
                                }
                                s += ")";
                            }
                            else
                            {
                                s = Primitives.GetArrayStringValue(g.buffer, dataIndex + 5, g.dataLength() - 5);
                            }
                            Log.d("MediatorNetIf:" + Exchange.Id, ":" + ticks + ":" + s);
                        }
                    }
                    return(1);

                // Connection specific commands.
                case ProtocolConstants.MEDIATOR_DEVICE_GETSN: // Get SN of receiver device at end of link.
                    if (isReply)                              // We've been sent an SN for SPort.
                    {
                        g.buffer[dataIndex + g.dataLength()] = 0;
                        Manager.SerialNumberManager.UpdateSerialNumbers(g.buffer, dataIndex, g.dataLength(), g.iNetIf, g.sender());
                        if (mtx.MsgBuffer.iNetIf != ProtocolConstants.NETIF_USER_BASE)       // Notify master of SN via connection attach command.
                        {
                            SendLinkMediatorCommand(this, true, ProtocolConstants.MEDIATOR_CONNECT_ATTACH, g.dataLength(), g.buffer, dataIndex);
                        }
                        break;
                    }
                    // Sender wants to know SN of master.
                    g.dataLength(Manager.SerialNumberManager.CopyMasterSerialNumber(g.buffer, dataIndex, g.iNetIf));
                    mtx.ChangeDir = true;
                    mtx.Finish    = MessageTransaction.FinishAction.Normal;
                    break;

                case ProtocolConstants.MEDIATOR_CONNECT_ATTACH:     // TODO: Report attach and SN of device.
                case ProtocolConstants.MEDIATOR_CONNECT_DETACH:     // TODO: Report detach of device.
                case ProtocolConstants.MEDIATOR_CONNECT_GATEWAY:    // TODO: Register as a gateway.
                    return(10);

                default:
                    // TODO: try handling via NETIF_MEDIATOR_PORT.
                    return(11);
                }
                return(0);
            }
            return(BabelMessage.ProcessIncomingRawMesssage(Exchange, mtx));
        }