-- Auto-generated protocol definition
-- DO NOT EDIT - This file is generated by Morel
local Protocol = {}
Protocol.name = "txse_moth_control"
Protocol.description = "txse_moth_control"
-- Enum definitions
Protocol.enums = {}
Protocol.enums.CancelOnDisconnectInstruction = {
  [0] = "DISABLED",
  [1] = "ENABLED_CANCEL_ALL",
}
Protocol.enums.ExchangeCode = {
  [1] = "TXSE",
  [2] = "XNAS",
  [3] = "XBOS",
  [4] = "XPSX",
  [5] = "EDGA",
  [6] = "EDGX",
  [7] = "BATY",
  [8] = "BATS",
  [9] = "MEMX",
  [10] = "EPRL",
  [11] = "LTSE",
  [12] = "IEXG",
  [13] = "XNYS",
  [14] = "ARCX",
  [15] = "XCIS",
  [16] = "XCHI",
  [17] = "XASE",
  [18] = "FINRA",
  [19] = "X24EQ",
  [20] = "SIP",
}
Protocol.enums.Instruction = {
  [1] = "GO_ACTIVE",
  [2] = "GO_PASSIVE",
  [3] = "SNAPSHOT_STATE",
}
Protocol.enums.MarketConstraintAction = {
  [0] = "NO_CHANGE",
  [1] = "SET",
  [2] = "CLEAR",
}
Protocol.enums.MarketDataSource = {
  [1] = "EXCHANGE",
  [2] = "SIP",
}
Protocol.enums.MarketHoursState = {
  [0] = "CLOSED_BEFORE_HOURS",
  [1] = "EARLY_SESSION",
  [2] = "REGULAR_SESSION",
  [3] = "AFTER_HOURS_SESSION",
  [4] = "CLOSED_AFTER_HOURS",
}
Protocol.enums.MassCancelScope = {
  [0] = "BY_MEMBER_OWNED_SENDER_COMPS",
  [1] = "BY_MEMBER_OWNED_MPIDS",
}
Protocol.enums.OperationalHaltReason = {
  [0] = "ADMINISTRATIVE",
}
Protocol.enums.OrderCapacity = {
  [1] = "AGENCY",
  [2] = "PRINCIPAL",
  [3] = "RISKLESS_PRINCIPAL",
}
Protocol.enums.PriceSlideInstruction = {
  [0] = "NO_PRICE_SLIDE",
  [1] = "SINGLE_PRICE_SLIDE_ON_LOCK_AND_CROSS",
  [2] = "MULTIPLE_PRICE_SLIDES_ON_LOCK_AND_CROSS",
  [3] = "SINGLE_PRICE_SLIDE_LOCK_ONLY",
}
Protocol.enums.RegulatoryHaltReason = {
  [0] = "REASON_NOT_AVAILABLE",
  [1] = "NEWS_PENDING",
  [2] = "NEWS_DISSEMINATION",
  [3] = "INFO_REQUESTED",
  [4] = "ORDER_IMBALANCE",
  [5] = "EXTRAORDINARY_MARKET_ACTIVITY",
  [6] = "LULD_PAUSE",
  [7] = "NON_COMPLIANCE",
  [8] = "FILINGS_NOT_CURRENT",
  [9] = "SEC_SUSPENSION",
  [10] = "REGULATORY_CONCERN",
  [11] = "SUB_PENNY_TRADING",
  [12] = "ETF",
  [13] = "IPO_NOT_TRADING",
  [14] = "CORPORATE_ACTION",
  [15] = "CIRCUIT_BREAKER_L1",
  [16] = "CIRCUIT_BREAKER_L2",
  [17] = "CIRCUIT_BREAKER_L3",
}
Protocol.enums.RejectReason = {
  [1] = "INVALID_CLIENT_ORDER_ID",
  [2] = "DUPLICATE_CLIENT_ORDER_ID",
  [3] = "UNKNOWN_ORIGINAL_CLIENT_ORDER_ID",
  [4] = "NO_LONGER_ON_BOOK",
  [5] = "INVALID_SYMBOL",
  [6] = "INVALID_PRICE",
  [7] = "INVALID_ORDER_QUANTITY",
  [8] = "INVALID_REFERENCE_PRICE_TARGET",
  [9] = "INVALID_IS_HIDDEN_FLAG",
  [10] = "INVALID_ORDER_TYPE",
  [11] = "INVALID_SIDE",
  [12] = "INVALID_MAX_FLOOR_QUANTITY",
  [13] = "INVALID_MAX_REPLENISH_QUANTITY_RANGE",
  [14] = "INVALID_MAX_REPLENISH_TIME_RANGE",
  [15] = "INVALID_MINIMUM_QUANTITY",
  [16] = "INVALID_LOCATE_REQUIRED_FLAG",
  [17] = "INVALID_TIME_IN_FORCE",
  [18] = "MODIFICATION_NOT_PERMITTED",
  [19] = "INVALID_MPID",
  [20] = "INVALID_SENDER_COMP",
  [21] = "INVALID_IS_POST_ONLY_FLAG",
  [22] = "INVALID_EXPIRE_TIME",
  [23] = "ORDER_INVALID_FOR_TRADING_SESSION",
  [24] = "ORDER_INVALID_FOR_TRADING_STATUS",
  [25] = "ORDER_INVALID_FOR_SYMBOL_STATUS",
  [26] = "INVALID_IS_ISO_FLAG",
  [27] = "TRADING_DISABLED_FOR_MPID_ON_PORT",
  [28] = "TRADING_DISABLED_FOR_NON_TEST_SYMBOLS",
  [29] = "TRADING_DISABLED_FOR_ORDER_CAPACITY",
  [30] = "TRADING_DISABLED_FOR_ISO",
  [31] = "MAXIMUM_ORDER_QUANTITY_BREACHED",
  [32] = "MAXIMUM_PRICE_BREACHED",
  [33] = "MAXIMUM_NOTIONAL_BREACHED",
  [34] = "INVALID_MASS_CANCEL_REQUEST_ID",
  [35] = "SYMBOL_ON_RESTRICTED_LIST",
}
Protocol.enums.SelfMatchInstruction = {
  [0] = "NO_SELF_MATCH_PREVENTION",
  [1] = "CANCEL_NEWEST",
  [2] = "CANCEL_OLDEST",
  [3] = "CANCEL_BOTH",
  [4] = "CANCEL_SMALLEST",
  [5] = "DECREMENT_AND_CANCEL",
}
Protocol.enums.SelfMatchScope = {
  [0] = "BY_MEMBER",
  [1] = "BY_MPID",
  [2] = "BY_MEMBER_GROUP",
  [3] = "BY_MPID_AND_MEMBER_GROUP",
}
Protocol.enums.SessionTradingState = {
  [0] = "CLOSED",
  [1] = "TRADING",
  [2] = "HALTED",
}
Protocol.enums.ShortSaleRestrictionState = {
  [0] = "NONE",
  [1] = "ACTIVATED",
  [2] = "CONTINUED",
}
Protocol.enums.SymbolListAction = {
  [1] = "ADD_TO_RESTRICTED_LIST",
  [2] = "REMOVE_FROM_RESTRICTED_LIST",
  [3] = "ADD_TO_HARD_TO_BORROW_LIST",
  [4] = "REMOVE_FROM_HARD_TO_BORROW_LIST",
}
-- Field definitions
-- Returns a function that creates Fields table given TXSE lib
Protocol.createFields = function(TXSE)
  local Fields = {}
  local Enums = Protocol.enums
  Fields["msgType"] = {
    length = 1,
    abbr = "txse_moth_control.msgType",
    name = "msgType",
    ftype = ftypes.CHAR,
    encoding = ENC_ASCII,
    value_map = {
      [80] = "MassCancelRejected",
      [81] = "MassCancelResult",
      [86] = "MassCancel",
      [97] = "AppRegister",
      [99] = "Symbol",
      [100] = "MPIDSettings",
      [104] = "Heartbeat",
      [106] = "AppInstruction",
      [108] = "PortMPIDSymbolSettings",
      [109] = "MarketConstraint",
      [110] = "TradingSessionSettings",
      [111] = "StartSession",
      [112] = "PortSettings",
      [114] = "PortMPIDSettings",
      [116] = "TradingSessionStatus",
      [119] = "MarketDataSourceUpdate",
    },
  }
  Fields["presenceOffset"] = {
    length = 1,
    abbr = "txse_moth_control.presenceOffset",
    name = "presenceOffset",
    ftype = ftypes.UINT8,
    encoding = ENC_NA,
  }
  Fields["afterHoursSessionEnd"] = {
    length = 8,
    abbr = "txse_moth_control.afterHoursSessionEnd",
    name = "afterHoursSessionEnd",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.TimeStamp",
  }
  Fields["afterHoursSessionStart"] = {
    length = 8,
    abbr = "txse_moth_control.afterHoursSessionStart",
    name = "afterHoursSessionStart",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.TimeStamp",
  }
  Fields["appId"] = {
    length = 2,
    abbr = "txse_moth_control.appId",
    name = "appId",
    ftype = ftypes.INT16,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.AppId",
  }
  Fields["appSeq"] = {
    length = 4,
    abbr = "txse_moth_control.appSeq",
    name = "appSeq",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.AppSeq",
  }
  Fields["cancelOnDisconnectInstruction"] = {
    length = 1,
    abbr = "txse_moth_control.cancelOnDisconnectInstruction",
    name = "cancelOnDisconnectInstruction",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.CancelOnDisconnectInstruction",
    value_map = Enums.CancelOnDisconnectInstruction,
  }
  Fields["canceledCount"] = {
    length = 4,
    abbr = "txse_moth_control.canceledCount",
    name = "canceledCount",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "kotlin.Int",
  }
  Fields["clOrdId"] = {
    length = 8,
    abbr = "txse_moth_control.clOrdId",
    name = "clOrdId",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.ClOrdId",
  }
  Fields["cqsSymbol"] = {
    length = 14,
    abbr = "txse_moth_control.cqsSymbol",
    name = "cqsSymbol",
    ftype = ftypes.STRING,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.CqsSymbol",
  }
  Fields["earlySessionStart"] = {
    length = 8,
    abbr = "txse_moth_control.earlySessionStart",
    name = "earlySessionStart",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.TimeStamp",
  }
  Fields["environment"] = {
    length = 4,
    abbr = "txse_moth_control.environment",
    name = "environment",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Environment",
  }
  Fields["exchangeCode"] = {
    length = 1,
    abbr = "txse_moth_control.exchangeCode",
    name = "exchangeCode",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.ExchangeCode",
    value_map = Enums.ExchangeCode,
  }
  Fields["id"] = {
    length = 2,
    abbr = "txse_moth_control.id",
    name = "id",
    ftype = ftypes.INT16,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.AppId",
  }
  Fields["instruction"] = {
    length = 1,
    abbr = "txse_moth_control.instruction",
    name = "instruction",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.Instruction",
    value_map = Enums.Instruction,
  }
  Fields["limitDown"] = {
    length = 8,
    abbr = "txse_moth_control.limitDown",
    name = "limitDown",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Price",
  }
  Fields["limitUp"] = {
    length = 8,
    abbr = "txse_moth_control.limitUp",
    name = "limitUp",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Price",
  }
  Fields["lotSize"] = {
    length = 4,
    abbr = "txse_moth_control.lotSize",
    name = "lotSize",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Quantity",
  }
  Fields["marketConstraintAction"] = {
    length = 1,
    abbr = "txse_moth_control.marketConstraintAction",
    name = "marketConstraintAction",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.MarketConstraintAction",
    value_map = Enums.MarketConstraintAction,
  }
  Fields["marketDataSource"] = {
    length = 1,
    abbr = "txse_moth_control.marketDataSource",
    name = "marketDataSource",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.MarketDataSource",
    value_map = Enums.MarketDataSource,
  }
  Fields["marketHoursState"] = {
    length = 1,
    abbr = "txse_moth_control.marketHoursState",
    name = "marketHoursState",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.MarketHoursState",
    value_map = Enums.MarketHoursState,
  }
  Fields["massCancelId"] = {
    length = 8,
    abbr = "txse_moth_control.massCancelId",
    name = "massCancelId",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.MassCancelId",
  }
  Fields["massCancelRequestId"] = {
    length = 8,
    abbr = "txse_moth_control.massCancelRequestId",
    name = "massCancelRequestId",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.MassCancelId",
  }
  Fields["massCancelScope"] = {
    length = 1,
    abbr = "txse_moth_control.massCancelScope",
    name = "massCancelScope",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.MassCancelScope",
    value_map = Enums.MassCancelScope,
  }
  Fields["maxNotional"] = {
    length = 8,
    abbr = "txse_moth_control.maxNotional",
    name = "maxNotional",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Notional",
  }
  Fields["maxShares"] = {
    length = 4,
    abbr = "txse_moth_control.maxShares",
    name = "maxShares",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Quantity",
  }
  Fields["memberGroup"] = {
    length = 2,
    abbr = "txse_moth_control.memberGroup",
    name = "memberGroup",
    ftype = ftypes.INT16,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.MemberGroup",
  }
  Fields["mpid"] = {
    length = 4,
    abbr = "txse_moth_control.mpid",
    name = "mpid",
    ftype = ftypes.INT32,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.MPID",
  }
  Fields["name"] = {
    length = 8,
    abbr = "txse_moth_control.name",
    name = "name",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.AppName",
  }
  Fields["nasdaqSymbol"] = {
    length = 8,
    abbr = "txse_moth_control.nasdaqSymbol",
    name = "nasdaqSymbol",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.NasdaqSymbol",
  }
  Fields["operationalHaltReason"] = {
    length = 1,
    abbr = "txse_moth_control.operationalHaltReason",
    name = "operationalHaltReason",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.OperationalHaltReason",
    value_map = Enums.OperationalHaltReason,
  }
  Fields["orderCapacity"] = {
    length = 1,
    abbr = "txse_moth_control.orderCapacity",
    name = "orderCapacity",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.OrderCapacity",
    value_map = Enums.OrderCapacity,
  }
  Fields["originatingAppId"] = {
    length = 2,
    abbr = "txse_moth_control.originatingAppId",
    name = "originatingAppId",
    ftype = ftypes.INT16,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.AppId",
  }
  Fields["owningMember"] = {
    length = 3,
    abbr = "txse_moth_control.owningMember",
    name = "owningMember",
    ftype = ftypes.STRING,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.Member",
  }
  Fields["portAppId"] = {
    length = 2,
    abbr = "txse_moth_control.portAppId",
    name = "portAppId",
    ftype = ftypes.INT16,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.AppId",
  }
  Fields["com.txse.exchange.specs.moth.define.PortMPIDSettingsBitFields"] = {
    length = 2,
    abbr = "txse_moth_control.portMPIDSettingsBitFields",
    name = "portMPIDSettingsBitFields",
    ftype = ftypes.INT16,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.specs.moth.define.PortMPIDSettingsBitFields",
    custom_decode = function(buffer, pinfo, tree)
      local numeric = buffer(0, 2):le_uint()
      tree:add(buffer, string.format("isDefault: %d", TXSE.extract_bits(numeric, 0)))
      tree:add(buffer, string.format("isTradingDisabled: %d", TXSE.extract_bits(numeric, 1)))
      tree:add(buffer, string.format("isTestSymbolsOnly: %d", TXSE.extract_bits(numeric, 2)))
      tree:add(buffer, string.format("shouldRejectISO: %d", TXSE.extract_bits(numeric, 3)))
      tree:add(buffer, string.format("forceSelfMatchScope: %d", TXSE.extract_bits(numeric, 4)))
      tree:add(buffer, string.format("forceSelfMatchInstruction: %d", TXSE.extract_bits(numeric, 5)))
      tree:add(buffer, string.format("forceMemberGroup: %d", TXSE.extract_bits(numeric, 6)))
      tree:add(buffer, string.format("restrictOrderCapacityAgency: %d", TXSE.extract_bits(numeric, 7)))
      tree:add(buffer, string.format("restrictOrderCapacityPrincipal: %d", TXSE.extract_bits(numeric, 8)))
      tree:add(buffer, string.format("restrictOrderCapacityRisklessPrincipal: %d", TXSE.extract_bits(numeric, 9)))
      tree:add(buffer, string.format("reserved: %d", TXSE.extract_bits(numeric, 10, 6)))
    end,
  }
  Fields["com.txse.exchange.specs.moth.define.PortSettingsBitFields"] = {
    length = 1,
    abbr = "txse_moth_control.portSettingsBitFields",
    name = "portSettingsBitFields",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.specs.moth.define.PortSettingsBitFields",
    custom_decode = function(buffer, pinfo, tree)
      local numeric = buffer(0, 1):le_uint()
      tree:add(buffer, string.format("isSponsoredAccess: %d", TXSE.extract_bits(numeric, 0)))
      tree:add(buffer, string.format("reserved: %d", TXSE.extract_bits(numeric, 1, 7)))
    end,
  }
  Fields["priceSlideInstruction"] = {
    length = 1,
    abbr = "txse_moth_control.priceSlideInstruction",
    name = "priceSlideInstruction",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.PriceSlideInstruction",
    value_map = Enums.PriceSlideInstruction,
  }
  Fields["regularSessionStart"] = {
    length = 8,
    abbr = "txse_moth_control.regularSessionStart",
    name = "regularSessionStart",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.TimeStamp",
  }
  Fields["regulatoryHaltReason"] = {
    length = 1,
    abbr = "txse_moth_control.regulatoryHaltReason",
    name = "regulatoryHaltReason",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.RegulatoryHaltReason",
    value_map = Enums.RegulatoryHaltReason,
  }
  Fields["rejectReason"] = {
    length = 1,
    abbr = "txse_moth_control.rejectReason",
    name = "rejectReason",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.RejectReason",
    value_map = Enums.RejectReason,
  }
  Fields["root"] = {
    length = 8,
    abbr = "txse_moth_control.root",
    name = "root",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.SymbolRoot",
  }
  Fields["selfMatchInstruction"] = {
    length = 1,
    abbr = "txse_moth_control.selfMatchInstruction",
    name = "selfMatchInstruction",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.SelfMatchInstruction",
    value_map = Enums.SelfMatchInstruction,
  }
  Fields["selfMatchScope"] = {
    length = 1,
    abbr = "txse_moth_control.selfMatchScope",
    name = "selfMatchScope",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.SelfMatchScope",
    value_map = Enums.SelfMatchScope,
  }
  Fields["senderComp"] = {
    length = 8,
    abbr = "txse_moth_control.senderComp",
    name = "senderComp",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.foundation.protocols.rake.morel.define.SenderComp",
  }
  Fields["seqTimestamp"] = {
    length = 8,
    abbr = "txse_moth_control.seqTimestamp",
    name = "seqTimestamp",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.TimeStamp",
  }
  Fields["session"] = {
    length = 8,
    abbr = "txse_moth_control.session",
    name = "session",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Session",
  }
  Fields["sessionTradingState"] = {
    length = 1,
    abbr = "txse_moth_control.sessionTradingState",
    name = "sessionTradingState",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.SessionTradingState",
    value_map = Enums.SessionTradingState,
  }
  Fields["shortSaleRestrictionState"] = {
    length = 1,
    abbr = "txse_moth_control.shortSaleRestrictionState",
    name = "shortSaleRestrictionState",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.ShortSaleRestrictionState",
    value_map = Enums.ShortSaleRestrictionState,
  }
  Fields["suffix"] = {
    length = 8,
    abbr = "txse_moth_control.suffix",
    name = "suffix",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.SymbolSuffix",
  }
  Fields["com.txse.exchange.specs.moth.define.SymbolBitFields"] = {
    length = 1,
    abbr = "txse_moth_control.symbolBitFields",
    name = "symbolBitFields",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.specs.moth.define.SymbolBitFields",
    custom_decode = function(buffer, pinfo, tree)
      local numeric = buffer(0, 1):le_uint()
      tree:add(buffer, string.format("isTest: %d", TXSE.extract_bits(numeric, 0)))
      tree:add(buffer, string.format("isHardToBorrow: %d", TXSE.extract_bits(numeric, 1)))
      tree:add(buffer, string.format("reserved: %d", TXSE.extract_bits(numeric, 2, 6)))
    end,
  }
  Fields["symbolId"] = {
    length = 2,
    abbr = "txse_moth_control.symbolId",
    name = "symbolId",
    ftype = ftypes.INT16,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.SymbolId",
  }
  Fields["symbolListAction"] = {
    length = 1,
    abbr = "txse_moth_control.symbolListAction",
    name = "symbolListAction",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.exchange.SymbolListAction",
    value_map = Enums.SymbolListAction,
  }
  Fields["symbolsOffset"] = {
    length = 1,
    abbr = "txse_moth_control.symbolsOffset",
    name = "symbolsOffset",
    ftype = ftypes.UINT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.morel.generate.MorelOffset",
  }
  Fields["targetAppId"] = {
    length = 2,
    abbr = "txse_moth_control.targetAppId",
    name = "targetAppId",
    ftype = ftypes.INT16,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.exchange.AppId",
  }
  Fields["tickSize"] = {
    length = 8,
    abbr = "txse_moth_control.tickSize",
    name = "tickSize",
    ftype = ftypes.INT64,
    encoding = ENC_LITTLE_ENDIAN,
    kotlin_type = "com.txse.avail.Price",
  }
  Fields["tradingStreamId"] = {
    length = 1,
    abbr = "txse_moth_control.tradingStreamId",
    name = "tradingStreamId",
    ftype = ftypes.INT8,
    encoding = ENC_NA,
    kotlin_type = "com.txse.avail.StreamId",
  }
  Fields["marketConstraintPresence"] = {
    length = 1,
    abbr = "txse_moth_control.marketConstraintPresence",
    name = "marketConstraintPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["massCancelPresence"] = {
    length = 1,
    abbr = "txse_moth_control.massCancelPresence",
    name = "massCancelPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["massCancelRejectedPresence"] = {
    length = 1,
    abbr = "txse_moth_control.massCancelRejectedPresence",
    name = "massCancelRejectedPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["portMPIDSettingsPresence"] = {
    length = 1,
    abbr = "txse_moth_control.portMPIDSettingsPresence",
    name = "portMPIDSettingsPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  Fields["tradingSessionStatusPresence"] = {
    length = 1,
    abbr = "txse_moth_control.tradingSessionStatusPresence",
    name = "tradingSessionStatusPresence",
    ftype = ftypes.BYTES,
    encoding = ENC_NA,
    is_presence_field = true,
  }
  return Fields
