Simulate message from the Gateway => Gateway Bridge


Hi! I refactored the simulator to change its GUI and took the time to extend it a bit to support OTAA. Besides a couple of issues with frame counters that I’ll take care of before merging, it works fine for 1.0 but I’m having some troubles with 1.1. In both cases a join looks like this:

//Join sends a join request for a given device (OTAA) and rxInfo.
func (d *Device) Join(client MQTT.Client, gwMac string, rxInfo RxInfo) error {

	devNonceKey := fmt.Sprintf("dev-nonce-%s", d.DevEUI[:])
	var devNonce uint16
	sdn, err := redisClient.Get(devNonceKey).Result()
	if err == nil {
		dn, err := strconv.Atoi(sdn)
		if err == nil {
			devNonce = uint16(dn + 1)
	redisClient.Set(devNonceKey, devNonce, 0)

	d.DevNonce = lorawan.DevNonce(devNonce)

	joinPhy := lorawan.PHYPayload{
		MHDR: lorawan.MHDR{
			MType: lorawan.JoinRequest,
			Major: lorawan.LoRaWANR1,
		MACPayload: &lorawan.JoinRequestPayload{
			JoinEUI:  d.AppEUI,
			DevEUI:   d.DevEUI,
			DevNonce: d.DevNonce,

	if err := joinPhy.SetUplinkJoinMIC(d.NwkKey); err != nil {
		return err

	joinStr, err := joinPhy.MarshalText()
	if err != nil {
		return err

	message := &Message{
		PhyPayload: string(joinStr),
		RxInfo:     &rxInfo,

	pErr := publish(client, "gateway/"+rxInfo.Mac+"/rx", message)

	return pErr


Now, the next function processes the join response and, as mentioned, it works fine when setting to say 1.0.2 the device’s mac version at loraserver:

func (d *Device) processJoinResponse(phy lorawan.PHYPayload, payload []byte, mv lorawan.MACVersion) (string, error) {
	log.Infoln("processing join response")

	err := phy.DecryptJoinAcceptPayload(d.NwkKey)
	if err != nil {
		log.Errorf("can't decrypt join accept: %s", err)

	log.Infof("unmarshaled: %s", payload)
	ok, err := phy.ValidateDownlinkJoinMIC(lorawan.JoinRequestType, d.DevEUI, d.DevNonce, d.NwkKey)
	if err != nil {
		log.Error("failed at join mic function")
		return "", err
	if !ok {
		return "", errors.New("join invalid mic")

	if err := phy.DecryptFOpts(d.NwkKey); err != nil {
		log.Error("failed at opts decryption")
		return "", err

	phyJSON, err := phy.MarshalJSON()
	if err != nil {
		log.Error("failed at json marshal")
		return "", err

	jap := phy.MACPayload.(*lorawan.JoinAcceptPayload)

	log.Infof("join accept payload: %+v", jap)

	//Check that JoinNonce is greater than the one already stored.
	joinNonceKey := fmt.Sprintf("join-nonce-%s", d.DevEUI[:])
	var joinNonce lorawan.JoinNonce
	sjn, err := redisClient.Get("join-nonce").Result()
	if err == nil {
		jn, err := strconv.Atoi(sjn)
		if err == nil {
			joinNonce = lorawan.JoinNonce(jn + 1)

	if jap.JoinNonce <= joinNonce {
		return "", errors.New("got lower or equal JoinNonce from server")

	redisClient.Set(joinNonceKey, joinNonce, 0)

	d.FNwkSIntKey, err = getFNwkSIntKey(jap.DLSettings.OptNeg, d.NwkKey, jap.HomeNetID, d.DevEUI, jap.JoinNonce, d.DevNonce)
	if d.MACVersion == 0 {
		d.NwkSEncKey = d.FNwkSIntKey
		d.SNwkSIntKey = d.FNwkSIntKey
	} else {
		d.NwkSEncKey, err = getNwkSEncKey(jap.DLSettings.OptNeg, d.NwkKey, jap.HomeNetID, d.DevEUI, jap.JoinNonce, d.DevNonce)
		d.SNwkSIntKey, err = getSNwkSIntKey(jap.DLSettings.OptNeg, d.NwkKey, jap.HomeNetID, d.DevEUI, jap.JoinNonce, d.DevNonce)
	if jap.DLSettings.OptNeg {
		d.AppSKey, err = getAppSKey(jap.DLSettings.OptNeg, d.AppKey, jap.HomeNetID, d.DevEUI, jap.JoinNonce, d.DevNonce)
	} else {
		d.AppSKey, err = getAppSKey(jap.DLSettings.OptNeg, d.NwkKey, jap.HomeNetID, d.DevEUI, jap.JoinNonce, d.DevNonce)
	d.DevAddr = jap.DevAddr

	return string(phyJSON), nil

For 1.1., this fails at ValidateDownlinkJoinMIC, which returns false, nil, indicating the MIC is incorrect. Accordingly, if I just remove the validation, devAddr is correct but all keys are wrong and uplinks don’t work, which of course is expected.

Anyway, if anyone knows what I’m doing wrong when processing the join accept (or maybe it’s 1.1’s join that should be different), it’d be of great help.


Hi, just wanted to let know anyone interested that I made a first release including GUI changes and new features (1.0 and 1.1. ABP and OTAA, JS encoder function, etc.):

Any feedback is very welcome, and please file an issue for any bug you may find.


EDIT: Changed the link as the original released was missing a file.

Test our network architecture

thank you very much for this release.but i want to know how we can use it?!
please get a complete guidance,because i need it so much and i need to send a ABP to test our network.thank you again beforehand.


Hi. First, that release was missing a file, so use this one instead:

There’s no guide on how to use it because the GUI is pretty straight forward. There’s a first window where you can set the mqtt broker’s server and credentials, as well as the simulated gateway’s MAC.

The next window allows to set all relevant device info, such as eui and address, keys, lorawan version, type of uplink, activation profile (abp or otaa) and if you need to disable frame counter validation. How you should set the keys depends on the lorawan version and the activation.

The third window allows to input regional LoRa parameters as well as signal ones, so here you’d select your band, bandwidth and spread factor, as well as snr, rssi, etc.

Windows from the right deal with data. The top one allows to set fCtrl parameters and send mac commands along with an uplink. The middle one allows to define the data that’ll be sent, which may be given as a hex encoded payload, as a JS encoding function and an object to be encoded as bytes, or using our encoding scheme that’s explained at the readme. You can also set the fPort to be used and you may chose to send periodic messages by checking the “send every x seconds” option and selecting the amount with the slider.

Finally, the bottom right window is used to log output. You can select the log level in the main menu, as well as clear the console, copy its content or dump its history since the last time the program was executed.

As the readme mentions, you may feed a conf file to have all parameters filled on initialization, which is what I’d recommend. Also, Redis is a requirements as it’s used to keep device information such as frame counters, nonces and keys (when using OTAA). And that’s about it, just give it a try and if you can’t figure out something, send me a message, ask kere or in the repo’s issues.



thank you so much.
i will do what you said and report you if i have problem or any error.
so thankful for your answer.


i apologize for this.but i’m new in go and i don’t know how to run your release.
can you help me to do that.which file that i must to run??
main file in cli directory?
please help.


The release has no binaries, you need to compile the program yourself. Check the Readme for instructions on requirements and building the executable on Debian based systems. It should work on others (at least Arch has been tested and if you get Redis working in Windows it should work fine too), but I can’t provide instructions for requirements on those.


thank for giving me your time. yes i have a linux 18.04 system and go compiler .
i know that i have to compile a go file.and i read readme file but i do’nt understand wich file must be compiled.and another question is :in main.go in cli directory we have some import from girhub and there aren’t in your zip.should i import them??
so thankful again :pray::pray:


The cli directory contains an outdated and no longer working cli version of the program. You shouldn’t run anything inside that directory. I’ve kept it because I mean to update it eventually, but it’s useless right now.

As the readme says, just run make from the top directory (i.e., download, uncompress, cd into the uncompressed directory and run make), which is just shorthand for go build -o gui (I prefer to have the Makefile in case I need to add something to the build process). Then you can run the program with ./gui --conf your-conf-file.toml.

As for imports, they’ll be handled by Go modules when building. That’s why the readme asks for Go version 1.12 (1.11 works too) and Go modules enabled (i.e. by setting GO111MODULE=on, or by setting GO111MODULE=auto and running from outside GOPATH).

Finally, you may get some warnings when building. Those are related to the underlying Go OpenGL package and may be ignored for now.


i really so thankful for this obvious explanation.ok.i do what you said and report you everything.
i try to do instruction that you said correctlly. :wink:


hi iegomez.i apologize for giving your time,but please help me for solve these two problem
redis error:i check that at web and i understand this is not important but if i am wrong please tell me
device error: i use your conf file without change and get this error,i check this and see that brocaar said that this for DevEUI is unknown for loraserver.but i don’t know what musi i set it. :cry:
please help me :cry:


The Redis error doesn’t matter, it means the device has no keys, frame counters and nonces as it hasn’t joined yet.

As for the device, check that you set it correctly at lora-app-server. What do you see in the lorawan frames?


hi.i’m so sorry if i make you upset.
in lora-app-server i don’t set anything yet.only i add loraserver as a network server(localhost:8000)
i can’t find where i must add device.should i add a new application and then add a device??
and another question,how can i see lorawan frames?should i get log from lora-app-server but i can’t see anything about join message that i sent with gui.

thank again and apologize for my hurry


Yes, you need to create everything before: network server, service profile, application, device profile and then the device itself which belonmgs to an application and thus is created from there.

LoRaWAN frames may be seen at the device, there are different tabs (configuration, activation, device keys, etc.), and one of them is for the frames.


hi.i do what you ordered.and get uplink message as a lorawan frame but still i get a error and i think this happen because i set a variable wrong.can you help me again please? :sob:


The error is pretty clear: device does not support join. You need to assign a device profile that does support Join, i.e., an OTAA one (as opposed to ABP).

Maybe you should read a little about LoRaWAN and also the docs for Loraserver ( before blindly trying to get things to work, or you’ll keep hitting errors.


hi again.
i read papers about that but they told me to send message with ABP and because of this i don’t set (support OTAA).ok.i agree with you.i must read more about it.
and now device joined successfully.
and then send a data successfully.thank a lot again for your help.