Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
openwireless committed Nov 24, 2018
1 parent d275a21 commit 0c7f7a0
Show file tree
Hide file tree
Showing 2 changed files with 429 additions and 0 deletions.
333 changes: 333 additions & 0 deletions sgim/sgim.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,333 @@
/*
* sgim.cpp -- SGIM(V1) Control Class Library (implmentation)
*
* History:
* R0.1 2018/11/24 1st Release for SGIM(Ver1.0)
*
* Author:
* Open wireless Alliance and Atsushi Daikoku
*
*/

#include <sgim.h>

// Symbols
#define SEND_INTERVAL 10000UL //
#define END_OF_RESPONSE '\r' // Character '\r' marks the end of response.
// Command strings
#define CMD_END "\r"
#define CMD_SEND_MESSAGE "AT$SF=" // Prefix to send a message to SIGFOX cloud.
#define CMD_SEND_MESSAGE_RESPONSE ",1" // Expect downlink response from SIGFOX.
#define CMD_GET_ID "AT$I=10" // Get SIGFOX device ID.
#define CMD_GET_PAC "AT$I=11" // Get SIGFOX device PAC, used for registering the device.
#define CMD_GET_TEMPERATURE "AT$T?" // Get the module temperature.
#define CMD_GET_VOLTAGE "AT$V?" // Get the module voltage.
#define CMD_RESET "AT$P=0" // Software reset.
#define CMD_SLEEP "AT$P=1" // Switch to sleep mode : consumption is < 1.5uA
#define CMD_WAKEUP "AT$P=0" // Switch back to normal mode : consumption is 0.5 mA @change
#define CMD_RCZ3 "AT$IF=902080000" // JP / RCZ3 Frequency

// Define SGIM instance
// SGIM sigm;

//
bool SGIM::begin(void) {
if (_hasInitialized)
return false;

_hasInitialized = true;
_lastSent = 0;

pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW); // turn off
pinMode(interruptPin, INPUT_PULLUP);
// pinMode(1, OUTPUT);
// digitalWrite(1, HIGH); // External TX1 as high

// Set up Sigfox module
// pinMode(sigfoxResetPin, OUTPUT);
// digitalWrite(sigfoxResetPin, HIGH);

return true;
}

//
bool SGIM::end(void) {
if (! _hasInitialized)
return false;

_hasInitialized = true;

return true;
}

// Reboot Sigfox module
bool SGIM::reboot(void) {
String data;
uint8_t markers;
if (! sendCommand(String(CMD_RESET) + CMD_END, 1, data, markers))
return false;

return true;
}

// Reset SAMD21G18
void SGIM::reset(void) {
NVIC_SystemReset();
}

void SGIM::setLed(int onoff) {
digitalWrite(ledPin, onoff);
}

int SGIM::getVBAT(void) {
int mV = analogRead(vbatPin) * 2.444;
return (mV * 4.0);
}

int SGIM::onDetectMotion(void (*handler)(void)) {
_onMotionHandler = handler;
if (handler)
attachInterrupt(interruptPin, handler, LOW);
else
detachInterrupt(interruptPin);
}

bool SGIM::getID(String &id) {
String data;
uint8_t markers;
if (! sendCommand(String(CMD_GET_ID) + CMD_END, 1, data, markers))
return false;
id = data;

return true;
}

bool SGIM::getPAC(String &pac) {
String data;
uint8_t markers;
if (! sendCommand(String(CMD_GET_ID) + CMD_END, 1, data, markers))
return false;
pac = data;

return true;
}

bool SGIM::sendMessage(const String &payload) {
if (! isReady())
return false; // Prevent user from sending too many messages.

uint8_t markers;
String data, message = String(CMD_SEND_MESSAGE) + payload + CMD_END;
if (sendBuffer(message, TIMEOUT_UPLINK, 1, data, markers)) { // One '\r' marker expected ("OK\r").
_lastSent = millis();
return true; // OK
}

return false;
}

bool SGIM::sendMessageAndGetResponse(const String &payload, String &response) {
if (! isReady())
return false; // Prevent user from sending too many messages.

uint8_t markers;
String data, message = String(CMD_SEND_MESSAGE) + payload + CMD_SEND_MESSAGE_RESPONSE + CMD_END;
// Two '\r' markers expected ("OK\r RX=...\r").
if (sendBuffer(message, TIMEOUT_DOWNLINK, 2, data, markers)) {
_lastSent = millis();
response = data;
// Response contains OK\nRX=01 23 45 67 89 AB CD EF
// Remove the prefix and spaces.
response.replace("OK\nRX=", "");
response.replace(" ", "");
return true; // OK
}

return false;
}

