Ejemplo n.º 1
0
// Parses the input buffer and copies the received payload into the "received payload" buffer
// when a "mac rx" message has been received. It is called internally by macTransmit().
// Returns 0 (NoError) or otherwise one of the MacTransmitErrorCodes.
uint8_t Sodaq_RN2483::onMacRX()
{
    debugPrintLn("[onMacRX]");

    // parse inputbuffer, put payload into packet buffer
    char* token = strtok(this->inputBuffer, " ");

    // sanity check
    if (strcmp(token, STR_RESULT_MAC_RX) != 0) {
        debugPrintLn("[onMacRX]: mac_rx keyword not found!");
        return InternalError;
    }

    // port
    token = strtok(NULL, " ");

    // payload
    token = strtok(NULL, " "); // until end of string

    uint16_t len = strlen(token) + 1; // include termination char
    memcpy(this->receivedPayloadBuffer, token, len <= this->receivedPayloadBufferSize ? len : this->receivedPayloadBufferSize);

    this->packetReceived = true; // enable receive() again
    return NoError;
}
Ejemplo n.º 2
0
// Returns the enum that is mapped to the given "error" message.
uint8_t Sodaq_RN2483::lookupMacTransmitError(const char* error)
{
    debugPrint("[lookupMacTransmitError]: ");
    debugPrintLn(error);

    if (error[0] == 0) {
        debugPrintLn("[lookupMacTransmitError]: The string is empty!");
        return NoResponse;
    }

    StringEnumPair_t errorTable[] =
    {
        { STR_RESULT_INVALID_PARAM, InternalError },
        { STR_RESULT_NOT_JOINED, NotConnected },
        { STR_RESULT_NO_FREE_CHANNEL, Busy },
        { STR_RESULT_SILENT, Busy },
        { STR_RESULT_FRAME_COUNTER_ERROR, NetworkFatalError },
        { STR_RESULT_BUSY, Busy },
        { STR_RESULT_MAC_PAUSED, InternalError },
        { STR_RESULT_INVALID_DATA_LEN, PayloadSizeError },
        { STR_RESULT_MAC_ERROR, NoAcknowledgment },
    };

    for (StringEnumPair_t * p = errorTable; p->stringValue != NULL; ++p) {
        if (strcmp(p->stringValue, error) == 0) {
            debugPrint("[lookupMacTransmitError]: found ");
            debugPrintLn(p->enumValue);

            return p->enumValue;
        }
    }

    debugPrintLn("[lookupMacTransmitError]: not found!");
    return NoResponse;
}
Ejemplo n.º 3
0
// Sends a reset command to the module and waits for the success response (or timeout).
// Returns true on success.
bool Sodaq_RN2483::resetDevice()
{
    debugPrintLn("[resetDevice]");

    this->loraStream->print(STR_CMD_RESET);
    this->loraStream->print(CRLF);

    if (expectString(STR_DEVICE_TYPE_RN)) {
        if (strstr(this->inputBuffer, STR_DEVICE_TYPE_RN2483) != NULL) {
            debugPrintLn("The device type is RN2483");

            return true;
        }
        else if (strstr(this->inputBuffer, STR_DEVICE_TYPE_RN2903) != NULL) {
            debugPrintLn("The device type is RN2903");
            // TODO move into init once it is decided how to handle RN2903-specific operations
            setFsbChannels(DEFAULT_FSB);

            return true;
        }
        else {
            debugPrintLn("Unknown device type!");

            return false;
        }
    }

    return false;
}
Ejemplo n.º 4
0
// initialize the Lora stack
bool Hal::initLora()
{
#ifdef SODAQ_ONE
  // enable power, only for the Sodaq One
  pinMode(ENABLE_PIN_IO, OUTPUT);
  digitalWrite(ENABLE_PIN_IO, HIGH);
  // enable power to the grove shield
  pinMode(11, OUTPUT);
  digitalWrite(11, HIGH);

  pinMode(LED_RED, OUTPUT);
  pinMode(LED_GREEN, OUTPUT);
  pinMode(LED_BLUE, OUTPUT);
  GREEN();
#endif

  loraSerial.begin(LoRaBee.getDefaultBaudRate());

  LoRaBee.setDiag(debugSerial); // optional
  if (LoRaBee.initABP(loraSerial, devAddr, appSKey, nwkSKey, false))
  {
    debugPrintLn("Connection to the network was successful.");
    isHalInitialized = true;
    //    LoRaBee.resetUplinkCntr();
  }
  else
  {
    debugPrintLn("Connection to the network failed!");
  }
}
Ejemplo n.º 5
0
// GPIO interface
// Sets the mode of a GPIO ( digital in= 0, digital out = 1, analog = 2 )
// Returns true on successful setup.
uint8_t Sodaq_RN2483::pinMode(uint8_t gpio, pinModes mode) {
	//sanitize inputs,
	//GPIO4 does not do analog
	debugPrintLn("setting GPIO pin");
	if (mode == analog) {
		if (gpio==4) {
			return false;
			debugPrintLn("GPIO4 does not support analog");
		}
	}
	// only handle GPIO0-13
	if (gpio >13) {
		return false;
		debugPrintLn("GPIO out of bounds : 0-13 only");
	}
	// sys set pinmode <pinname> <pinFunc>
	this->loraStream->print(STR_SYS_SET);
	this->loraStream->print(STR_GPIO_MODE);
	this->loraStream->print(STR_GPIO);
	this->loraStream->print(gpio);
	if (mode == digitalIn) {
		this->loraStream->print(STR_GPIO_MODE_DIGIN);
	}
	else if (mode == digitalOut){
		this->loraStream->print(STR_GPIO_MODE_DIGOUT);
	}
	else {
		this->loraStream->print(STR_GPIO_MODE_ANA);
	}
	this->loraStream->print(CRLF);

	// parse response
	return expectOK();
}
Ejemplo n.º 6
0
// Sends the given payload with acknowledgement.
// Returns 0 (NoError) when transmission is successful or one of the MacTransmitErrorCodes otherwise.
uint8_t Sodaq_RN2483::sendReqAck(uint8_t port, const uint8_t* payload,
        uint8_t size, uint8_t maxRetries)
{
    debugPrintLn("[sendReqAck]");

    if (!setMacParam(STR_RETRIES, maxRetries)) {
        // not a fatal error -just show a debug message
        debugPrintLn("[sendReqAck] Non-fatal error: setting number of retries failed.");
    }

    return macTransmit(STR_CONFIRMED, port, payload, size);
}
Ejemplo n.º 7
0
bool Hal::initHal()
{
  debugPrintLn("Start init");
  // initialize all the hardware
  initLora();
  initSwitch();
  initLTC();
  compass.init();
  compass.enableDefault();
  htu.begin();
//  setAckOn();
  debugPrintLn("Einde init");
}
Ejemplo n.º 8
0
bool TheThingsUno::waitForOK(int waitTime) {
  String line = readLine(waitTime);
  if (!line) {
    debugPrintLn("Wait for OK time-out expired");
    return false;
  }

  if (line != "ok") {
    debugPrintLn("Response is not OK: " + line);
    return false;
  }

  return true;
}
Ejemplo n.º 9
0
bool TheThingsUno::join(const byte appEui[8], const byte appKey[16]) {
  // TODO: Check that mac deveui is set to sys hweui by default, otherwise put that in here
  sendCommand("mac set appeui", appEui, 8);
  sendCommand("mac set appkey", appKey, 16);
  sendCommand("mac join otaa");

  if (readLine() != "accepted") {
    debugPrintLn("Join not accepted");
    return false;
  }

  debugPrintLn("Join accepted. Status: " + readValue("mac get status"));
  return true;
}
Ejemplo n.º 10
0
bool TheThingsUno::personalize(const byte devAddr[4], const byte nwkSKey[16], const byte appSKey[16]) {
  sendCommand("mac set devaddr", devAddr, 4);
  sendCommand("mac set nwkskey", nwkSKey, 16);
  sendCommand("mac set appskey", appSKey, 16);
  sendCommand("mac join abp");

  if (readLine() != "accepted") {
    debugPrintLn("Personalize not accepted");
    return false;
  }

  debugPrintLn("Personalize accepted. Status: " + readValue("mac get status"));
  return true;
}
Ejemplo n.º 11
0
bool TheThingsUno::waitForOK(int waitTime, String okMessage) {
  String line = readLine(waitTime);
  if (line == "") {
    debugPrintLn("Wait for OK time-out expired");
    return false;
  }

  if (line != okMessage) {
    debugPrintLn("Response is not OK");
    return false;
  }

  return true;
}
Ejemplo n.º 12
0
String TheThingsUno::readValue(String cmd) {
  debugPrintLn("Reading value " + cmd);
  
  modemStream->println(cmd);
  
  return readLine();
}
Ejemplo n.º 13
0
void Sodaq_RN2483::sleep()
{
    debugPrintLn("[sleep]");

    this->loraStream->print(STR_CMD_SLEEP);
    this->loraStream->print(CRLF);
}
Ejemplo n.º 14
0
bool TheThingsUno::sendCommand(String cmd, int waitTime) {
  debugPrintLn("Sending: " + cmd);

  modemStream->println(cmd);

  return waitForOK(waitTime);
}
Ejemplo n.º 15
0
// Waits for the given string. Returns true if the string is received before a timeout.
// Returns false if a timeout occurs or if another string is received.
bool Sodaq_RN2483::expectString(const char* str, uint16_t timeout)
{
    debugPrint("[expectString] expecting "); debugPrint(str);
	
	

    unsigned long end  = millis() + timeout;
    while (millis() < end) {
        debugPrint(".");
		uint16_t len = readLn();
        if (len > 0) {
            debugPrint("("); debugWrite((uint8_t*)this->inputBuffer, len); debugPrint(")");

            if (strstr(this->inputBuffer, str) != NULL) {
                debugPrintLn(" found a match!");

                return true;
            }

            //return false;
        }
    }

    return false;
}
Ejemplo n.º 16
0
// Sends a reset command to the module and waits for the success response (or timeout).
// Returns true on success.
bool Sodaq_RN2483::resetDevice()
{
    debugPrintLn("[resetDevice]");

    this->loraStream->print(STR_CMD_RESET);
    this->loraStream->print(CRLF);

    return expectString(STR_DEVICE_TYPE);
}
Ejemplo n.º 17
0
bool TheThingsUno::sendCommand(String cmd, String value, int waitTime) {
  debugPrintLn("Sending: " + cmd + " with value " + value);

  modemStream->print(cmd + " ");
  for (int i = 0; i < value.length(); i++)
    modemStream->print(String(value.charAt(i), HEX));
  modemStream->println();

  return waitForOK(waitTime);
}
Ejemplo n.º 18
0
bool TheThingsUno::sendCommand(String cmd, const byte* buffer, int length, int waitTime) {
  debugPrintLn("Sending: " + cmd + " with " + String(length) + " bytes");

  modemStream->print(cmd + " ");
  for (int i = 0; i < length; i++)
    modemStream->print(String(buffer[i], HEX));
  modemStream->println();

  return waitForOK(waitTime);
}
Ejemplo n.º 19
0
// Sends a join network command to the device and waits for the response (or timeout).
// Returns true on success.
bool Sodaq_RN2483::joinNetwork(const char* type)
{
    debugPrintLn("[joinNetwork]");

    this->loraStream->print(STR_CMD_JOIN);
    this->loraStream->print(type);
    this->loraStream->print(CRLF);

    return expectOK() && expectString(STR_ACCEPTED, 10000);
}
Ejemplo n.º 20
0
String TheThingsUno::readLine(int waitTime) {
  unsigned long start = millis();
  while (millis() < start + waitTime) {
    String line = modemStream->readStringUntil('\n');
    if (line.length() >= 0) {
      debugPrintLn("Read " + line);
      return line.substring(0, line.length() - 1); // TODO: Check this
    }
  }
  return "";
}
Ejemplo n.º 21
0
bool Sodaq_RN2483::getMacParam(const char* paramName, char* paramValue, uint8_t size)
{
	debugPrint("[getMacParam] ");
    debugPrint(paramName);
	debugPrint("? ");

    this->loraStream->print(STR_CMD_GET);
    this->loraStream->print(paramName);
    this->loraStream->print(CRLF);

    if (readLn() > 0) {
		strncpy (paramValue, this->inputBuffer, size-1);
		paramValue[size-1] = 0x00;
		debugPrintLn(paramValue);
		return true;
	}
	debugPrintLn(" ERROR!");
	return false;
	
}
Ejemplo n.º 22
0
/*!
 * \brief Publish a message
 * \param topic The topic of the publish
 * \param msg The (binary) message to publish
 * \param msg_len The length of the (binary) message
 *
 * Create a PUBLISH packet and send it to the MQTT server
 *
 * \returns false if sending the message failed somehow
 */
