Compare commits
No commits in common. "e95297fe93337f9a863f72f5fab1bebe56f6b87f" and "927f3dc6c614fc20ff2300b1d34139deceaea063" have entirely different histories.
e95297fe93
...
927f3dc6c6
31
Makefile
Normal file
31
Makefile
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# dragino lora testing
|
||||||
|
# Single lora testing app
|
||||||
|
|
||||||
|
CC=g++
|
||||||
|
CFLAGS=-c -Wall `pkg-config --cflags sqlite3 'libprotobuf-c >= 1.0.0'`
|
||||||
|
LIBS=-lwiringPi -lprotobuf-c -lsqlite3
|
||||||
|
|
||||||
|
all: dragino_lora_app
|
||||||
|
|
||||||
|
dragino_lora_app: main.o protobuf.o message.pb-c.o database.o
|
||||||
|
$(CC) main.o protobuf.o database.o message.pb-c.o $(LIBS) -o dragino_lora_app
|
||||||
|
|
||||||
|
main.o: main.c protobuf.h
|
||||||
|
$(CC) $(CFLAGS) main.c
|
||||||
|
|
||||||
|
protobuf.o: message.pb-c.h protobuf.c protobuf.h
|
||||||
|
$(CC) $(CFLAGS) protobuf.c -o protobuf.o
|
||||||
|
|
||||||
|
protobuf.h: message.pb-c.h
|
||||||
|
|
||||||
|
database.o: database.c database.h
|
||||||
|
$(CC) $(CFLAGS) database.c -o database.o
|
||||||
|
|
||||||
|
message.pb-c.o: message.pb-c.h message.pb-c.c
|
||||||
|
$(CC) $(CFLAGS) message.pb-c.c -o message.pb-c.o
|
||||||
|
|
||||||
|
message.pb-c.h message.pb-c.c: message.proto
|
||||||
|
protoc-c --c_out=. message.proto
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm *.o dragino_lora_app message.pb-c.c message.pb-c.h
|
5
README
Normal file
5
README
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
Install the following packages on the Raspberry Pi:
|
||||||
|
wiringpi
|
||||||
|
|
||||||
|
Dragino User Manual:
|
||||||
|
www.dragino.com/downloads/downloads/LoRa-GPS-HAT/LoRa_GPS_HAT_UserManual_v1.0.pdf
|
@ -1,8 +0,0 @@
|
|||||||
# Dependencies
|
|
||||||
|
|
||||||
- protobuf-compiler
|
|
||||||
- python-sqlite
|
|
||||||
|
|
||||||
# Generate files from .proto file
|
|
||||||
|
|
||||||
```protoc -I=./ --python_out=./ message.proto```
|
|
53
database.c
Normal file
53
database.c
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
#include "database.h"
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
void database_state_init(struct database_state* s, const char* db_path) {
|
||||||
|
int return_code;
|
||||||
|
return_code = sqlite3_open_v2(db_path, &s->vm, SQLITE_OPEN_READWRITE, NULL);
|
||||||
|
assert(return_code == SQLITE_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void database_state_free(struct database_state* s) {
|
||||||
|
sqlite3_close_v2(s->vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
void database_write_active(struct database_state* s, int collar_id, int active_status) {
|
||||||
|
const char query[] = "UPDATE collar SET active=? WHERE id=?";
|
||||||
|
int return_code;
|
||||||
|
|
||||||
|
sqlite3_stmt* stmt;
|
||||||
|
return_code = sqlite3_prepare_v2(s->vm, query, sizeof(query), &stmt, NULL);
|
||||||
|
assert(return_code == SQLITE_OK);
|
||||||
|
return_code = sqlite3_bind_int(stmt, 1, active_status);
|
||||||
|
assert(return_code == SQLITE_OK);
|
||||||
|
return_code = sqlite3_bind_int(stmt, 2, collar_id);
|
||||||
|
assert(return_code == SQLITE_OK);
|
||||||
|
|
||||||
|
do {
|
||||||
|
return_code = sqlite3_step(stmt);
|
||||||
|
} while(return_code == SQLITE_ROW);
|
||||||
|
assert(return_code == SQLITE_DONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void database_write_location(struct database_state* s, int collar_id, double x, double y) {
|
||||||
|
const char query[] = "INSERT INTO data_point(collar_id, longitude, latitude, datetime)"
|
||||||
|
"VALUES (?, ?, ?, datetime('now'))";
|
||||||
|
int return_code;
|
||||||
|
|
||||||
|
sqlite3_stmt* stmt;
|
||||||
|
return_code = sqlite3_prepare_v2(s->vm, query, sizeof(query), &stmt, NULL);
|
||||||
|
assert(return_code == SQLITE_OK);
|
||||||
|
return_code = sqlite3_bind_int(stmt, 1, collar_id);
|
||||||
|
assert(return_code == SQLITE_OK);
|
||||||
|
return_code = sqlite3_bind_double(stmt, 2, x);
|
||||||
|
assert(return_code == SQLITE_OK);
|
||||||
|
return_code = sqlite3_bind_double(stmt, 3, y);
|
||||||
|
assert(return_code == SQLITE_OK);
|
||||||
|
|
||||||
|
do {
|
||||||
|
return_code = sqlite3_step(stmt);
|
||||||
|
} while(return_code == SQLITE_ROW);
|
||||||
|
assert(return_code == SQLITE_DONE);
|
||||||
|
}
|
14
database.h
Normal file
14
database.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#include <sqlite3.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
struct database_state {
|
||||||
|
sqlite3* vm;
|
||||||
|
};
|
||||||
|
|
||||||
|
void database_state_init(struct database_state* s, const char* db_path);
|
||||||
|
void database_state_free(struct database_state* s);
|
||||||
|
void database_write_active(struct database_state* s, int collar_id, int active_status);
|
||||||
|
void database_write_location(struct database_state* s, int collar_id, double x, double y);
|
||||||
|
|
||||||
|
}
|
488
main.c
Normal file
488
main.c
Normal file
@ -0,0 +1,488 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (c) 2018 Dragino
|
||||||
|
*
|
||||||
|
* http://www.dragino.com
|
||||||
|
*
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
#include <wiringPi.h>
|
||||||
|
#include <wiringPiSPI.h>
|
||||||
|
|
||||||
|
#include "protobuf.h"
|
||||||
|
#include "database.h"
|
||||||
|
|
||||||
|
// #############################################
|
||||||
|
// #############################################
|
||||||
|
|
||||||
|
#define REG_FIFO 0x00
|
||||||
|
#define REG_OPMODE 0x01
|
||||||
|
#define REG_FIFO_ADDR_PTR 0x0D
|
||||||
|
#define REG_FIFO_TX_BASE_AD 0x0E
|
||||||
|
#define REG_FIFO_RX_BASE_AD 0x0F
|
||||||
|
#define REG_RX_NB_BYTES 0x13
|
||||||
|
#define REG_FIFO_RX_CURRENT_ADDR 0x10
|
||||||
|
#define REG_IRQ_FLAGS 0x12
|
||||||
|
#define REG_DIO_MAPPING_1 0x40
|
||||||
|
#define REG_DIO_MAPPING_2 0x41
|
||||||
|
#define REG_MODEM_CONFIG 0x1D
|
||||||
|
#define REG_MODEM_CONFIG2 0x1E
|
||||||
|
#define REG_MODEM_CONFIG3 0x26
|
||||||
|
#define REG_SYMB_TIMEOUT_LSB 0x1F
|
||||||
|
#define REG_PKT_SNR_VALUE 0x19
|
||||||
|
#define REG_PAYLOAD_LENGTH 0x22
|
||||||
|
#define REG_IRQ_FLAGS_MASK 0x11
|
||||||
|
#define REG_MAX_PAYLOAD_LENGTH 0x23
|
||||||
|
#define REG_HOP_PERIOD 0x24
|
||||||
|
#define REG_SYNC_WORD 0x39
|
||||||
|
#define REG_VERSION 0x42
|
||||||
|
|
||||||
|
#define PAYLOAD_LENGTH 0x40
|
||||||
|
|
||||||
|
// LOW NOISE AMPLIFIER
|
||||||
|
#define REG_LNA 0x0C
|
||||||
|
#define LNA_MAX_GAIN 0x23
|
||||||
|
#define LNA_OFF_GAIN 0x00
|
||||||
|
#define LNA_LOW_GAIN 0x20
|
||||||
|
|
||||||
|
#define RegDioMapping1 0x40 // common
|
||||||
|
#define RegDioMapping2 0x41 // common
|
||||||
|
|
||||||
|
#define RegPaConfig 0x09 // common
|
||||||
|
#define RegPaRamp 0x0A // common
|
||||||
|
#define RegPaDac 0x5A // common
|
||||||
|
|
||||||
|
#define SX72_MC2_FSK 0x00
|
||||||
|
#define SX72_MC2_SF7 0x70
|
||||||
|
#define SX72_MC2_SF8 0x80
|
||||||
|
#define SX72_MC2_SF9 0x90
|
||||||
|
#define SX72_MC2_SF10 0xA0
|
||||||
|
#define SX72_MC2_SF11 0xB0
|
||||||
|
#define SX72_MC2_SF12 0xC0
|
||||||
|
|
||||||
|
#define SX72_MC1_LOW_DATA_RATE_OPTIMIZE 0x01 // mandated for SF11 and SF12
|
||||||
|
|
||||||
|
// sx1276 RegModemConfig1
|
||||||
|
#define SX1276_MC1_BW_125 0x70
|
||||||
|
#define SX1276_MC1_BW_250 0x80
|
||||||
|
#define SX1276_MC1_BW_500 0x90
|
||||||
|
#define SX1276_MC1_CR_4_5 0x02
|
||||||
|
#define SX1276_MC1_CR_4_6 0x04
|
||||||
|
#define SX1276_MC1_CR_4_7 0x06
|
||||||
|
#define SX1276_MC1_CR_4_8 0x08
|
||||||
|
|
||||||
|
#define SX1276_MC1_IMPLICIT_HEADER_MODE_ON 0x01
|
||||||
|
|
||||||
|
// sx1276 RegModemConfig2
|
||||||
|
#define SX1276_MC2_RX_PAYLOAD_CRCON 0x04
|
||||||
|
|
||||||
|
// sx1276 RegModemConfig3
|
||||||
|
#define SX1276_MC3_LOW_DATA_RATE_OPTIMIZE 0x08
|
||||||
|
#define SX1276_MC3_AGCAUTO 0x04
|
||||||
|
|
||||||
|
// preamble for lora networks (nibbles swapped)
|
||||||
|
#define LORA_MAC_PREAMBLE 0x34
|
||||||
|
|
||||||
|
#define RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG1 0x0A
|
||||||
|
#ifdef LMIC_SX1276
|
||||||
|
#define RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG2 0x70
|
||||||
|
#elif LMIC_SX1272
|
||||||
|
#define RXLORA_RXMODE_RSSI_REG_MODEM_CONFIG2 0x74
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// FRF
|
||||||
|
#define REG_FRF_MSB 0x06
|
||||||
|
#define REG_FRF_MID 0x07
|
||||||
|
#define REG_FRF_LSB 0x08
|
||||||
|
|
||||||
|
#define FRF_MSB 0xD9 // 868.1 Mhz
|
||||||
|
#define FRF_MID 0x06
|
||||||
|
#define FRF_LSB 0x66
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// Constants for radio registers
|
||||||
|
#define OPMODE_LORA 0x80
|
||||||
|
#define OPMODE_MASK 0x07
|
||||||
|
#define OPMODE_SLEEP 0x00
|
||||||
|
#define OPMODE_STANDBY 0x01
|
||||||
|
#define OPMODE_FSTX 0x02
|
||||||
|
#define OPMODE_TX 0x03
|
||||||
|
#define OPMODE_FSRX 0x04
|
||||||
|
#define OPMODE_RX 0x05
|
||||||
|
#define OPMODE_RX_SINGLE 0x06
|
||||||
|
#define OPMODE_CAD 0x07
|
||||||
|
|
||||||
|
// ----------------------------------------
|
||||||
|
// Bits masking the corresponding IRQs from the radio
|
||||||
|
#define IRQ_LORA_RXTOUT_MASK 0x80
|
||||||
|
#define IRQ_LORA_RXDONE_MASK 0x40
|
||||||
|
#define IRQ_LORA_CRCERR_MASK 0x20
|
||||||
|
#define IRQ_LORA_HEADER_MASK 0x10
|
||||||
|
#define IRQ_LORA_TXDONE_MASK 0x08
|
||||||
|
#define IRQ_LORA_CDDONE_MASK 0x04
|
||||||
|
#define IRQ_LORA_FHSSCH_MASK 0x02
|
||||||
|
#define IRQ_LORA_CDDETD_MASK 0x01
|
||||||
|
|
||||||
|
// DIO function mappings D0D1D2D3
|
||||||
|
#define MAP_DIO0_LORA_RXDONE 0x00 // 00------
|
||||||
|
#define MAP_DIO0_LORA_TXDONE 0x40 // 01------
|
||||||
|
#define MAP_DIO1_LORA_RXTOUT 0x00 // --00----
|
||||||
|
#define MAP_DIO1_LORA_NOP 0x30 // --11----
|
||||||
|
#define MAP_DIO2_LORA_NOP 0xC0 // ----11--
|
||||||
|
|
||||||
|
// #############################################
|
||||||
|
// #############################################
|
||||||
|
//
|
||||||
|
typedef bool boolean;
|
||||||
|
typedef unsigned char byte;
|
||||||
|
|
||||||
|
static const int CHANNEL = 0;
|
||||||
|
|
||||||
|
database_state db;
|
||||||
|
|
||||||
|
char message[256];
|
||||||
|
const char tok[2] = "|";
|
||||||
|
bool sx1272 = true;
|
||||||
|
|
||||||
|
byte receivedbytes;
|
||||||
|
|
||||||
|
enum sf_t { SF7=7, SF8, SF9, SF10, SF11, SF12 };
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
*
|
||||||
|
* Configure these values!
|
||||||
|
*
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
// SX1272 - Raspberry connections
|
||||||
|
int ssPin = 6;
|
||||||
|
int dio0 = 7;
|
||||||
|
int RST = 0;
|
||||||
|
|
||||||
|
// Set spreading factor (SF7 - SF12)
|
||||||
|
sf_t sf = SF7;
|
||||||
|
|
||||||
|
// Set center frequency
|
||||||
|
uint32_t freq = 915000000; // in Mhz! (915)
|
||||||
|
|
||||||
|
byte hello[32] = "HELLO";
|
||||||
|
|
||||||
|
void txlora(byte *frame, byte datalen);
|
||||||
|
static void configPower (int8_t pw);
|
||||||
|
void die(const char *s)
|
||||||
|
{
|
||||||
|
perror(s);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void selectreceiver()
|
||||||
|
{
|
||||||
|
digitalWrite(ssPin, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
void unselectreceiver()
|
||||||
|
{
|
||||||
|
digitalWrite(ssPin, HIGH);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte readReg(byte addr)
|
||||||
|
{
|
||||||
|
unsigned char spibuf[2];
|
||||||
|
|
||||||
|
selectreceiver();
|
||||||
|
spibuf[0] = addr & 0x7F;
|
||||||
|
spibuf[1] = 0x00;
|
||||||
|
wiringPiSPIDataRW(CHANNEL, spibuf, 2);
|
||||||
|
unselectreceiver();
|
||||||
|
|
||||||
|
return spibuf[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
void writeReg(byte addr, byte value)
|
||||||
|
{
|
||||||
|
unsigned char spibuf[2];
|
||||||
|
|
||||||
|
spibuf[0] = addr | 0x80;
|
||||||
|
spibuf[1] = value;
|
||||||
|
selectreceiver();
|
||||||
|
wiringPiSPIDataRW(CHANNEL, spibuf, 2);
|
||||||
|
|
||||||
|
unselectreceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void opmode (uint8_t mode) {
|
||||||
|
writeReg(REG_OPMODE, (readReg(REG_OPMODE) & ~OPMODE_MASK) | mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void opmodeLora() {
|
||||||
|
uint8_t u = OPMODE_LORA;
|
||||||
|
if (sx1272 == false)
|
||||||
|
u |= 0x8; // TBD: sx1276 high freq
|
||||||
|
writeReg(REG_OPMODE, u);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SetupLoRa()
|
||||||
|
{
|
||||||
|
|
||||||
|
digitalWrite(RST, HIGH);
|
||||||
|
delay(100);
|
||||||
|
digitalWrite(RST, LOW);
|
||||||
|
delay(100);
|
||||||
|
|
||||||
|
byte version = readReg(REG_VERSION);
|
||||||
|
|
||||||
|
if (version == 0x22) {
|
||||||
|
// sx1272
|
||||||
|
printf("SX1272 detected, starting.\n");
|
||||||
|
sx1272 = true;
|
||||||
|
} else {
|
||||||
|
// sx1276?
|
||||||
|
digitalWrite(RST, LOW);
|
||||||
|
delay(100);
|
||||||
|
digitalWrite(RST, HIGH);
|
||||||
|
delay(100);
|
||||||
|
version = readReg(REG_VERSION);
|
||||||
|
if (version == 0x12) {
|
||||||
|
// sx1276
|
||||||
|
//printf("SX1276 detected, starting.\n");
|
||||||
|
sx1272 = false;
|
||||||
|
} else {
|
||||||
|
printf("Unrecognized transceiver.\n");
|
||||||
|
//printf("Version: 0x%x\n",version);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
opmode(OPMODE_SLEEP);
|
||||||
|
|
||||||
|
// set frequency
|
||||||
|
uint64_t frf = ((uint64_t)freq << 19) / 32000000;
|
||||||
|
writeReg(REG_FRF_MSB, (uint8_t)(frf>>16) );
|
||||||
|
writeReg(REG_FRF_MID, (uint8_t)(frf>> 8) );
|
||||||
|
writeReg(REG_FRF_LSB, (uint8_t)(frf>> 0) );
|
||||||
|
|
||||||
|
writeReg(REG_SYNC_WORD, 0x34); // LoRaWAN public sync word
|
||||||
|
|
||||||
|
if (sx1272) {
|
||||||
|
if (sf == SF11 || sf == SF12) {
|
||||||
|
writeReg(REG_MODEM_CONFIG,0x0B);
|
||||||
|
} else {
|
||||||
|
writeReg(REG_MODEM_CONFIG,0x0A);
|
||||||
|
}
|
||||||
|
writeReg(REG_MODEM_CONFIG2,(sf<<4) | 0x04);
|
||||||
|
} else {
|
||||||
|
if (sf == SF11 || sf == SF12) {
|
||||||
|
writeReg(REG_MODEM_CONFIG3,0x0C);
|
||||||
|
} else {
|
||||||
|
writeReg(REG_MODEM_CONFIG3,0x04);
|
||||||
|
}
|
||||||
|
writeReg(REG_MODEM_CONFIG,0x72);
|
||||||
|
writeReg(REG_MODEM_CONFIG2,(sf<<4) | 0x04);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sf == SF10 || sf == SF11 || sf == SF12) {
|
||||||
|
writeReg(REG_SYMB_TIMEOUT_LSB,0x05);
|
||||||
|
} else {
|
||||||
|
writeReg(REG_SYMB_TIMEOUT_LSB,0x08);
|
||||||
|
}
|
||||||
|
writeReg(REG_MAX_PAYLOAD_LENGTH,0x80);
|
||||||
|
writeReg(REG_PAYLOAD_LENGTH,PAYLOAD_LENGTH);
|
||||||
|
writeReg(REG_HOP_PERIOD,0xFF);
|
||||||
|
writeReg(REG_FIFO_ADDR_PTR, readReg(REG_FIFO_RX_BASE_AD));
|
||||||
|
|
||||||
|
writeReg(REG_LNA, LNA_MAX_GAIN);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean receive(char *payload) {
|
||||||
|
// clear rxDone
|
||||||
|
writeReg(REG_IRQ_FLAGS, 0x40);
|
||||||
|
|
||||||
|
int irqflags = readReg(REG_IRQ_FLAGS);
|
||||||
|
|
||||||
|
// payload crc: 0x20
|
||||||
|
if((irqflags & 0x20) == 0x20)
|
||||||
|
{
|
||||||
|
printf("CRC error\n");
|
||||||
|
writeReg(REG_IRQ_FLAGS, 0x20);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
byte currentAddr = readReg(REG_FIFO_RX_CURRENT_ADDR);
|
||||||
|
byte receivedCount = readReg(REG_RX_NB_BYTES);
|
||||||
|
receivedbytes = receivedCount;
|
||||||
|
|
||||||
|
writeReg(REG_FIFO_ADDR_PTR, currentAddr);
|
||||||
|
|
||||||
|
for(int i = 0; i < receivedCount; i++)
|
||||||
|
{
|
||||||
|
payload[i] = (char)readReg(REG_FIFO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int send(char * s) {
|
||||||
|
opmode(OPMODE_STANDBY);
|
||||||
|
|
||||||
|
txlora((byte *) s, strlen((char *) s));
|
||||||
|
|
||||||
|
SetupLoRa();
|
||||||
|
opmodeLora();
|
||||||
|
opmode(OPMODE_STANDBY);
|
||||||
|
writeReg(RegPaRamp, (readReg(RegPaRamp) & 0xF0) | 0x08);
|
||||||
|
configPower(23);
|
||||||
|
opmode(OPMODE_RX);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void receivepacket() {
|
||||||
|
|
||||||
|
long int SNR;
|
||||||
|
int rssicorr;
|
||||||
|
|
||||||
|
if(digitalRead(dio0) == 1)
|
||||||
|
{
|
||||||
|
if(receive(message)) {
|
||||||
|
|
||||||
|
byte value = readReg(REG_PKT_SNR_VALUE);
|
||||||
|
if( value & 0x80 ) // The SNR sign bit is 1
|
||||||
|
{
|
||||||
|
// Invert and divide by 4
|
||||||
|
value = ( ( ~value + 1 ) & 0xFF ) >> 2;
|
||||||
|
SNR = -value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Divide by 4
|
||||||
|
SNR = ( value & 0xFF ) >> 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sx1272) {
|
||||||
|
rssicorr = 139;
|
||||||
|
} else {
|
||||||
|
rssicorr = 157;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
printf("Packet RSSI: %d, ", readReg(0x1A)-rssicorr);
|
||||||
|
printf("RSSI: %d, ", readReg(0x1B)-rssicorr);
|
||||||
|
printf("SNR: %li, ", SNR);
|
||||||
|
printf("Length: %i", (int)receivedbytes);
|
||||||
|
printf("\n");
|
||||||
|
printf("Payload: %s\n", message);
|
||||||
|
*/
|
||||||
|
|
||||||
|
Fenceless__CollarResponse * m = decode_update(sizeof(message), (uint8_t*) message);
|
||||||
|
printf("Received message (x, y): ");
|
||||||
|
printf("%f ", m->loc->x);
|
||||||
|
printf("%f", m->loc->y);
|
||||||
|
|
||||||
|
database_write_location(&db, 1, m->loc->x, m->loc->y);
|
||||||
|
|
||||||
|
|
||||||
|
} // received a message
|
||||||
|
|
||||||
|
} // dio0=1
|
||||||
|
}
|
||||||
|
|
||||||
|
static void configPower (int8_t pw) {
|
||||||
|
if (sx1272 == false) {
|
||||||
|
// no boost used for now
|
||||||
|
if(pw >= 17) {
|
||||||
|
pw = 15;
|
||||||
|
} else if(pw < 2) {
|
||||||
|
pw = 2;
|
||||||
|
}
|
||||||
|
// check board type for BOOST pin
|
||||||
|
writeReg(RegPaConfig, (uint8_t)(0x80|(pw&0xf)));
|
||||||
|
writeReg(RegPaDac, readReg(RegPaDac)|0x4);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// set PA config (2-17 dBm using PA_BOOST)
|
||||||
|
if(pw > 17) {
|
||||||
|
pw = 17;
|
||||||
|
} else if(pw < 2) {
|
||||||
|
pw = 2;
|
||||||
|
}
|
||||||
|
writeReg(RegPaConfig, (uint8_t)(0x80|(pw-2)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void writeBuf(byte addr, byte *value, byte len) {
|
||||||
|
unsigned char spibuf[256];
|
||||||
|
spibuf[0] = addr | 0x80;
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
spibuf[i + 1] = value[i];
|
||||||
|
}
|
||||||
|
selectreceiver();
|
||||||
|
wiringPiSPIDataRW(CHANNEL, spibuf, len + 1);
|
||||||
|
unselectreceiver();
|
||||||
|
}
|
||||||
|
|
||||||
|
void txlora(byte *frame, byte datalen) {
|
||||||
|
|
||||||
|
// set the IRQ mapping DIO0=TxDone DIO1=NOP DIO2=NOP
|
||||||
|
writeReg(RegDioMapping1, MAP_DIO0_LORA_TXDONE|MAP_DIO1_LORA_NOP|MAP_DIO2_LORA_NOP);
|
||||||
|
// clear all radio IRQ flags
|
||||||
|
writeReg(REG_IRQ_FLAGS, 0xFF);
|
||||||
|
// mask all IRQs but TxDone
|
||||||
|
writeReg(REG_IRQ_FLAGS_MASK, ~IRQ_LORA_TXDONE_MASK);
|
||||||
|
|
||||||
|
// initialize the payload size and address pointers
|
||||||
|
writeReg(REG_FIFO_TX_BASE_AD, 0x00);
|
||||||
|
writeReg(REG_FIFO_ADDR_PTR, 0x00);
|
||||||
|
writeReg(REG_PAYLOAD_LENGTH, datalen);
|
||||||
|
|
||||||
|
// download buffer to the radio FIFO
|
||||||
|
writeBuf(REG_FIFO, frame, datalen);
|
||||||
|
// now we actually start the transmission
|
||||||
|
opmode(OPMODE_TX);
|
||||||
|
|
||||||
|
printf("send: %s\n", frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (int argc, char *argv[]) {
|
||||||
|
if (argc != 2) {
|
||||||
|
printf("./a.out [Database Location]");
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
database_state_init(&db, argv[1]);
|
||||||
|
}
|
||||||
|
wiringPiSetup () ;
|
||||||
|
pinMode(ssPin, OUTPUT);
|
||||||
|
pinMode(dio0, INPUT);
|
||||||
|
pinMode(RST, OUTPUT);
|
||||||
|
|
||||||
|
wiringPiSPISetup(CHANNEL, 500000);
|
||||||
|
|
||||||
|
SetupLoRa();
|
||||||
|
|
||||||
|
opmodeLora();
|
||||||
|
opmode(OPMODE_STANDBY);
|
||||||
|
writeReg(RegPaRamp, (readReg(RegPaRamp) & 0xF0) | 0x08);
|
||||||
|
configPower(23);
|
||||||
|
opmode(OPMODE_RX);
|
||||||
|
while(1) {
|
||||||
|
receivepacket();
|
||||||
|
delay(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
database_state_free(&db);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
63
main.py
63
main.py
@ -1,63 +0,0 @@
|
|||||||
import paho.mqtt.client as mqtt
|
|
||||||
import json
|
|
||||||
import base64
|
|
||||||
import message_pb2
|
|
||||||
import sqlite3
|
|
||||||
|
|
||||||
app_id = "fenceles_grazing"
|
|
||||||
access_key = "ttn-account-v2.XVvtBVcWzkeby-fe9eLtiJBLRbjQR-b358S4z70Xa-0"
|
|
||||||
|
|
||||||
|
|
||||||
# For now use collar id of 1, should look up collar id based on collarname from db
|
|
||||||
def store_coord(collarname, x, y):
|
|
||||||
print("Coord {x: " + str(x) + ", y: " + str(y) + "}")
|
|
||||||
db = sqlite3.connect('data.sqlite')
|
|
||||||
entries = [(1, x, y)]
|
|
||||||
db.executemany("INSERT INTO data_point (collar_id, longitude, latitude, datetime) VALUES (?,?,?,datetime('now'))", entries)
|
|
||||||
db.commit()
|
|
||||||
db.close()
|
|
||||||
|
|
||||||
# The callback for when the client receives a CONNACK response from the server.
|
|
||||||
def on_connect(client, userdata, flags, rc):
|
|
||||||
print("Connected with result code "+str(rc))
|
|
||||||
|
|
||||||
# Subscribing in on_connect() means that if we lose the connection and
|
|
||||||
# reconnect then subscriptions will be renewed.
|
|
||||||
# client.subscribe("+/devices/+/events/activations")
|
|
||||||
client.subscribe("+/devices/+/up")
|
|
||||||
client.publish(appid+"/devices/+/down", "hello world")
|
|
||||||
|
|
||||||
# The callback for when a PUBLISH message is received from the server.
|
|
||||||
def on_message(client, userdata, msg):
|
|
||||||
# Print entire payload
|
|
||||||
print(msg.payload)
|
|
||||||
# Parse payload (JSON)
|
|
||||||
payload = json.loads(msg.payload)
|
|
||||||
|
|
||||||
# Decode payload_raw, which is the protobuf
|
|
||||||
code = payload['payload_raw']
|
|
||||||
bcode = base64.b64decode(code)
|
|
||||||
res = message_pb2.CollarResponse()
|
|
||||||
res.ParseFromString(bcode)
|
|
||||||
store_coord(payload['dev_id'], res.loc.x, res.loc.y)
|
|
||||||
|
|
||||||
# Test protobuf here
|
|
||||||
# code = bytearray('CgoNAAAAABUAAAAA', "utf-8")
|
|
||||||
# print(code)
|
|
||||||
# bcode = base64.b64decode(code)
|
|
||||||
# res = message_pb2.CollarResponse()
|
|
||||||
# res.ParseFromString(bcode)
|
|
||||||
# print("Coord {x: " + str(res.loc.x) + ", y: " + str(res.loc.y) + "}")
|
|
||||||
|
|
||||||
client = mqtt.Client()
|
|
||||||
client.on_connect = on_connect
|
|
||||||
client.on_message = on_message
|
|
||||||
|
|
||||||
client.username_pw_set(app_id, access_key)
|
|
||||||
client.connect("us-west.thethings.network", 1883, 60)
|
|
||||||
|
|
||||||
# Blocking call that processes network traffic, dispatches callbacks and
|
|
||||||
# handles reconnecting.
|
|
||||||
# Other loop*() functions are available that give a threaded interface and a
|
|
||||||
# manual interface.
|
|
||||||
client.loop_forever()
|
|
12
message.proto
Normal file
12
message.proto
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
syntax = "proto2";
|
||||||
|
|
||||||
|
package Fenceless;
|
||||||
|
|
||||||
|
message Coordinate {
|
||||||
|
required float x = 1;
|
||||||
|
required float y = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CollarResponse {
|
||||||
|
required Coordinate loc = 1;
|
||||||
|
}
|
32
protobuf.c
Normal file
32
protobuf.c
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#include "message.pb-c.h"
|
||||||
|
#include "protobuf.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
void* _allocator_alloc(void*, size_t count) {
|
||||||
|
return malloc(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _allocator_free(void*, void* data) {
|
||||||
|
free(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ProtobufCAllocator malloc_allocator = {
|
||||||
|
_allocator_alloc, _allocator_free, NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
void encode_update(double x, double y, uint8_t* buffer) {
|
||||||
|
Fenceless__Coordinate coord;
|
||||||
|
Fenceless__CollarResponse response;
|
||||||
|
|
||||||
|
fenceless__coordinate__init(&coord);
|
||||||
|
coord.x = x;
|
||||||
|
coord.y = y;
|
||||||
|
|
||||||
|
fenceless__collar_response__init(&response);
|
||||||
|
response.loc = &coord;
|
||||||
|
fenceless__collar_response__pack(&response, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
Fenceless__CollarResponse* decode_update(size_t len, uint8_t* buffer) {
|
||||||
|
return fenceless__collar_response__unpack(&malloc_allocator, len, buffer);
|
||||||
|
}
|
4
protobuf.h
Normal file
4
protobuf.h
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
#include "message.pb-c.h"
|
||||||
|
|
||||||
|
void encode_update(double x, double y, uint8_t* buffer);
|
||||||
|
Fenceless__CollarResponse* decode_update(size_t len, uint8_t* buffer);
|
Loading…
Reference in New Issue
Block a user