code: func GetPingOffset(beacon time.Duration, devAddr lorawan.DevAddr, pingNb int) (int, error) {
  	if pingNb == 0 {
  		return 0, errors.New("pingNb must be > 0")
  	}
  
  	if beacon%beaconPeriod != 0 {
  		return 0, fmt.Errorf("beacon must be a multiple of %s", beaconPeriod)
  	}
  
  	devAddrBytes, err := devAddr.MarshalBinary()
  	if err != nil {
  		return 0, errors.Wrap(err, "marshal devaddr error")
  	}
  
  	pingPeriod := pingPeriodBase / pingNb
  	beaconTime := uint32(int64(beacon/time.Second) % (1 << 32))
  
  	key := lorawan.AES128Key{} // 16 x 0x00
  	block, err := aes.NewCipher(key[:])
  	if err != nil {
  		return 0, errors.Wrap(err, "new cipher error")
  	}
  
  	if block.BlockSize() != 16 {
  		return 0, errors.New("block size of 16 was expected")
  	}
  
  	b := make([]byte, len(key))
  	rand := make([]byte, len(key))
  
  	binary.LittleEndian.PutUint32(b[0:4], beaconTime)
  	copy(b[4:8], devAddrBytes)
  	block.Encrypt(rand, b)
  
  	return (int(rand[0]) + int(rand[1])*256) % pingPeriod, nil
  }
docs: // GetPingOffset returns the ping offset for the given beacon.