bool SGIM::isReady(void) {
if (_lastSent == 0)
return true;
else if (millis() - _lastSent > SEND_INTERVAL)
return true;

return false;
}

bool SGIM::enterCommandMode(void) {
return true;
}

bool SGIM::exitCommandMode(void) {
return true;
}

bool SGIM::sleep(void) {
String data;
uint8_t markers;
if (! sendCommand(String(CMD_SLEEP) + CMD_END, 1, data, markers))
return false;

return true; // OK
}

bool SGIM::wakeup(void) {
sgSerial.begin(BAUDRATE_SIGFOX);
sgSerial.write('\r');
delay(30);
// sgSerial.flush();
sgSerial.end();

delay(100);

return true; // OK
}

bool SGIM::getVoltage(int &voltage) {
String data;
uint8_t markers;
if (! sendCommand(String(CMD_GET_VOLTAGE) + CMD_END, 1, data, markers))
return false;
voltage = data.toInt(); // Unit is "mV"

return true; // OK
}

bool SGIM::getTemperature(float &temperature) {
String data;
uint8_t markers;
if (! sendCommand(String(CMD_GET_TEMPERATURE) + CMD_END, 1, data, markers))
return false;
temperature = data.toInt() / 10.0;

return true; // OK
}

String SGIM::toHex(uint8_t u8) {
// Convert the char to a string of 2 hex digits.
uint8_t *b = (uint8_t *)&u8;
String bytes;
if (b[0] <= 0x0f)
bytes.concat('0');
bytes.concat(String(b[0], 16));

return bytes;
}

String SGIM::toHex(uint16_t u16) {
// Convert the integer to a string of 4 hex digits.
uint8_t *b = (uint8_t *)&u16;
String bytes;
for (int i = 0; i < 2; i++) {
if (b[i] <= 0x0f)
bytes.concat('0');
bytes.concat(String(b[i], 16));
}

return bytes;
}

String SGIM::toHex(uint32_t u32) {
// Convert the long to a string of 8 hex digits.
uint8_t * b = (uint8_t *)&u32;
String bytes;
for (int i = 0; i < 4; i++) {
if (b[i] <= 0x0f)
bytes.concat('0');
bytes.concat(String(b[i], 16));
}

return bytes;
}

String SGIM::toHex(char *s) {
// Convert the string to a string of hex digits.
uint8_t *b = (uint8_t *)s;
String bytes;
for (int i = 0; i < strlen(s); i++) {
if (b[i] <= 0x0f)
bytes.concat('0');
bytes.concat(String(b[i], 16));
}

return bytes;
}

String SGIM::toHex(float f) {
uint8_t *b = (uint8_t *)&f;
String bytes;
for (int i = 0; i < 4; i++) {
if (b[i] <= 0x0f)
bytes.concat('0');
bytes.concat(String(b[i], 16));
}

return bytes;
}

/*
* Private methods
*/

bool SGIM::sendBuffer(const String &buffer, const uint32_t timeout, uint8_t expectedMarkerCount, String &response, uint8_t &actualMarkerCount) {
response = "";
actualMarkerCount = 0;

sgSerial.begin(BAUDRATE_SIGFOX);
sgSerial.flush();

const char *rawBuffer = buffer.c_str();
unsigned long startTime = millis();
int i = 0;
for (;;) {
// If there is data to send, send it.
if (i < buffer.length()) {
uint8_t txChar = rawBuffer[i++];
sgSerial.write(txChar);
delay(2);
startTime = millis(); // Start the timer only when all data has been sent.
}
// If timeout, quit.
uint32_t currentTime = millis();
if (currentTime - startTime > timeout)
break;

// If data is available to receive, receive it.
if (sgSerial.available() > 0) {
int rxChar = sgSerial.read();
if (rxChar == -1)
continue;
if (rxChar == END_OF_RESPONSE) {
if (actualMarkerCount < markerPosMax)
_markerPos[actualMarkerCount] = response.length(); // Remember the marker pos.
actualMarkerCount++; // Count the number of end markers.
if (actualMarkerCount >= expectedMarkerCount)
break; // Seen all markers already.
} else {
response.concat(String((char)rxChar));
}
}
}

sgSerial.flush();
sgSerial.end();

// If we did not see the terminating '\r', something is wrong.
if (actualMarkerCount < expectedMarkerCount) {
return false; // No response or bad response
}

return true; // OK
}

bool SGIM::sendCommand(const String &cmd, uint8_t expectedMarkerCount, String &result, uint8_t &actualMarkerCount) {
String data;
if (! sendBuffer(cmd, TIMEOUT_LOCAL, expectedMarkerCount, data, actualMarkerCount))
return false;
result = data;

return true;
}

Loading

0 comments on commit 0c7f7a0

Please sign in to comment.