bool MQTT::publish(const char * topic, const uint8_t * msg, size_t msg_len, uint8_t qos)
{
    debugPrintLn(DEBUG_PREFIX + "PUBLISH topic: " + topic);
    debugPrintLn(DEBUG_PREFIX + "PUBLISH msg:");
    debugDump(msg, msg_len);
    bool retval = false;

    if (_transport == 0) {
        goto ending;
    }

    if (_state != ST_MQTT_CONNECTED) {
        if (!connect()) {
            goto ending;
        }
    }

    newPacketIdentifier();

    uint8_t pckt[MQTT_MAX_PACKET_LENGTH];
    size_t pckt_len;
    // Assemble the PUBLISH packet
    pckt_len = assemblePublishPacket(pckt, sizeof(pckt), topic, msg, msg_len, qos);
    if (pckt_len == 0 || !_transport->sendMQTTPacket(pckt, pckt_len)) {
        goto ending;
    }

    if (qos == 0) {
        // Nothing to be received
    } else if (qos == 1) {
        // Handle incoming PUBACK
    } else if (qos == 2) {
        // Handle incoming PUBREC
    } else {
        // Shouldn't happen
    }
    retval = true;

ending:
    return retval;
}
Ejemplo n.º 23
0
// Sets the digital state of a pin
// Returns true on successful setting.
uint8_t Sodaq_RN2483::digitalWrite(uint8_t gpio, uint8_t state) {
	//sanitize inputs,
	// only handle GPIO0-13
	debugPrintLn("digitalWrite");
	if (gpio >13) {
		return false;
		debugPrintLn("GPIO out of bounds : 0-13 only");
	}
	// sys set pindig <pinname> <pinstate>
	// example: sys set pindig GPIO5 1
	this->loraStream->print(STR_SYS_SET);
	this->loraStream->print(STR_GPIO_DIG);
	this->loraStream->print(STR_GPIO);
	this->loraStream->print(gpio);
	this->loraStream->print(" ");
	this->loraStream->print(state);
	this->loraStream->print(CRLF);

	// parse response 
	return expectOK();
}
Ejemplo n.º 24
0
// Gets the digital state of a pin
// Returns the state of a GPIO ( true or false ), returns false if pin not set up
uint8_t Sodaq_RN2483::digitalRead(uint8_t gpio) {
	//sanitize inputs,
	// only handle GPIO0-13
	debugPrintLn("digitalRead");
	if (gpio >13) {
		return false;
		debugPrintLn("GPIO out of bounds : 0-13 only");
	}
	// sys get pindig <pinname>
	this->loraStream->print(STR_SYS_GET);
	this->loraStream->print(STR_GPIO_DIG);
	this->loraStream->print(STR_GPIO);
	this->loraStream->print(gpio);
	this->loraStream->print(CRLF);

	// parse response 
	// "1" means pin is High, so return true
	// will return false / 0 otherwise
	return expectString("1"); 

}
Ejemplo n.º 25
0
// Copies the latest received packet (optionally starting from the "payloadStartPosition"
// position of the payload) into the given "buffer", up to "size" number of bytes.
// Returns the number of bytes written or 0 if no packet is received since last transmission.
uint16_t Sodaq_RN2483::receive(uint8_t* buffer, uint16_t size,
        uint16_t payloadStartPosition)
{
    debugPrintLn("[receive]");

    if (!this->packetReceived) {
        debugPrintLn("[receive]: There is no packet received!");
        return 0;
    }

    uint16_t inputIndex = payloadStartPosition * 2; // payloadStartPosition is in bytes, not hex char pairs
    uint16_t outputIndex = 0;

    // check that the asked starting position is within bounds
    if (inputIndex >= this->receivedPayloadBufferSize) {
        debugPrintLn("[receive]: Out of bounds start position!");
        return 0;
    }

    // stop at the first string termination char, or if output buffer is over, or if payload buffer is over
    while (outputIndex < size
            && inputIndex + 1 < this->receivedPayloadBufferSize
            && this->receivedPayloadBuffer[inputIndex] != 0
            && this->receivedPayloadBuffer[inputIndex + 1] != 0) {
        buffer[outputIndex] = HEX_PAIR_TO_BYTE(
                this->receivedPayloadBuffer[inputIndex],
                this->receivedPayloadBuffer[inputIndex + 1]);

        inputIndex += 2;
        outputIndex++;
    }

    // Note: if the payload has an odd length, the last char is discarded

    buffer[outputIndex] = 0; // terminate the string

    debugPrintLn("[receive]: Done");
    return outputIndex;
}
Ejemplo n.º 26
0
// Initializes the device and connects to the network using Activation By Personalization.
// Returns true on successful connection.
bool Sodaq_RN2483::initABP(Stream& stream, const uint8_t devAddr[4], const uint8_t appSKey[16], const uint8_t nwkSKey[16])
{
    debugPrintLn("[initABP]");

    init(stream);

    return resetDevice() &&
		setMacParam(STR_DEV_ADDR, devAddr, 4) &&
        setMacParam(STR_APP_SESSION_KEY, appSKey, 16) &&
        setMacParam(STR_NETWORK_SESSION_KEY, nwkSKey, 16) &&
        //setMacParam(STR_ADR, BOOL_TO_ONOFF(adr)) &&
        joinNetwork(STR_ABP);
}
Ejemplo n.º 27
0
// Initializes the device and connects to the network using Over-The-Air Activation.
// Returns true on successful connection.
bool Sodaq_RN2483::initOTA(Stream& stream, const uint8_t devEUI[8], const uint8_t appEUI[8], const uint8_t appKey[16])
{
    debugPrintLn("[initOTA]");

    init(stream);

    return resetDevice() &&
        setMacParam(STR_DEV_EUI, devEUI, 8) &&
        setMacParam(STR_APP_EUI, appEUI, 8) &&
        setMacParam(STR_APP_KEY, appKey, 16) &&
     //   setMacParam(STR_ADR, BOOL_TO_ONOFF(adr)) &&
        joinNetwork(STR_OTAA);
}
Ejemplo n.º 28
0
/*!
 * \brief do stuff
 *
 * This function is used to do the following:
 *  - read incoming packets and call handlers (if there is one)
 */
