Documentation ¶
Overview ¶
Package lorawan provides LoRaWAN decoding/encoding interfaces.
Index ¶
- Variables
- func ADRAckDelayExponentToUint32(v ttnpb.ADRAckDelayExponent) uint32
- func ADRAckLimitExponentToUint32(v ttnpb.ADRAckLimitExponent) uint32
- func AppendCFList(dst []byte, msg ttnpb.CFList) ([]byte, error)
- func AppendDLSettings(dst []byte, msg ttnpb.DLSettings) ([]byte, error)
- func AppendFCtrl(dst []byte, msg ttnpb.FCtrl, isUplink bool, fOptsLen uint8) ([]byte, error)
- func AppendFHDR(dst []byte, msg ttnpb.FHDR, isUplink bool) ([]byte, error)
- func AppendJoinAcceptPayload(dst []byte, msg ttnpb.JoinAcceptPayload) ([]byte, error)
- func AppendJoinRequestPayload(dst []byte, msg ttnpb.JoinRequestPayload) ([]byte, error)
- func AppendMACPayload(dst []byte, msg ttnpb.MACPayload, isUplink bool) ([]byte, error)
- func AppendMHDR(dst []byte, msg ttnpb.MHDR) ([]byte, error)
- func AppendMessage(dst []byte, msg ttnpb.Message) ([]byte, error)
- func AppendRejoinRequestPayload(dst []byte, msg ttnpb.RejoinRequestPayload) ([]byte, error)
- func DeviceEIRPToFloat32(v ttnpb.DeviceEIRP) float32
- func Float32ToDeviceEIRP(v float32) ttnpb.DeviceEIRP
- func GetUplinkMessageIdentifiers(phyPayload []byte) (ttnpb.EndDeviceIdentifiers, error)
- func MarshalCFList(msg ttnpb.CFList) ([]byte, error)
- func MarshalDLSettings(msg ttnpb.DLSettings) ([]byte, error)
- func MarshalJoinAcceptPayload(msg ttnpb.JoinAcceptPayload) ([]byte, error)
- func MarshalJoinRequestPayload(msg ttnpb.JoinRequestPayload) ([]byte, error)
- func MarshalMACPayload(msg ttnpb.MACPayload, isUplink bool) ([]byte, error)
- func MarshalMHDR(msg ttnpb.MHDR) ([]byte, error)
- func MarshalMessage(msg ttnpb.Message) ([]byte, error)
- func MarshalRejoinRequestPayload(msg ttnpb.RejoinRequestPayload) ([]byte, error)
- func Uint32ToADRAckDelayExponent(v uint32) ttnpb.ADRAckDelayExponent
- func Uint32ToADRAckLimitExponent(v uint32) ttnpb.ADRAckLimitExponent
- func UnmarshalCFList(b []byte, msg *ttnpb.CFList) error
- func UnmarshalDLSettings(b []byte, msg *ttnpb.DLSettings) error
- func UnmarshalFCtrl(b []byte, msg *ttnpb.FCtrl, isUplink bool) error
- func UnmarshalFHDR(b []byte, msg *ttnpb.FHDR, isUplink bool) error
- func UnmarshalJoinAcceptPayload(b []byte, msg *ttnpb.JoinAcceptPayload) error
- func UnmarshalJoinRequestPayload(b []byte, msg *ttnpb.JoinRequestPayload) error
- func UnmarshalMACPayload(b []byte, msg *ttnpb.MACPayload, isUplink bool) error
- func UnmarshalMHDR(b []byte, msg *ttnpb.MHDR) error
- func UnmarshalMessage(b []byte, msg *ttnpb.Message) error
- func UnmarshalRejoinRequestPayload(b []byte, msg *ttnpb.RejoinRequestPayload) error
- type MACCommandDescriptor
- type MACCommandSpec
- func (spec MACCommandSpec) AppendDownlink(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error)
- func (spec MACCommandSpec) AppendUplink(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error)
- func (spec MACCommandSpec) ReadDownlink(phy band.Band, r io.Reader, cmd *ttnpb.MACCommand) error
- func (spec MACCommandSpec) ReadUplink(phy band.Band, r io.Reader, cmd *ttnpb.MACCommand) error
Constants ¶
This section is empty.
Variables ¶
var DefaultMACCommands = MACCommandSpec{ ttnpb.CID_RESET: &MACCommandDescriptor{ InitiatedByDevice: true, UplinkLength: 1, AppendUplink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetResetInd() if pld.MinorVersion > 15 { return nil, errExpectedLowerOrEqual("MinorVersion", 15)(pld.MinorVersion) } b = append(b, byte(pld.MinorVersion)) return b, nil }, UnmarshalUplink: newMACUnmarshaler(ttnpb.CID_RESET, "ResetInd", 1, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_ResetInd_{ ResetInd: &ttnpb.MACCommand_ResetInd{ MinorVersion: ttnpb.Minor(b[0] & 0xf), }, } return nil }), DownlinkLength: 1, AppendDownlink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetResetConf() if pld.MinorVersion > 15 { return nil, errExpectedLowerOrEqual("MinorVersion", 15)(pld.MinorVersion) } b = append(b, byte(pld.MinorVersion)) return b, nil }, UnmarshalDownlink: newMACUnmarshaler(ttnpb.CID_RESET, "ResetConf", 1, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_ResetConf_{ ResetConf: &ttnpb.MACCommand_ResetConf{ MinorVersion: ttnpb.Minor(b[0] & 0xf), }, } return nil }), }, ttnpb.CID_LINK_CHECK: &MACCommandDescriptor{ InitiatedByDevice: true, AppendUplink: func(phy band.Band, b []byte, _ ttnpb.MACCommand) ([]byte, error) { return b, nil }, UnmarshalUplink: newMACUnmarshaler(ttnpb.CID_LINK_CHECK, "LinkCheckReq", 0, nil), DownlinkLength: 2, AppendDownlink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetLinkCheckAns() if pld.Margin > 254 { return nil, errExpectedLowerOrEqual("Margin", 254)(pld.Margin) } if pld.GatewayCount > 255 { return nil, errExpectedLowerOrEqual("GatewayCount", 255)(pld.GatewayCount) } b = append(b, byte(pld.Margin), byte(pld.GatewayCount)) return b, nil }, UnmarshalDownlink: newMACUnmarshaler(ttnpb.CID_LINK_CHECK, "LinkCheckAns", 2, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_LinkCheckAns_{ LinkCheckAns: &ttnpb.MACCommand_LinkCheckAns{ Margin: uint32(b[0]), GatewayCount: uint32(b[1]), }, } return nil }), }, ttnpb.CID_LINK_ADR: &MACCommandDescriptor{ InitiatedByDevice: false, UplinkLength: 1, AppendUplink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetLinkAdrAns() var status byte if pld.ChannelMaskAck { status |= 1 } if pld.DataRateIndexAck { status |= (1 << 1) } if pld.TxPowerIndexAck { status |= (1 << 2) } b = append(b, status) return b, nil }, UnmarshalUplink: newMACUnmarshaler(ttnpb.CID_LINK_ADR, "LinkADRAns", 1, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_LinkAdrAns{ LinkAdrAns: &ttnpb.MACCommand_LinkADRAns{ ChannelMaskAck: b[0]&1 == 1, DataRateIndexAck: (b[0]>>1)&1 == 1, TxPowerIndexAck: (b[0]>>2)&1 == 1, }, } return nil }), DownlinkLength: 4, AppendDownlink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetLinkAdrReq() if pld.DataRateIndex > 15 { return nil, errExpectedLowerOrEqual("DataRateIndex", 15)(pld.DataRateIndex) } if pld.TxPowerIndex > 15 { return nil, errExpectedLowerOrEqual("TxPowerIndex", 15)(pld.TxPowerIndex) } if len(pld.ChannelMask) > 16 { return nil, errExpectedLowerOrEqual("length of ChannelMask", "16 bits")(len(pld.ChannelMask)) } if pld.ChannelMaskControl > 7 { return nil, errExpectedLowerOrEqual("ChannelMaskControl", 7)(pld.ChannelMaskControl) } if pld.NbTrans > 15 { return nil, errExpectedLowerOrEqual("NbTrans", 15)(pld.NbTrans) } b = append(b, byte((pld.DataRateIndex&0xf)<<4)^byte(pld.TxPowerIndex&0xf)) chMask := make([]byte, 2) for i, v := range pld.ChannelMask { chMask[i/8] = chMask[i/8] ^ boolToByte(v)<<(i%8) } b = append(b, chMask...) b = append(b, byte((pld.ChannelMaskControl&0x7)<<4)^byte(pld.NbTrans&0xf)) return b, nil }, UnmarshalDownlink: newMACUnmarshaler(ttnpb.CID_LINK_ADR, "LinkADRReq", 4, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { var chMask [16]bool for i := 0; i < 16; i++ { chMask[i] = (b[1+i/8]>>(i%8))&1 == 1 } cmd.Payload = &ttnpb.MACCommand_LinkAdrReq{ LinkAdrReq: &ttnpb.MACCommand_LinkADRReq{ DataRateIndex: ttnpb.DataRateIndex(b[0] >> 4), TxPowerIndex: uint32(b[0] & 0xf), ChannelMask: chMask[:], ChannelMaskControl: uint32((b[3] >> 4) & 0x7), NbTrans: uint32(b[3] & 0xf), }, } return nil }), }, ttnpb.CID_DUTY_CYCLE: &MACCommandDescriptor{ InitiatedByDevice: false, AppendUplink: func(phy band.Band, b []byte, _ ttnpb.MACCommand) ([]byte, error) { return b, nil }, UnmarshalUplink: newMACUnmarshaler(ttnpb.CID_DUTY_CYCLE, "DutyCycleAns", 0, nil), DownlinkLength: 1, AppendDownlink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetDutyCycleReq() if pld.MaxDutyCycle > 15 { return nil, errExpectedLowerOrEqual("MaxDutyCycle", 15)(pld.MaxDutyCycle) } b = append(b, byte(pld.MaxDutyCycle)) return b, nil }, UnmarshalDownlink: newMACUnmarshaler(ttnpb.CID_DUTY_CYCLE, "DutyCycleReq", 1, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_DutyCycleReq_{ DutyCycleReq: &ttnpb.MACCommand_DutyCycleReq{ MaxDutyCycle: ttnpb.AggregatedDutyCycle(b[0] & 0xf), }, } return nil }), }, ttnpb.CID_RX_PARAM_SETUP: &MACCommandDescriptor{ InitiatedByDevice: false, UplinkLength: 1, AppendUplink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetRxParamSetupAns() var v byte if pld.Rx2FrequencyAck { v |= 1 } if pld.Rx2DataRateIndexAck { v |= (1 << 1) } if pld.Rx1DataRateOffsetAck { v |= (1 << 2) } b = append(b, v) return b, nil }, UnmarshalUplink: newMACUnmarshaler(ttnpb.CID_RX_PARAM_SETUP, "RxParamSetupAns", 1, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_RxParamSetupAns_{ RxParamSetupAns: &ttnpb.MACCommand_RxParamSetupAns{ Rx2FrequencyAck: b[0]&1 == 1, Rx2DataRateIndexAck: (b[0]>>1)&1 == 1, Rx1DataRateOffsetAck: (b[0]>>2)&1 == 1, }, } return nil }), DownlinkLength: 4, AppendDownlink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetRxParamSetupReq() if pld.Rx1DataRateOffset > 7 { return nil, errExpectedLowerOrEqual("Rx1DROffset", 7)(pld.Rx1DataRateOffset) } if pld.Rx2DataRateIndex > 15 { return nil, errExpectedLowerOrEqual("Rx2DR", 15)(pld.Rx2DataRateIndex) } b = append(b, byte(pld.Rx2DataRateIndex)|byte(pld.Rx1DataRateOffset<<4)) if pld.Rx2Frequency < 100000 || pld.Rx2Frequency > byteutil.MaxUint24*phy.FreqMultiplier { return nil, errExpectedBetween("Rx2Frequency", 100000, byteutil.MaxUint24*phy.FreqMultiplier)(pld.Rx2Frequency) } b = byteutil.AppendUint64(b, pld.Rx2Frequency/phy.FreqMultiplier, 3) return b, nil }, UnmarshalDownlink: newMACUnmarshaler(ttnpb.CID_RX_PARAM_SETUP, "RxParamSetupReq", 4, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_RxParamSetupReq_{ RxParamSetupReq: &ttnpb.MACCommand_RxParamSetupReq{ Rx1DataRateOffset: ttnpb.DataRateOffset(uint32((b[0] >> 4) & 0x7)), Rx2DataRateIndex: ttnpb.DataRateIndex(b[0] & 0xf), Rx2Frequency: byteutil.ParseUint64(b[1:4]) * phy.FreqMultiplier, }, } return nil }), }, ttnpb.CID_DEV_STATUS: &MACCommandDescriptor{ InitiatedByDevice: false, UplinkLength: 2, AppendUplink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetDevStatusAns() if pld.Battery > math.MaxUint8 { return nil, errExpectedLowerOrEqual("Battery", math.MaxUint8)(math.MaxUint8) } if pld.Margin < -32 || pld.Margin > 31 { return nil, errExpectedBetween("Margin", -32, 31)(pld.Margin) } b = append(b, byte(pld.Battery)) if pld.Margin < 0 { b = append(b, byte(-(pld.Margin+1)|(1<<5))) } else { b = append(b, byte(pld.Margin)) } return b, nil }, UnmarshalUplink: newMACUnmarshaler(ttnpb.CID_DEV_STATUS, "DevStatusAns", 2, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { margin := int32(b[1] & 0x1f) if (b[1]>>5)&1 == 1 { margin = -margin - 1 } cmd.Payload = &ttnpb.MACCommand_DevStatusAns_{ DevStatusAns: &ttnpb.MACCommand_DevStatusAns{ Battery: uint32(b[0]), Margin: margin, }, } return nil }), AppendDownlink: func(phy band.Band, b []byte, _ ttnpb.MACCommand) ([]byte, error) { return b, nil }, UnmarshalDownlink: newMACUnmarshaler(ttnpb.CID_DEV_STATUS, "DevStatusReq", 0, nil), }, ttnpb.CID_NEW_CHANNEL: &MACCommandDescriptor{ InitiatedByDevice: false, UplinkLength: 1, AppendUplink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetNewChannelAns() var v byte if pld.FrequencyAck { v |= 1 } if pld.DataRateAck { v |= (1 << 1) } b = append(b, v) return b, nil }, UnmarshalUplink: newMACUnmarshaler(ttnpb.CID_NEW_CHANNEL, "NewChannelAns", 1, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_NewChannelAns_{ NewChannelAns: &ttnpb.MACCommand_NewChannelAns{ FrequencyAck: b[0]&1 == 1, DataRateAck: (b[0]>>1)&1 == 1, }, } return nil }), DownlinkLength: 5, AppendDownlink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetNewChannelReq() if pld.ChannelIndex > math.MaxUint8 { return nil, errExpectedLowerOrEqual("ChannelIndex", math.MaxUint8)(pld.ChannelIndex) } b = append(b, byte(pld.ChannelIndex)) if pld.Frequency > byteutil.MaxUint24*phy.FreqMultiplier { return nil, errExpectedLowerOrEqual("Frequency", byteutil.MaxUint24*phy.FreqMultiplier)(pld.Frequency) } b = byteutil.AppendUint64(b, pld.Frequency/phy.FreqMultiplier, 3) if pld.MinDataRateIndex > 15 { return nil, errExpectedLowerOrEqual("MinDataRateIndex", 15)(pld.MinDataRateIndex) } v := byte(pld.MinDataRateIndex) if pld.MaxDataRateIndex > 15 { return nil, errExpectedLowerOrEqual("MaxDataRateIndex", 15)(pld.MaxDataRateIndex) } v |= byte(pld.MaxDataRateIndex) << 4 b = append(b, v) return b, nil }, UnmarshalDownlink: newMACUnmarshaler(ttnpb.CID_NEW_CHANNEL, "NewChannelReq", 5, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_NewChannelReq_{ NewChannelReq: &ttnpb.MACCommand_NewChannelReq{ ChannelIndex: uint32(b[0]), Frequency: byteutil.ParseUint64(b[1:4]) * phy.FreqMultiplier, MinDataRateIndex: ttnpb.DataRateIndex(b[4] & 0xf), MaxDataRateIndex: ttnpb.DataRateIndex(b[4] >> 4), }, } return nil }), }, ttnpb.CID_RX_TIMING_SETUP: &MACCommandDescriptor{ InitiatedByDevice: false, AppendUplink: func(phy band.Band, b []byte, _ ttnpb.MACCommand) ([]byte, error) { return b, nil }, UnmarshalUplink: newMACUnmarshaler(ttnpb.CID_RX_TIMING_SETUP, "RxTimingSetupAns", 0, nil), DownlinkLength: 1, AppendDownlink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetRxTimingSetupReq() if pld.Delay > 15 { return nil, errExpectedLowerOrEqual("Delay", 15)(pld.Delay) } b = append(b, byte(pld.Delay)) return b, nil }, UnmarshalDownlink: newMACUnmarshaler(ttnpb.CID_RX_TIMING_SETUP, "RxTimingSetupReq", 1, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_RxTimingSetupReq_{ RxTimingSetupReq: &ttnpb.MACCommand_RxTimingSetupReq{ Delay: ttnpb.RxDelay(b[0] & 0xf), }, } return nil }), }, ttnpb.CID_TX_PARAM_SETUP: &MACCommandDescriptor{ InitiatedByDevice: false, AppendUplink: func(phy band.Band, b []byte, _ ttnpb.MACCommand) ([]byte, error) { return b, nil }, UnmarshalUplink: newMACUnmarshaler(ttnpb.CID_TX_PARAM_SETUP, "TxParamSetupAns", 0, nil), DownlinkLength: 1, AppendDownlink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetTxParamSetupReq() v := byte(pld.MaxEirpIndex) if pld.UplinkDwellTime { v |= (1 << 4) } if pld.DownlinkDwellTime { v |= (1 << 5) } b = append(b, v) return b, nil }, UnmarshalDownlink: newMACUnmarshaler(ttnpb.CID_TX_PARAM_SETUP, "TxParamSetupReq", 1, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_TxParamSetupReq_{ TxParamSetupReq: &ttnpb.MACCommand_TxParamSetupReq{ MaxEirpIndex: ttnpb.DeviceEIRP(b[0] & 0xf), UplinkDwellTime: (b[0]>>4)&1 == 1, DownlinkDwellTime: (b[0]>>5)&1 == 1, }, } return nil }), }, ttnpb.CID_DL_CHANNEL: &MACCommandDescriptor{ InitiatedByDevice: false, UplinkLength: 1, AppendUplink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetDlChannelAns() var v byte if pld.ChannelIndexAck { v |= 1 } if pld.FrequencyAck { v |= (1 << 1) } b = append(b, v) return b, nil }, UnmarshalUplink: newMACUnmarshaler(ttnpb.CID_DL_CHANNEL, "DLChannelAns", 1, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_DlChannelAns{ DlChannelAns: &ttnpb.MACCommand_DLChannelAns{ ChannelIndexAck: b[0]&1 == 1, FrequencyAck: (b[0]>>1)&1 == 1, }, } return nil }), DownlinkLength: 4, AppendDownlink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetDlChannelReq() if pld.ChannelIndex > math.MaxUint8 { return nil, errExpectedLowerOrEqual("ChannelIndex", math.MaxUint8)(pld.ChannelIndex) } b = append(b, byte(pld.ChannelIndex)) if pld.Frequency < 100000 || pld.Frequency > byteutil.MaxUint24*phy.FreqMultiplier { return nil, errExpectedBetween("Frequency", 100000, byteutil.MaxUint24*phy.FreqMultiplier)(pld.Frequency) } b = byteutil.AppendUint64(b, pld.Frequency/phy.FreqMultiplier, 3) return b, nil }, UnmarshalDownlink: newMACUnmarshaler(ttnpb.CID_DL_CHANNEL, "DLChannelReq", 4, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_DlChannelReq{ DlChannelReq: &ttnpb.MACCommand_DLChannelReq{ ChannelIndex: uint32(b[0]), Frequency: byteutil.ParseUint64(b[1:4]) * phy.FreqMultiplier, }, } return nil }), }, ttnpb.CID_REKEY: &MACCommandDescriptor{ InitiatedByDevice: true, UplinkLength: 1, AppendUplink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetRekeyInd() if pld.MinorVersion > 15 { return nil, errExpectedLowerOrEqual("MinorVersion", 15)(pld.MinorVersion) } b = append(b, byte(pld.MinorVersion)) return b, nil }, UnmarshalUplink: newMACUnmarshaler(ttnpb.CID_REKEY, "RekeyInd", 1, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_RekeyInd_{ RekeyInd: &ttnpb.MACCommand_RekeyInd{ MinorVersion: ttnpb.Minor(b[0] & 0xf), }, } return nil }), DownlinkLength: 1, AppendDownlink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetRekeyConf() if pld.MinorVersion > 15 { return nil, errExpectedLowerOrEqual("MinorVersion", 15)(pld.MinorVersion) } b = append(b, byte(pld.MinorVersion)) return b, nil }, UnmarshalDownlink: newMACUnmarshaler(ttnpb.CID_REKEY, "RekeyConf", 1, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_RekeyConf_{ RekeyConf: &ttnpb.MACCommand_RekeyConf{ MinorVersion: ttnpb.Minor(b[0] & 0xf), }, } return nil }), }, ttnpb.CID_ADR_PARAM_SETUP: &MACCommandDescriptor{ InitiatedByDevice: false, AppendUplink: func(phy band.Band, b []byte, _ ttnpb.MACCommand) ([]byte, error) { return b, nil }, UnmarshalUplink: newMACUnmarshaler(ttnpb.CID_ADR_PARAM_SETUP, "ADRParamSetupAns", 0, nil), DownlinkLength: 1, AppendDownlink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetAdrParamSetupReq() if 1 > pld.AdrAckDelayExponent || pld.AdrAckDelayExponent > 32768 { return nil, errExpectedBetween("ADRAckDelay", 1, 32768)(pld.AdrAckDelayExponent) } v := byte(pld.AdrAckDelayExponent) if 1 > pld.AdrAckLimitExponent || pld.AdrAckLimitExponent > 32768 { return nil, errExpectedBetween("ADRAckLimit", 1, 32768)(pld.AdrAckLimitExponent) } v |= byte(pld.AdrAckLimitExponent) << 4 b = append(b, v) return b, nil }, UnmarshalDownlink: newMACUnmarshaler(ttnpb.CID_ADR_PARAM_SETUP, "ADRParamSetupReq", 1, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_AdrParamSetupReq{ AdrParamSetupReq: &ttnpb.MACCommand_ADRParamSetupReq{ AdrAckDelayExponent: ttnpb.ADRAckDelayExponent(b[0] & 0xf), AdrAckLimitExponent: ttnpb.ADRAckLimitExponent(b[0] >> 4), }, } return nil }), }, ttnpb.CID_DEVICE_TIME: &MACCommandDescriptor{ InitiatedByDevice: true, AppendUplink: func(phy band.Band, b []byte, _ ttnpb.MACCommand) ([]byte, error) { return b, nil }, UnmarshalUplink: newMACUnmarshaler(ttnpb.CID_DEVICE_TIME, "DeviceTimeReq", 0, nil), DownlinkLength: 5, AppendDownlink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetDeviceTimeAns() t := gpstime.ToGPS(pld.Time) sec := t / time.Second if sec > math.MaxUint32 { return nil, errExpectedLowerOrEqual("Time", uint32(math.MaxUint32))(sec) } b = byteutil.AppendUint32(b, uint32(sec), 4) b = append(b, byte((t-sec*time.Second)/fractStep)) return b, nil }, UnmarshalDownlink: newMACUnmarshaler(ttnpb.CID_DEVICE_TIME, "DeviceTimeAns", 5, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_DeviceTimeAns_{ DeviceTimeAns: &ttnpb.MACCommand_DeviceTimeAns{ Time: gpstime.Parse(time.Duration(byteutil.ParseUint32(b[0:4]))*time.Second + time.Duration(b[4])*fractStep), }, } return nil }), }, ttnpb.CID_FORCE_REJOIN: &MACCommandDescriptor{ InitiatedByDevice: false, DownlinkLength: 2, AppendDownlink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetForceRejoinReq() if pld.PeriodExponent > 7 { return nil, errExpectedLowerOrEqual("PeriodExponent", 7)(pld.PeriodExponent) } v := byte(pld.PeriodExponent) << 3 if pld.MaxRetries > 7 { return nil, errExpectedLowerOrEqual("MaxRetries", 7)(pld.MaxRetries) } v |= byte(pld.MaxRetries) b = append(b, v) if pld.RejoinType > 2 { return nil, errExpectedLowerOrEqual("RejoinType", 2)(pld.RejoinType) } v = byte(pld.RejoinType) << 4 if pld.DataRateIndex > 15 { return nil, errExpectedLowerOrEqual("DataRateIndex", 15)(pld.DataRateIndex) } v |= byte(pld.DataRateIndex) b = append(b, v) return b, nil }, UnmarshalDownlink: newMACUnmarshaler(ttnpb.CID_FORCE_REJOIN, "ForceRejoinReq", 2, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_ForceRejoinReq_{ ForceRejoinReq: &ttnpb.MACCommand_ForceRejoinReq{ PeriodExponent: ttnpb.RejoinPeriodExponent(uint32(b[0] >> 3)), MaxRetries: uint32(b[0] & 0x7), RejoinType: ttnpb.RejoinRequestType(b[1] >> 4), DataRateIndex: ttnpb.DataRateIndex(b[1] & 0xf), }, } return nil }), }, ttnpb.CID_REJOIN_PARAM_SETUP: &MACCommandDescriptor{ InitiatedByDevice: false, UplinkLength: 1, AppendUplink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetRejoinParamSetupAns() var v byte if pld.MaxTimeExponentAck { v |= 1 } b = append(b, v) return b, nil }, UnmarshalUplink: newMACUnmarshaler(ttnpb.CID_REJOIN_PARAM_SETUP, "RejoinParamSetupAns", 1, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_RejoinParamSetupAns_{ RejoinParamSetupAns: &ttnpb.MACCommand_RejoinParamSetupAns{ MaxTimeExponentAck: b[0]&1 == 1, }, } return nil }), DownlinkLength: 1, AppendDownlink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetRejoinParamSetupReq() if pld.MaxTimeExponent > 15 { return nil, errExpectedLowerOrEqual("MaxTimeExponent", 15)(pld.MaxTimeExponent) } v := byte(pld.MaxTimeExponent) << 4 if pld.MaxCountExponent > 15 { return nil, errExpectedLowerOrEqual("MaxCountExponent", 15)(pld.MaxCountExponent) } v |= byte(pld.MaxCountExponent) b = append(b, v) return b, nil }, UnmarshalDownlink: newMACUnmarshaler(ttnpb.CID_REJOIN_PARAM_SETUP, "RejoinParamSetupReq", 1, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_RejoinParamSetupReq_{ RejoinParamSetupReq: &ttnpb.MACCommand_RejoinParamSetupReq{ MaxTimeExponent: ttnpb.RejoinTimeExponent(uint32(b[0] >> 4)), MaxCountExponent: ttnpb.RejoinCountExponent(uint32(b[0] & 0xf)), }, } return nil }), }, ttnpb.CID_PING_SLOT_INFO: &MACCommandDescriptor{ InitiatedByDevice: true, UplinkLength: 1, AppendUplink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetPingSlotInfoReq() if pld.Period > 7 { return nil, errExpectedLowerOrEqual("Period", 15)(pld.Period) } b = append(b, byte(pld.Period)) return b, nil }, UnmarshalUplink: newMACUnmarshaler(ttnpb.CID_PING_SLOT_INFO, "PingSlotInfoReq", 1, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_PingSlotInfoReq_{ PingSlotInfoReq: &ttnpb.MACCommand_PingSlotInfoReq{ Period: ttnpb.PingSlotPeriod(b[0] & 0x7), }, } return nil }), AppendDownlink: func(phy band.Band, b []byte, _ ttnpb.MACCommand) ([]byte, error) { return b, nil }, UnmarshalDownlink: newMACUnmarshaler(ttnpb.CID_PING_SLOT_INFO, "PingSlotInfoAns", 0, nil), }, ttnpb.CID_PING_SLOT_CHANNEL: &MACCommandDescriptor{ InitiatedByDevice: false, UplinkLength: 1, AppendUplink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetPingSlotChannelAns() var v byte if pld.FrequencyAck { v |= 1 } if pld.DataRateIndexAck { v |= (1 << 1) } b = append(b, v) return b, nil }, UnmarshalUplink: newMACUnmarshaler(ttnpb.CID_PING_SLOT_CHANNEL, "PingSlotChannelAns", 1, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_PingSlotChannelAns_{ PingSlotChannelAns: &ttnpb.MACCommand_PingSlotChannelAns{ FrequencyAck: b[0]&1 == 1, DataRateIndexAck: (b[0]>>1)&1 == 1, }, } return nil }), DownlinkLength: 4, AppendDownlink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetPingSlotChannelReq() if pld.Frequency < 100000 || pld.Frequency > byteutil.MaxUint24*phy.FreqMultiplier { return nil, errExpectedBetween("Frequency", 100000, byteutil.MaxUint24*phy.FreqMultiplier)(pld.Frequency) } b = byteutil.AppendUint64(b, pld.Frequency/phy.FreqMultiplier, 3) if pld.DataRateIndex > 15 { return nil, errExpectedLowerOrEqual("DataRateIndex", 15)(pld.DataRateIndex) } b = append(b, byte(pld.DataRateIndex)) return b, nil }, UnmarshalDownlink: newMACUnmarshaler(ttnpb.CID_PING_SLOT_CHANNEL, "PingSlotChannelReq", 4, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_PingSlotChannelReq_{ PingSlotChannelReq: &ttnpb.MACCommand_PingSlotChannelReq{ Frequency: byteutil.ParseUint64(b[0:3]) * phy.FreqMultiplier, DataRateIndex: ttnpb.DataRateIndex(b[3] & 0xf), }, } return nil }), }, ttnpb.CID_BEACON_TIMING: &MACCommandDescriptor{ InitiatedByDevice: true, AppendUplink: func(phy band.Band, b []byte, _ ttnpb.MACCommand) ([]byte, error) { return b, nil }, UnmarshalUplink: newMACUnmarshaler(ttnpb.CID_BEACON_TIMING, "BeaconTimingReq", 0, nil), DownlinkLength: 3, AppendDownlink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetBeaconTimingAns() if pld.Delay > math.MaxUint16 { return nil, errExpectedLowerOrEqual("Delay", math.MaxUint16)(pld.Delay) } b = byteutil.AppendUint32(b, pld.Delay, 2) if pld.ChannelIndex > math.MaxUint8 { return nil, errExpectedLowerOrEqual("ChannelIndex", math.MaxUint8)(pld.ChannelIndex) } b = append(b, byte(pld.ChannelIndex)) return b, nil }, UnmarshalDownlink: newMACUnmarshaler(ttnpb.CID_BEACON_TIMING, "BeaconTimingAns", 3, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_BeaconTimingAns_{ BeaconTimingAns: &ttnpb.MACCommand_BeaconTimingAns{ Delay: byteutil.ParseUint32(b[0:2]), ChannelIndex: uint32(b[2]), }, } return nil }), }, ttnpb.CID_BEACON_FREQ: &MACCommandDescriptor{ InitiatedByDevice: false, UplinkLength: 1, AppendUplink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetBeaconFreqAns() var v byte if pld.FrequencyAck { v |= 1 } b = append(b, v) return b, nil }, UnmarshalUplink: newMACUnmarshaler(ttnpb.CID_BEACON_FREQ, "BeaconFreqAns", 1, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_BeaconFreqAns_{ BeaconFreqAns: &ttnpb.MACCommand_BeaconFreqAns{ FrequencyAck: b[0]&1 == 1, }, } return nil }), DownlinkLength: 3, AppendDownlink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetBeaconFreqReq() if pld.Frequency < 100000 || pld.Frequency > byteutil.MaxUint24*phy.FreqMultiplier { return nil, errExpectedBetween("Frequency", 100000, byteutil.MaxUint24*phy.FreqMultiplier)(pld.Frequency) } b = byteutil.AppendUint64(b, pld.Frequency/phy.FreqMultiplier, 3) return b, nil }, UnmarshalDownlink: newMACUnmarshaler(ttnpb.CID_BEACON_FREQ, "BeaconFreqReq", 3, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_BeaconFreqReq_{ BeaconFreqReq: &ttnpb.MACCommand_BeaconFreqReq{ Frequency: byteutil.ParseUint64(b[0:3]) * phy.FreqMultiplier, }, } return nil }), }, ttnpb.CID_DEVICE_MODE: &MACCommandDescriptor{ InitiatedByDevice: true, UplinkLength: 1, AppendUplink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetDeviceModeInd() b = append(b, byte(pld.Class)) return b, nil }, UnmarshalUplink: newMACUnmarshaler(ttnpb.CID_DEVICE_MODE, "DeviceModeInd", 1, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_DeviceModeInd_{ DeviceModeInd: &ttnpb.MACCommand_DeviceModeInd{ Class: ttnpb.Class(b[0]), }, } return nil }), DownlinkLength: 1, AppendDownlink: func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) { pld := cmd.GetDeviceModeConf() b = append(b, byte(pld.Class)) return b, nil }, UnmarshalDownlink: newMACUnmarshaler(ttnpb.CID_DEVICE_MODE, "DeviceModeConf", 1, func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error { cmd.Payload = &ttnpb.MACCommand_DeviceModeConf_{ DeviceModeConf: &ttnpb.MACCommand_DeviceModeConf{ Class: ttnpb.Class(b[0]), }, } return nil }), }, }
DefaultMACCommands contains all the default MAC commands.
Functions ¶
func ADRAckDelayExponentToUint32 ¶
func ADRAckDelayExponentToUint32(v ttnpb.ADRAckDelayExponent) uint32
ADRAckDelayExponentToUint32 returns v as a uint32 value.
func ADRAckLimitExponentToUint32 ¶
func ADRAckLimitExponentToUint32(v ttnpb.ADRAckLimitExponent) uint32
ADRAckLimitExponentToUint32 returns v as a uint32 value.
func AppendCFList ¶
AppendCFList appends encoded msg to dst.
func AppendDLSettings ¶
func AppendDLSettings(dst []byte, msg ttnpb.DLSettings) ([]byte, error)
AppendDLSettings appends encoded msg to dst.
func AppendFCtrl ¶
AppendFCtrl appends encoded msg to dst.
func AppendFHDR ¶
AppendFHDR appends encoded msg to dst.
func AppendJoinAcceptPayload ¶
func AppendJoinAcceptPayload(dst []byte, msg ttnpb.JoinAcceptPayload) ([]byte, error)
AppendJoinAcceptPayload appends encoded msg to dst.
func AppendJoinRequestPayload ¶
func AppendJoinRequestPayload(dst []byte, msg ttnpb.JoinRequestPayload) ([]byte, error)
AppendJoinRequestPayload appends encoded msg to dst.
func AppendMACPayload ¶
AppendMACPayload appends encoded msg to dst.
func AppendMHDR ¶
AppendMHDR appends encoded msg to dst.
func AppendMessage ¶
AppendMessage appends encoded msg to dst.
func AppendRejoinRequestPayload ¶
func AppendRejoinRequestPayload(dst []byte, msg ttnpb.RejoinRequestPayload) ([]byte, error)
AppendRejoinRequestPayload appends encoded msg to dst.
func DeviceEIRPToFloat32 ¶
func DeviceEIRPToFloat32(v ttnpb.DeviceEIRP) float32
DeviceEIRPToFloat32 returns v as a float32 value.
func Float32ToDeviceEIRP ¶
func Float32ToDeviceEIRP(v float32) ttnpb.DeviceEIRP
Float32ToDeviceEIRP returns v as a highest possible DeviceEIRP.
func GetUplinkMessageIdentifiers ¶
func GetUplinkMessageIdentifiers(phyPayload []byte) (ttnpb.EndDeviceIdentifiers, error)
GetUplinkMessageIdentifiers parses the PHYPayload and retrieves the EndDeviceIdentifers (except DeviceID).
func MarshalCFList ¶
MarshalCFList returns encoded msg.
func MarshalDLSettings ¶
func MarshalDLSettings(msg ttnpb.DLSettings) ([]byte, error)
MarshalDLSettings returns encoded msg.
func MarshalJoinAcceptPayload ¶
func MarshalJoinAcceptPayload(msg ttnpb.JoinAcceptPayload) ([]byte, error)
MarshalJoinAcceptPayload returns encoded msg.
func MarshalJoinRequestPayload ¶
func MarshalJoinRequestPayload(msg ttnpb.JoinRequestPayload) ([]byte, error)
MarshalJoinRequestPayload returns encoded msg.
func MarshalMACPayload ¶
func MarshalMACPayload(msg ttnpb.MACPayload, isUplink bool) ([]byte, error)
MarshalMACPayload returns encoded msg.
func MarshalMHDR ¶
MarshalMHDR returns encoded msg.
func MarshalMessage ¶
MarshalMessage returns encoded msg.
func MarshalRejoinRequestPayload ¶
func MarshalRejoinRequestPayload(msg ttnpb.RejoinRequestPayload) ([]byte, error)
MarshalRejoinRequestPayload returns encoded msg.
func Uint32ToADRAckDelayExponent ¶
func Uint32ToADRAckDelayExponent(v uint32) ttnpb.ADRAckDelayExponent
Uint32ToADRAckDelayExponent returns v as a highest possible ADRAckDelayExponent.
func Uint32ToADRAckLimitExponent ¶
func Uint32ToADRAckLimitExponent(v uint32) ttnpb.ADRAckLimitExponent
Uint32ToADRAckLimitExponent returns v as a highest possible ADRAckLimitExponent.
func UnmarshalCFList ¶
UnmarshalCFList unmarshals b into msg.
func UnmarshalDLSettings ¶
func UnmarshalDLSettings(b []byte, msg *ttnpb.DLSettings) error
UnmarshalDLSettings unmarshals b into msg.
func UnmarshalFCtrl ¶
UnmarshalFCtrl unmarshals b into msg.
func UnmarshalFHDR ¶
UnmarshalFHDR unmarshals b into msg.
func UnmarshalJoinAcceptPayload ¶
func UnmarshalJoinAcceptPayload(b []byte, msg *ttnpb.JoinAcceptPayload) error
UnmarshalJoinAcceptPayload unmarshals b into msg.
func UnmarshalJoinRequestPayload ¶
func UnmarshalJoinRequestPayload(b []byte, msg *ttnpb.JoinRequestPayload) error
UnmarshalJoinRequestPayload unmarshals b into msg.
func UnmarshalMACPayload ¶
func UnmarshalMACPayload(b []byte, msg *ttnpb.MACPayload, isUplink bool) error
UnmarshalMACPayload unmarshals b into msg.
func UnmarshalMHDR ¶
UnmarshalMHDR unmarshals b into msg.
func UnmarshalMessage ¶
UnmarshalMessage unmarshals b into msg.
func UnmarshalRejoinRequestPayload ¶
func UnmarshalRejoinRequestPayload(b []byte, msg *ttnpb.RejoinRequestPayload) error
UnmarshalRejoinRequestPayload unmarshals b into msg.
Types ¶
type MACCommandDescriptor ¶
type MACCommandDescriptor struct { InitiatedByDevice bool // UplinkLength is length of uplink payload. UplinkLength uint16 // DownlinkLength is length of downlink payload. DownlinkLength uint16 // AppendUplink appends uplink payload of cmd to b. AppendUplink func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) // UnmarshalUplink unmarshals uplink payload b into cmd. UnmarshalUplink func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error // AppendDownlink appends uplink payload of cmd to b. AppendDownlink func(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error) // UnmarshalDownlink unmarshals downlink payload b into cmd. UnmarshalDownlink func(phy band.Band, b []byte, cmd *ttnpb.MACCommand) error }
MACCommandDescriptor descibes a MAC command.
type MACCommandSpec ¶
type MACCommandSpec map[ttnpb.MACCommandIdentifier]*MACCommandDescriptor
MACCommandSpec maps the ttnpb.CID of MACCommand to a *MACCommandDescriptor.
func (MACCommandSpec) AppendDownlink ¶
func (spec MACCommandSpec) AppendDownlink(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error)
AppendDownlink encodes downlink MAC command cmd, appends it to b and returns any errors encountered.
func (MACCommandSpec) AppendUplink ¶
func (spec MACCommandSpec) AppendUplink(phy band.Band, b []byte, cmd ttnpb.MACCommand) ([]byte, error)
AppendUplink encodes uplink MAC command cmd, appends it to b and returns any errors encountered.
func (MACCommandSpec) ReadDownlink ¶
func (spec MACCommandSpec) ReadDownlink(phy band.Band, r io.Reader, cmd *ttnpb.MACCommand) error
ReadDownlink reads a downlink MACCommand from r into cmd and returns any errors encountered.
func (MACCommandSpec) ReadUplink ¶
func (spec MACCommandSpec) ReadUplink(phy band.Band, r io.Reader, cmd *ttnpb.MACCommand) error
ReadUplink reads an uplink MACCommand from r into cmd and returns any errors encountered.