end
-- Message definitions
Protocol.messages = {
  {
    name = "AppInstruction",
    type = "j",
    fields = {
      "msgType",
      "seqTimestamp",
      "appId",
      "appSeq",
      "targetAppId",
      "instruction",
    },
  },
  {
    name = "AppRegister",
    type = "a",
    fields = {
      "msgType",
      "seqTimestamp",
      "id",
      "name",
    },
  },
  {
    name = "Heartbeat",
    type = "h",
    fields = {
      "msgType",
      "seqTimestamp",
      "appId",
      "appSeq",
    },
  },
  {
    name = "MPIDSettings",
    type = "d",
    fields = {
      "msgType",
      "seqTimestamp",
      "appId",
      "appSeq",
      "mpid",
      "owningMember",
    },
  },
  {
    name = "MarketConstraint",
    type = "m",
    fields = {
      "msgType",
      "presenceOffset",
      "seqTimestamp",
      "appId",
      "appSeq",
      "marketConstraintAction",
      "marketConstraintAction",
      "marketConstraintAction",
      "marketConstraintPresence",
    },
    presence_fields = {
      "symbolId",
      "operationalHaltReason",
      "regulatoryHaltReason",
      "shortSaleRestrictionState",
    },
  },
  {
    name = "MarketDataSourceUpdate",
    type = "w",
    fields = {
      "msgType",
      "seqTimestamp",
      "appId",
      "appSeq",
      "marketDataSource",
    },
  },
  {
    name = "MassCancel",
    type = "V",
    fields = {
      "msgType",
      "presenceOffset",
      "seqTimestamp",
      "appId",
      "appSeq",
      "originatingAppId",
      "massCancelRequestId",
      "massCancelScope",
      "massCancelId",
      "massCancelPresence",
    },
    presence_fields = {
      "mpid",
      "senderComp",
      "memberGroup",
      "clOrdId",
    },
  },
  {
    name = "MassCancelRejected",
    type = "P",
    fields = {
      "msgType",
      "presenceOffset",
      "seqTimestamp",
      "appId",
      "appSeq",
      "massCancelRequestId",
      "massCancelScope",
      "rejectReason",
      "massCancelRejectedPresence",
    },
    presence_fields = {
      "mpid",
      "senderComp",
      "memberGroup",
      "clOrdId",
    },
  },
  {
    name = "MassCancelResult",
    type = "Q",
    fields = {
      "msgType",
      "seqTimestamp",
      "appId",
      "appSeq",
      "originatingAppId",
      "massCancelRequestId",
      "massCancelId",
      "canceledCount",
    },
  },
  {
    name = "PortMPIDSettings",
    type = "r",
    fields = {
      "msgType",
      "presenceOffset",
      "seqTimestamp",
      "appId",
      "appSeq",
      "portAppId",
      "mpid",
      "memberGroup",
      "com.txse.exchange.specs.moth.define.PortMPIDSettingsBitFields",
      "maxNotional",
      "maxShares",
      "priceSlideInstruction",
      "selfMatchScope",
      "selfMatchInstruction",
      "portMPIDSettingsPresence",
    },
    presence_fields = {
      "orderCapacity",
    },
  },
  {
    name = "PortMPIDSymbolSettings",
    type = "l",
    fields = {
      "msgType",
      "seqTimestamp",
      "appId",
      "appSeq",
      "portAppId",
      "mpid",
      "symbolListAction",
      "symbolsOffset",
    },
    list_fields = {
      {
        name = "symbols",
        offset_field = "symbolsOffset",
        item_type = "SymbolId",
        item_length = 0,
        item_fields = {
        },
      },
    },
  },
  {
    name = "PortSettings",
    type = "p",
    fields = {
      "msgType",
      "seqTimestamp",
      "appId",
      "appSeq",
      "portAppId",
      "com.txse.exchange.specs.moth.define.PortSettingsBitFields",
      "owningMember",
      "cancelOnDisconnectInstruction",
    },
  },
  {
    name = "StartSession",
    type = "o",
    fields = {
      "msgType",
      "seqTimestamp",
      "environment",
      "session",
    },
  },
  {
    name = "Symbol",
    type = "c",
    fields = {
      "msgType",
      "seqTimestamp",
      "appId",
      "appSeq",
      "id",
      "root",
      "suffix",
      "com.txse.exchange.specs.moth.define.SymbolBitFields",
      "tradingStreamId",
      "exchangeCode",
      "tickSize",
      "lotSize",
      "limitUp",
      "limitDown",
      "cqsSymbol",
      "nasdaqSymbol",
    },
  },
  {
    name = "TradingSessionSettings",
    type = "n",
    fields = {
      "msgType",
      "seqTimestamp",
      "appId",
      "appSeq",
      "earlySessionStart",
      "regularSessionStart",
      "afterHoursSessionStart",
      "afterHoursSessionEnd",
    },
  },
  {
    name = "TradingSessionStatus",
    type = "t",
    fields = {
      "msgType",
      "presenceOffset",
      "seqTimestamp",
      "appId",
      "appSeq",
      "marketHoursState",
      "sessionTradingState",
      "tradingSessionStatusPresence",
    },
    presence_fields = {
      "operationalHaltReason",
      "regulatoryHaltReason",
    },
  },
}
-- Dissector setup
-- opts.payload_decoder: optional function(buffer, pinfo, tree_item) for trailing payload
Protocol.register = function(opts)
  local TXSE = require("txse-lib")
  local proto, messages = TXSE.Proto.new(TXSE.createSpec(Protocol, opts))
  function proto.dissector(buffer, pinfo, tree)
    local length = buffer:len()
    if length < 1 then
      return 0
    end
    local msg_type = buffer(0, 1):uint()
    local msg = messages.mapping[msg_type]
    if not msg then
      return 0
    end
    pinfo.cols.protocol = proto.name
    pinfo.cols.info = msg.name
    local subtree = tree:add(proto, buffer, msg.name)
    msg:parse(buffer, pinfo, subtree)
    return buffer:len()
  end
  return proto
end
return Protocol