bool MQTT::loop()
{
    // Is there a packet?
    bool status;
    size_t pckt_size;
    pckt_size = _transport->availableMQTTPacket();
    if (pckt_size > 0) {
        uint8_t mqtt_packet[256];
        char topic[128];
        uint8_t msg[128];
        MQTTPacketInfo pckt_info;
        pckt_info._topic = topic;
        pckt_info._topic_size = sizeof(topic);
        pckt_info._msg = msg;
        pckt_info._msg_size = sizeof(msg);

        pckt_size = _transport->receiveMQTTPacket(mqtt_packet, sizeof(mqtt_packet));
        if (pckt_size > 0) {
            // TODO

            debugPrintLn(DEBUG_PREFIX + " received packet:");
            debugDump(mqtt_packet, pckt_size);

            switch ((mqtt_packet[0] >> 4) & 0xF) {
            case CPT_PUBLISH:
                status = dissectPublishPacket(mqtt_packet, pckt_size, pckt_info);
                if (status) {
                    if (pckt_info._qos == 0) {
                        // Nothing else to do
                    } else if (pckt_info._qos == 1) {
                        // TODO
                        // Send PUBACK
                    } else if (pckt_info._qos == 2) {
                        // TODO
                        // Send PUBREC
                    } else {
                        // Shouldn't happen
                    }

                    if (_publishHandler) {
                        _publishHandler(topic, msg, pckt_info._msg_truncated_length);
                    }
                }
                break;
            default:
                if (_packetHandler) {
                    _packetHandler(mqtt_packet, pckt_size);
                }
                break;
            }
        }
Ejemplo n.º 29
0
// Gets the analog value of a pin
// Returns the ADC reading ( 0-1023 )
uint16_t Sodaq_RN2483::analogRead(uint8_t gpio) {
	uint16_t analogReading = 0;
	//sanitize inputs,
	// only handle GPIO0-13, but not 4
	debugPrintLn("analogRead");
	if (gpio >13 && gpio != 4) {
		return 0;
		debugPrintLn("GPIO out of bounds : 0-13 only, and not 4");
	}
	// sys get pinana <pinname>
	// example : sys get pinana GPIO0
	this->loraStream->print(STR_SYS_GET);
	this->loraStream->print(STR_GPIO_ANA);
	this->loraStream->print(STR_GPIO);
	this->loraStream->print(gpio);
	this->loraStream->print(CRLF);

	// parse response 
	// "1" means pin is High, so return true
	// will return false otherwise
	analogReading =	this->loraStream->parseInt();
	return analogReading;
}
Ejemplo n.º 30
0
// Sends the given mac command together with the given paramValue
// to the device and awaits for the response.
// Returns true on success.
// NOTE: paramName should include a trailing space
bool Sodaq_RN2483::setMacParam(const char* paramName, const char* paramValue)
{
    debugPrint("[setMacParam] ");
    debugPrint(paramName);
    debugPrint("= ");
    debugPrintLn(paramValue);

    this->loraStream->print(STR_CMD_SET);
    this->loraStream->print(paramName);
    this->loraStream->print(paramValue);
    this->loraStream->print(CRLF);

    return expectOK();
}