/// <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); }
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); }
/// <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); } }
// 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); }
/** * 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); }
/** * 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); }
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); }
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; }
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); }
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); }
// 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); }
// 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); }
// 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)); }