From f37f200792444fee2f74e807acfd5be7c9180cd7 Mon Sep 17 00:00:00 2001 From: Votre Nom Date: Wed, 30 Aug 2017 10:48:11 +0400 Subject: [PATCH] Init repo --- GEOLOC/Makefile | 34 +++++++ GEOLOC/Readme.md | 47 +++++++++ GEOLOC/app/Makefile | 18 ++++ GEOLOC/app/anchor/Makefile | 22 ++++ GEOLOC/app/anchor/app.c | 83 +++++++++++++++ GEOLOC/app/anchor/app.h | 17 ++++ GEOLOC/app/anchor/records.c | 51 ++++++++++ GEOLOC/app/anchor/records.h | 17 ++++ GEOLOC/app/anchor/socket/Makefile | 15 +++ GEOLOC/app/anchor/socket/clientBC.c | 45 ++++++++ GEOLOC/app/anchor/socket/clientTCP.c | 46 +++++++++ GEOLOC/app/anchor/socket/com.c | 44 ++++++++ GEOLOC/app/anchor/socket/com.h | 40 ++++++++ GEOLOC/app/anchor/socket/gwframe.h | 16 +++ GEOLOC/app/anchor/socket/serverBC.c | 51 ++++++++++ GEOLOC/app/anchor/socket/serverTCP.c | 61 +++++++++++ GEOLOC/app/frame.c | 22 ++++ GEOLOC/app/frame.h | 21 ++++ GEOLOC/app/mobile/app.c | 84 +++++++++++++++ GEOLOC/app/mobile/app.h | 16 +++ GEOLOC/lib/config.c | 51 ++++++++++ GEOLOC/lib/config.h | 62 +++++++++++ GEOLOC/lib/dragino.c | 40 ++++++++ GEOLOC/lib/dragino.h | 38 +++++++ GEOLOC/lib/fskconfig.c | 66 ++++++++++++ GEOLOC/lib/fskconfig.h | 67 ++++++++++++ GEOLOC/lib/gps.c | 147 +++++++++++++++++++++++++++ GEOLOC/lib/gps.h | 53 ++++++++++ GEOLOC/lib/types.h | 10 ++ GEOLOC/main.c | 51 ++++++++++ Readme.md | 6 ++ 31 files changed, 1341 insertions(+) create mode 100644 GEOLOC/Makefile create mode 100644 GEOLOC/Readme.md create mode 100644 GEOLOC/app/Makefile create mode 100644 GEOLOC/app/anchor/Makefile create mode 100644 GEOLOC/app/anchor/app.c create mode 100644 GEOLOC/app/anchor/app.h create mode 100644 GEOLOC/app/anchor/records.c create mode 100644 GEOLOC/app/anchor/records.h create mode 100644 GEOLOC/app/anchor/socket/Makefile create mode 100644 GEOLOC/app/anchor/socket/clientBC.c create mode 100644 GEOLOC/app/anchor/socket/clientTCP.c create mode 100644 GEOLOC/app/anchor/socket/com.c create mode 100644 GEOLOC/app/anchor/socket/com.h create mode 100644 GEOLOC/app/anchor/socket/gwframe.h create mode 100644 GEOLOC/app/anchor/socket/serverBC.c create mode 100644 GEOLOC/app/anchor/socket/serverTCP.c create mode 100644 GEOLOC/app/frame.c create mode 100644 GEOLOC/app/frame.h create mode 100644 GEOLOC/app/mobile/app.c create mode 100644 GEOLOC/app/mobile/app.h create mode 100644 GEOLOC/lib/config.c create mode 100644 GEOLOC/lib/config.h create mode 100644 GEOLOC/lib/dragino.c create mode 100644 GEOLOC/lib/dragino.h create mode 100644 GEOLOC/lib/fskconfig.c create mode 100644 GEOLOC/lib/fskconfig.h create mode 100644 GEOLOC/lib/gps.c create mode 100644 GEOLOC/lib/gps.h create mode 100644 GEOLOC/lib/types.h create mode 100644 GEOLOC/main.c create mode 100644 Readme.md diff --git a/GEOLOC/Makefile b/GEOLOC/Makefile new file mode 100644 index 0000000..fdf543d --- /dev/null +++ b/GEOLOC/Makefile @@ -0,0 +1,34 @@ +EXEC=GEOLOC +export TARGET=MOBILE# ANCHOR or MOBILE +export ANCHOR_ID=2# Define the anchor id +export IS_MASTER=0# Define if this anchor is master or not +export CC=gcc -g -D TARGET=$(TARGET) -D ANCHOR_ID=$(ANCHOR_ID) -D IS_MASTER=$(IS_MASTER) -Ilib -lm -pthread +export LDFLAGS=-lwiringPi + +all:$(EXEC) + +$(EXEC): main.o lib/dragino.o lib/config.o lib/fskconfig.o app/app.o lib/gps.o + $(CC) $^ -o $(EXEC) $(LDFLAGS) + +main.o: main.c + $(CC) -c $< -o $@ + +lib/dragino.o: lib/dragino.c + $(CC) -c $^ -o $@ + +lib/config.o: lib/config.c + $(CC) -c $^ -o $@ + +lib/fskconfig.o: lib/fskconfig.c + $(CC) -c $^ -o $@ + +lib/gps.o: lib/gps.c + $(CC) -c $^ -o $@ + +app/app.o: + $(MAKE) -C ./app + +clean: + -$(MAKE) -C ./app clean + -find ./ -name "*.o" -delete + -rm $(EXEC) diff --git a/GEOLOC/Readme.md b/GEOLOC/Readme.md new file mode 100644 index 0000000..d12a02e --- /dev/null +++ b/GEOLOC/Readme.md @@ -0,0 +1,47 @@ +GEOLOC +=================== + + +Some explanations about the GEOLOC project. + +---------- + + +Folders structure +------------- + +#### lib + +Contains library for accessing to dragino shield components (GPS and SX1276). It contains also tools for SX1276 registers configurations. + + +#### app + +Contains mobile application (turtle transmitter) and anchor application (gateway). + + +#### app/anchor/socket + +Contains application for gateway communication. + +#### records + +Folder created by the GEOLOC application to store received frame from mobile application and slave gateways. + +Build the project +------------- + +Configure the project by changing variable from Makefile : + +1. **TARGET** : Choose between MOBILE or ANCHOR (take care to do not add space at the end of the variable) +2. **ANCHOR_ID** : Change the anchor id +3. **IS_MASTER** : Define if the anchor is the master 1 for yes and 0 for no + +Next run the next command in the project root folder to build the project : + + make + To clear the project run : + + + make clean + \ No newline at end of file diff --git a/GEOLOC/app/Makefile b/GEOLOC/app/Makefile new file mode 100644 index 0000000..4f23251 --- /dev/null +++ b/GEOLOC/app/Makefile @@ -0,0 +1,18 @@ + +all: app.o + +app.o: +ifeq ($(TARGET),ANCHOR) + $(MAKE) -C ./anchor + cp anchor/app.o ./ +else + $(CC) -c ./mobile/app.c -o ./app.o +endif + $(CC) -c frame.c -o frame.o + ld -r app.o frame.o -o app_tmp.o + mv app_tmp.o $@ + +.PHONY: clean + +clean: + -rm ./app.o ./frame.o diff --git a/GEOLOC/app/anchor/Makefile b/GEOLOC/app/anchor/Makefile new file mode 100644 index 0000000..91280a1 --- /dev/null +++ b/GEOLOC/app/anchor/Makefile @@ -0,0 +1,22 @@ + +all: app.o + +app.o: socket.o app_tmp.o records.o + ld -r $^ -o $@ + -rm app_tmp.o + +socket.o: + $(MAKE) -C ./socket + cp socket/socket.o ./ + +records.o:records.c + $(CC) -c $^ -o $@ + +app_tmp.o:app.c + $(CC) -c $^ -o $@ + +.PHONY: clean + +clean: + $(MAKE) clean -C ./socket + -rm ./*.o diff --git a/GEOLOC/app/anchor/app.c b/GEOLOC/app/anchor/app.c new file mode 100644 index 0000000..4ff2c6e --- /dev/null +++ b/GEOLOC/app/anchor/app.c @@ -0,0 +1,83 @@ +#include +#include +#include +#include +#include +#include "app.h" +#include "../frame.h" +#include +#include "../../lib/gps.h" +#include "socket/com.h" +#include "records.h" + +//extern struct NMEA_GGA NmeaGgaFrame; +pthread_mutex_t mutex_NmeaGgaFrame; // Mutex for thread that use MASTER_IP + +void runApp(Config config){ + // Hello msg + printf("\n|Starting gateway application|\n\n"); + + // Start GW communication + startGWCom(); + + // Ensure we are in standby mode and apply configuration + config.mode=MODE_STDBY; + applyMode(config); + applyConfig(config); + + config.mode=MODE_RX; + applyMode(config); + + pthread_t frameHandlerThread; + + printf("Wait for packet...\n"); + while(1){ + if(digitalRead(0x7)==1){ + // Build parameters + Frame frame=pullFrame(); + int rssi=fetchRSSI(); + void *param; + param=malloc(sizeof(Frame)+sizeof(int)); + *((Frame *)param)=frame; + *((int *)(param+sizeof(Frame)))=rssi; + // Run thread + pthread_create(&frameHandlerThread, NULL, handleMessage, param); + config.mode=MODE_STDBY; + applyMode(config); + config.mode=MODE_RX; + applyMode(config); + } + } + pthread_join(frameHandlerThread,NULL); + +} + +void *handleMessage(void *args){ + // Fetch parameters + Frame frame=*((Frame *)args); + int rssi=*((int *)(args+sizeof(Frame))); + + // Print informations + printf("Packet receive !!!\n\n"); + printf("Frame info :\nId : %d\nStamp : %d\nData 1-6 : %d %d %d %d %d %d\nRSSI : %d\n\n", + frame.id, frame.stamp, + frame.data[0],frame.data[1],frame.data[2],frame.data[3],frame.data[4],frame.data[5], + rssi); + + GWFrame masterFrame; + masterFrame.slaveID=ANCHOR_ID; + + pthread_mutex_lock(& mutex_NmeaGgaFrame); + masterFrame.ggaFrame=getNMEA_GGAFrame(); + pthread_mutex_unlock(& mutex_NmeaGgaFrame); + + masterFrame.frame=frame; + masterFrame.rssi=rssi; + + if(!IS_MASTER){ + sendDataToMaster(masterFrame); + } + else{ + saveFrame(masterFrame); + } +} diff --git a/GEOLOC/app/anchor/app.h b/GEOLOC/app/anchor/app.h new file mode 100644 index 0000000..06d569b --- /dev/null +++ b/GEOLOC/app/anchor/app.h @@ -0,0 +1,17 @@ +#ifndef app_h +#define app_h + +#include "../frame.h" +#include "../../lib/config.h" + +/** + * Run the application + */ +void runApp(Config config); + +/** + * Used to handle received frame from mobile + */ +void *handleMessage(void *args); + +#endif diff --git a/GEOLOC/app/anchor/records.c b/GEOLOC/app/anchor/records.c new file mode 100644 index 0000000..db14206 --- /dev/null +++ b/GEOLOC/app/anchor/records.c @@ -0,0 +1,51 @@ + +#include "records.h" +#include +#include +#include +#include + +void saveFrame(GWFrame frame){ + // Create records dir if not exists + mkdir(RECORDS_DIR,0777); + +// // Build string + char idStr[50]; + sprintf(idStr,"/anchor_%d", frame.slaveID); + char filePath[200]; + filePath[0]='\0'; + strcat(filePath, RECORDS_DIR); + strcat(filePath, idStr); + +// // Save in file + FILE *file; + short writeHeader=0; + pthread_mutex_lock (& mutex_file); + if(access( filePath, F_OK ) == -1){ + writeHeader=1; + } + file=fopen(filePath,"a+"); + if(file!=NULL){ + if(writeHeader){ + fprintf(file,"GWID,GPSSTATE,LatDeg,LatMin,LatSec,LatDir,LonDeg,LonMin,LonSec,LonDir,turtleID,rssi\n"); + } + fprintf(file,"%d,%d,%d,%d,%f,%d,%d,%d,%f,%d,%d,%d\n", + frame.slaveID, + frame.ggaFrame.state, + frame.ggaFrame.latDeg, + frame.ggaFrame.latMin, + frame.ggaFrame.latSec, + frame.ggaFrame.latDir, + frame.ggaFrame.lonDeg, + frame.ggaFrame.lonMin, + frame.ggaFrame.lonSec, + frame.ggaFrame.lonDir, + frame.frame.id, + frame.rssi); + fclose(file); + } + else{ + printf("Failed to open file %s.\n",filePath); + } + pthread_mutex_unlock (& mutex_file); +} diff --git a/GEOLOC/app/anchor/records.h b/GEOLOC/app/anchor/records.h new file mode 100644 index 0000000..db17b8a --- /dev/null +++ b/GEOLOC/app/anchor/records.h @@ -0,0 +1,17 @@ +#ifndef records_h +#define records_h + +#include +#include "socket/gwframe.h" + +#define RECORDS_DIR "./records" + +// Mutex for thread writing in same file +pthread_mutex_t mutex_file; + +/** + * Save GWFrame into file + */ +void saveFrame(GWFrame frame); + +#endif diff --git a/GEOLOC/app/anchor/socket/Makefile b/GEOLOC/app/anchor/socket/Makefile new file mode 100644 index 0000000..84632b2 --- /dev/null +++ b/GEOLOC/app/anchor/socket/Makefile @@ -0,0 +1,15 @@ + +all:socket.o + +socket.o: clientTCP.c serverTCP.c clientBC.c serverBC.c com.c + $(CC) -c clientTCP.c + $(CC) -c serverTCP.c + $(CC) -c clientBC.c + $(CC) -c serverBC.c + $(CC) -c com.c + ld -r ./*.o -o $@ + +.PHONY: clean + +clean: + -rm ./*.o diff --git a/GEOLOC/app/anchor/socket/clientBC.c b/GEOLOC/app/anchor/socket/clientBC.c new file mode 100644 index 0000000..8230a6d --- /dev/null +++ b/GEOLOC/app/anchor/socket/clientBC.c @@ -0,0 +1,45 @@ +#include +#include //strlen +#include +#include +#include //inet_addr +#include "com.h" + + + + +void rcvIPFromMaster() +{ + int socketID; + struct sockaddr_in SockAddr; + int allowBC=1; + + socketID=socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + setsockopt(socketID,SOL_SOCKET,SO_BROADCAST,(void*) &allowBC,sizeof(allowBC)); + + SockAddr.sin_family=AF_INET; + SockAddr.sin_port=htons(DATA_PORT); + SockAddr.sin_addr.s_addr=htonl(INADDR_BROADCAST); + + + int binded=bind(socketID,(struct sockaddr *) &SockAddr,sizeof(SockAddr)); + if(binded<0){ + puts("Failed to bind socket for receiving IP from master."); + close(socketID); + } + else{ + listen(socketID,3); + socklen_t src_addr_len=sizeof(SockAddr); + char buffer[MASTER_IP_SIZE]; + memset(buffer, 0x0,MASTER_IP_SIZE); + recvfrom(socketID,buffer,sizeof(buffer),0,(struct sockaddr*)&SockAddr,&src_addr_len); + close(socketID); + puts(buffer); + + pthread_mutex_lock(&mutex_master_ip); + memset(MASTER_IP, 0x0,MASTER_IP_SIZE); + memcpy(MASTER_IP, buffer,MASTER_IP_SIZE); + pthread_mutex_unlock(&mutex_master_ip); + } + +} diff --git a/GEOLOC/app/anchor/socket/clientTCP.c b/GEOLOC/app/anchor/socket/clientTCP.c new file mode 100644 index 0000000..621da24 --- /dev/null +++ b/GEOLOC/app/anchor/socket/clientTCP.c @@ -0,0 +1,46 @@ +#include +#include //strlen +#include +#include +#include +#include //inet_addr +#include "com.h" + +void sendDataToMaster(GWFrame frame){ + + int socket_desc; + struct sockaddr_in server; + socket_desc=socket(AF_INET, SOCK_STREAM,0); + char message[1000]="GET / HTTP/1.1\r\n\r\n"; + char serverReply[2000]; + + if(socket_desc==-1){ + puts("Failed to create socket."); + } + else{ + // Configure server + pthread_mutex_lock(&mutex_master_ip); + server.sin_addr.s_addr = inet_addr(MASTER_IP); + pthread_mutex_unlock(&mutex_master_ip); + server.sin_family = AF_INET; + server.sin_port = htons(DATA_PORT); + + if(connect(socket_desc,(struct sockaddr *)&server, sizeof(server))<0){ + puts("Failed to connect to server"); + } + else{ + puts("Socket connected"); + if(send(socket_desc, &frame, sizeof(GWFrame),0)<0){ + puts("Failed to send message."); + } + puts("Data send !"); + if(recv(socket_desc, serverReply,2000,0)<0){ + puts("Timeout"); + } + puts(serverReply); + + } + + close(socket_desc); + } +} diff --git a/GEOLOC/app/anchor/socket/com.c b/GEOLOC/app/anchor/socket/com.c new file mode 100644 index 0000000..f0fa1d2 --- /dev/null +++ b/GEOLOC/app/anchor/socket/com.c @@ -0,0 +1,44 @@ +#include +#include +#include +#include "com.h" +#include "../records.h" + +static void *rcvIPFromMasterThread(void *args){ + while(1){ + rcvIPFromMaster(); + puts("Master IP receive !"); + //delay(IP_SEND_INTERVAL/2); // Add delay to free cpu resources + } +} + +static void *sendIPToSlaveThread(void *args){ + while(1){ + puts("Send Master IP to slave..."); + sendIPToSlave(); + delay(IP_SEND_INTERVAL); // Wait five minutes + } +} + + +static void *rcvDataFromSlaveThread(void *args){ + while(1){ + GWFrame frame; + frame=rcvDataFromSlave(); + puts("Frame receive from a slave !"); + saveFrame(frame); + } +} + +void startGWCom(){ + +#if IS_MASTER != 0 + pthread_t sendIPThread, rcvDataThread; + pthread_create(&sendIPThread, NULL, sendIPToSlaveThread, NULL); + pthread_create(&rcvDataThread, NULL, rcvDataFromSlaveThread, NULL); +#else + pthread_t rcvIPThread; + pthread_create(&rcvIPThread, NULL, rcvIPFromMasterThread, NULL); +#endif + +} diff --git a/GEOLOC/app/anchor/socket/com.h b/GEOLOC/app/anchor/socket/com.h new file mode 100644 index 0000000..18539e5 --- /dev/null +++ b/GEOLOC/app/anchor/socket/com.h @@ -0,0 +1,40 @@ +#ifndef com_h +#define com_h + +#include "gwframe.h" + +#define IP_SEND_INTERVAL 300000 +#define DATA_PORT 8888 +#define IFACE "wlan0" +#define MASTER_IP_SIZE 100 // Buffer size for IP address char + +char MASTER_IP[MASTER_IP_SIZE]; // Master IP (global variable) +pthread_mutex_t mutex_master_ip; // Mutex for thread that use MASTER_IP + +/** + * Init GW communication + */ +void startGWCom(); + +/** + * Send GW frame to master GW + */ +void sendDataToMaster(GWFrame frame); + +/** + * Start master GW slave frame receiver server + */ +GWFrame rcvDataFromSlave(); + +/** + * Start slave ip reveiver server + */ +void rcvIPFromMaster(); + +/** + * Send master ip to slaves (broadcast UDP) + */ +void sendIPToSlave(); + + +#endif diff --git a/GEOLOC/app/anchor/socket/gwframe.h b/GEOLOC/app/anchor/socket/gwframe.h new file mode 100644 index 0000000..b454d8c --- /dev/null +++ b/GEOLOC/app/anchor/socket/gwframe.h @@ -0,0 +1,16 @@ +#ifndef gwframe_h +#define gwframe_h + +#include "../../frame.h" +#include "../../../lib/gps.h" + +typedef struct GWFrame GWFrame; +struct GWFrame { + short slaveID; + struct NMEA_GGA ggaFrame; + int rssi; + Frame frame; +}; + + +#endif diff --git a/GEOLOC/app/anchor/socket/serverBC.c b/GEOLOC/app/anchor/socket/serverBC.c new file mode 100644 index 0000000..2e2da88 --- /dev/null +++ b/GEOLOC/app/anchor/socket/serverBC.c @@ -0,0 +1,51 @@ +#include +#include //strlen +#include +#include +#include "com.h" +#include +#include +#include //inet_addr + + + +static char *getIp(){ + int fd; + struct ifreq ifr; + + char iface[] = IFACE; + + fd = socket(AF_INET, SOCK_DGRAM, 0); + + //Type of address to retrieve - IPv4 IP address + ifr.ifr_addr.sa_family = AF_INET; + + //Copy the interface name in the ifreq structure + strncpy(ifr.ifr_name , iface , IFNAMSIZ-1); + + ioctl(fd, SIOCGIFADDR, &ifr); + + close(fd); + return(inet_ntoa(( (struct sockaddr_in *)&ifr.ifr_addr )->sin_addr)); +} + +void sendIPToSlave() +{ + int socketID; + struct sockaddr_in SockAddr; + int allowBC=1; + + socketID=socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); + setsockopt(socketID,SOL_SOCKET,SO_BROADCAST,(void*) &allowBC,sizeof(allowBC)); + + SockAddr.sin_family=AF_INET; + SockAddr.sin_port=htons(DATA_PORT); + SockAddr.sin_addr.s_addr=htonl(INADDR_BROADCAST); + + char *addr; + addr=getIp(); + sendto(socketID,addr,strlen(addr),0,(struct sockaddr*)&SockAddr, sizeof(SockAddr)); + +} + + diff --git a/GEOLOC/app/anchor/socket/serverTCP.c b/GEOLOC/app/anchor/socket/serverTCP.c new file mode 100644 index 0000000..2ed9b71 --- /dev/null +++ b/GEOLOC/app/anchor/socket/serverTCP.c @@ -0,0 +1,61 @@ + +#include +#include //strlen +#include +#include +#include //inet_addr +#include "com.h" +#include "./gwframe.h" +#include "../records.h" + + +int serverTCP_socket_desc=-1; + +GWFrame rcvDataFromSlave(){ + + if(serverTCP_socket_desc==-1){ + // Create socket + serverTCP_socket_desc=socket(AF_INET, SOCK_STREAM,0); + if(serverTCP_socket_desc==-1){ + puts("Failed to create socket"); + exit(1); + } + struct sockaddr_in listen_addr; + + listen_addr.sin_family = AF_INET; + listen_addr.sin_addr.s_addr = INADDR_ANY; + listen_addr.sin_port = htons(DATA_PORT); + + int binded=bind(serverTCP_socket_desc,(struct sockaddr *) &listen_addr,sizeof(listen_addr)); + if(binded<0){ + puts("Failed to bind, trying until it work..."); + while(binded<0){ + binded=bind(serverTCP_socket_desc,(struct sockaddr *) &listen_addr,sizeof(listen_addr)); + sleep(1); + } + puts("Bind succeed !"); + } + + listen(serverTCP_socket_desc,3); + } + + int client,len; + struct sockaddr_in client_addr; + client=accept(serverTCP_socket_desc, (struct sockaddr *)&client_addr, (socklen_t*)&len); + if(client<0){ + close(serverTCP_socket_desc); + serverTCP_socket_desc=-1; + puts("Acceptation failed"); + } + else{ + GWFrame frame; + recv(client, &frame, sizeof(GWFrame),0); + char msg[100]="Données bien reçus par la gateway maitre."; + write(client, msg,strlen(msg)); + close(client); + return(frame); + + } +} + + diff --git a/GEOLOC/app/frame.c b/GEOLOC/app/frame.c new file mode 100644 index 0000000..1908075 --- /dev/null +++ b/GEOLOC/app/frame.c @@ -0,0 +1,22 @@ +#include "frame.h" + + +void pushFrame(Frame frame){ + writeReg(REG_FIFO, frame.id); + writeReg(REG_FIFO, frame.stamp); + int i; + for(i=0;i +#include +#include +#include "app.h" +#include "../frame.h" +#include +#include "../../lib/gps.h" +#include + +extern struct NMEA_GGA NmeaGgaFrame; + +void runApp(Config config){ + + // Hello msg + printf("\n|Starting mobile application|\n\n"); + + // Ensure we are in standby mode and apply configuration + config.mode=MODE_STDBY; + applyMode(config); + applyConfig(config); + + // Write frame on sx1276 + Frame frame; + frame.id=234; + frame.stamp=81; + frame.data[0]=76; + frame.data[1]=17; + frame.data[2]=16; + frame.data[3]=87; + frame.data[4]=12; + frame.data[5]=106; + pushFrame(frame); + config.mode=MODE_TX; + applyMode(config); // Send frame + + // Wait for frame to be sending + while(1){ + if(digitalRead(0x7)==1){ + printf("Packet send !!!\n\n"); + config.mode=MODE_STDBY; + applyMode(config); + saveGPSPosition(); + delay(2000); + // Write frame on sx1276 + pushFrame(frame); + config.mode=MODE_TX; + applyMode(config); // Send frame + } + } +} + +void saveGPSPosition(){ + + // Fetch GPS position + NmeaGgaFrame=getNMEA_GGAFrame(); + + // Save in file + FILE *file; + char filePath[]="gps.csv"; + short writeHeader=0; + if(access( filePath, F_OK ) == -1){ + writeHeader=1; + } + file=fopen(filePath,"a+"); + if(file!=NULL){ + if(writeHeader){ + fprintf(file,"GPSSTATE,LatDeg,LatMin,LatSec,LatDir,LonDeg,LonMin,LonSec,LonDir\n"); + } + fprintf(file,"%d,%d,%d,%f,%d,%d,%d,%f,%d\n", + NmeaGgaFrame.state, + NmeaGgaFrame.latDeg, + NmeaGgaFrame.latMin, + NmeaGgaFrame.latSec, + NmeaGgaFrame.latDir, + NmeaGgaFrame.lonDeg, + NmeaGgaFrame.lonMin, + NmeaGgaFrame.lonSec, + NmeaGgaFrame.lonDir); + fclose(file); + } + else{ + printf("Failed to open file %s.\n",filePath); + } +} diff --git a/GEOLOC/app/mobile/app.h b/GEOLOC/app/mobile/app.h new file mode 100644 index 0000000..80e661b --- /dev/null +++ b/GEOLOC/app/mobile/app.h @@ -0,0 +1,16 @@ +#ifndef app_h +#define app_h + +#include "../../lib/config.h" + +/** + * Run the application + */ +void runApp(Config config); + +/** + * Save the GPS position + */ +void saveGPSPosition(); + +#endif diff --git a/GEOLOC/lib/config.c b/GEOLOC/lib/config.c new file mode 100644 index 0000000..b086628 --- /dev/null +++ b/GEOLOC/lib/config.c @@ -0,0 +1,51 @@ +#include "config.h" + +void applyConfig(Config config){ + + // Apply modulation and mode + byte reg=readReg(REG_OP_MODE) &0x3F ; // Fetch opmode register and clear modulation and mode bits + reg=reg | config.mod; // Apply modulation and mode + writeReg(REG_OP_MODE,reg); // Send register back to module + + // Apply carrier frequency + int cFreq=config.cFreq/FSTEP; + reg=cFreq >> 16 ; + writeReg(REG_FRF_MSB,reg); // Send register to module + reg=(cFreq&0x00FFFF) >> 8 ; + writeReg(REG_FRF_MID,reg); /// Send register to module + reg=(cFreq&0x0000FF); + writeReg(REG_FRF_LSB,reg); // Send register to module + + // Set LNAGain + reg=readReg(REG_LNA) & 0x7F; + writeReg(REG_LNA, reg|config.lnaGain); + + + // Apply PaBoost, max output power and outputPower + byte Pmax=round((config.maxPower-10.8)/0.6); + Pmax=(Pmax & 0x07)<<4; + byte outputPower; + if(config.paSelect==PA_SELECT_ON){ + outputPower=config.outputPower-32; + } + else{ + outputPower=config.outputPower-Pmax+15; + } + outputPower=config.outputPower & 0x0F; + reg=config.paSelect|outputPower|Pmax; + writeReg(REG_PA_CONFIG, reg); + + + // Apply FSK configuration + if(config.mod==MOD_FSK){ + applyFSKConfig(config.fsk); + } +} + +void applyMode(Config config){ + // Apply modulation and mode + byte reg=readReg(REG_OP_MODE) &0xF8 ; // Fetch opmode register and clear mode + reg=config.mode | reg; // Apply mode + writeReg(REG_OP_MODE,reg); // Send register back to module + +} diff --git a/GEOLOC/lib/config.h b/GEOLOC/lib/config.h new file mode 100644 index 0000000..47a7151 --- /dev/null +++ b/GEOLOC/lib/config.h @@ -0,0 +1,62 @@ +#ifndef config_h +#define config_h + +#include "dragino.h" +#include "types.h" +#include "fskconfig.h" +#include + +// Define General Registers +#define REG_FIFO 0x00 +#define REG_OP_MODE 0x01 +#define REG_VERSION 0x42 +#define REG_FRF_MSB 0x06 +#define REG_FRF_MID 0x07 +#define REG_FRF_LSB 0x08 +#define REG_PA_CONFIG 0x09 + +// Define General Registers values +#define MODE_SLEEP 0x00 +#define MODE_STDBY 0x01 +#define MODE_TX 0x03 +#define MODE_RX 0x05 +#define MOD_LORA 0x80 +#define MOD_FSK 0x00 +#define MOD_OOK 0x40 +#define LNA_GAIN_G1 0x20 +#define LNA_GAIN_G2 0x40 +#define LNA_GAIN_G3 0x60 +#define LNA_GAIN_G4 0x80 +#define LNA_GAIN_G5 0xA0 +#define LNA_GAIN_G6 0xC0 +#define PA_SELECT_ON 0x80 +#define PA_SELECT_OFF 0x00 + + + +// Define global configuration +typedef struct Config Config; +struct Config { + byte mod; + byte mode; + int cFreq; + FSKConfig fsk; // FSK Specific configuration + byte lnaGain; + byte paSelect; + short maxPower; + short outputPower; + // TODO LORA Specific configuration +}; + + +/** + * Apply global configuration (module mode is unchanged here) + */ +void applyConfig(Config config); + +/** + * Change SX1276 mode (SLEEP, TX, RX etc...) + */ +void applyMode(Config config); + +#endif diff --git a/GEOLOC/lib/dragino.c b/GEOLOC/lib/dragino.c new file mode 100644 index 0000000..30de48a --- /dev/null +++ b/GEOLOC/lib/dragino.c @@ -0,0 +1,40 @@ +#include "dragino.h" + + +void initPins(){ + // Init WiringPi + wiringPiSetup(); + pinMode(NSS_PIN, OUTPUT); + pinMode(DIO0_PIN, INPUT); + pinMode(RESET_PIN, OUTPUT); + wiringPiSPISetup(CHANNEL, BIT_RATE); +} + +byte readReg(byte address){ + byte buffer[2]; + buffer[0]=address & 0x7F; // Set read flag (SX1276 datasheet page 80) + buffer[1]=0x00; + + digitalWrite(NSS_PIN, LOW); + wiringPiSPIDataRW(CHANNEL, buffer, 2); + digitalWrite(NSS_PIN, HIGH); + + return(buffer[1]); +} +void writeReg(byte address, byte data){ + byte buffer[2]; + buffer[0]=address | 0x80; // Set write flag (SX1276 datasheet page 80) + buffer[1]=data; + + digitalWrite(NSS_PIN, LOW); + wiringPiSPIDataRW(CHANNEL, buffer, 2); + digitalWrite(NSS_PIN, HIGH); +} + +void reset(){ + // SX1276 datasheet page 116 + digitalWrite(RESET_PIN, LOW); + delay(100); + digitalWrite(RESET_PIN, HIGH); + delay(100); +} diff --git a/GEOLOC/lib/dragino.h b/GEOLOC/lib/dragino.h new file mode 100644 index 0000000..082de14 --- /dev/null +++ b/GEOLOC/lib/dragino.h @@ -0,0 +1,38 @@ +#ifndef dragino_h +#define dragino_h + +#include "types.h" +#include +#include + +// Define WiringPi Parameters +#define CHANNEL 0 +#define BIT_RATE 500000 + +// Define dragino shield pin for use SPI protocol (see http://wiki.dragino.com/index.php?title=Lora/GPS_HAT) +#define NSS_PIN 6 +#define RESET_PIN 0 +#define DIO0_PIN 7 +#define TX_PIN 15 + +/** + * Configure WiringPi for SPI + */ +void initPins(); + +/** + * Used to init and reset SX1276 + */ +void reset(); + +/** + * Read in SX1276 register + */ +byte readReg(byte address); + +/** + * Write in SX1276 register + */ +void writeReg(byte address, byte value); + +#endif diff --git a/GEOLOC/lib/fskconfig.c b/GEOLOC/lib/fskconfig.c new file mode 100644 index 0000000..42f3775 --- /dev/null +++ b/GEOLOC/lib/fskconfig.c @@ -0,0 +1,66 @@ +#include "fskconfig.h" + +void applyFSKConfig(FSKConfig fsk){ + + // Set preambleDetection + byte reg=readReg(REG_PREAMBLE_DETECT)&0x7F; + writeReg(REG_PREAMBLE_DETECT, fsk.preambleDetection | reg); + + // Set preamble size + reg=fsk.preambleSize>>8; + writeReg(REG_PREAMBLE_MSB, reg); + reg=fsk.preambleSize & 0x00ff; + writeReg(REG_PREAMBLE_LSB, reg); + + // Set crcOn + reg=readReg(REG_PACKET_CONFIG_1) & 0xEF; + writeReg(REG_PACKET_CONFIG_1,reg|fsk.crcOn); + + // Set crc autoclear + reg=readReg(REG_PACKET_CONFIG_1) & 0xF7; + writeReg(REG_PACKET_CONFIG_1,reg|fsk.crcAutoClearOff); + + // Set payloadLength + reg=readReg(REG_PACKET_CONFIG_2) & 0xF8; + byte payloadLengthMSB=(fsk.payloadLength >> 8) &0x7; + byte payloadLengthLSB=fsk.payloadLength &0xFF; + writeReg(REG_PACKET_CONFIG_2,payloadLengthMSB|reg); + writeReg(REG_PAYLOAD_LENGTH, payloadLengthLSB); + + // Set fifo threshold + reg=readReg(REG_FIFO_THRESH) & 0xC0; + reg=reg| (fsk.fifoThreshold & 0x3F); + writeReg(REG_FIFO_THRESH,reg); + + // Set fixedPayloadLength + reg=readReg(REG_PACKET_CONFIG_1) & 0x7F; + writeReg(REG_PACKET_CONFIG_1,reg | fsk.fixedPayloadLength); + + // Set frequency dev + short freqDev=fsk.freqDev/FSTEP; + byte freqDevMSB=freqDev>>8; + byte freqDevLSB=freqDev&0x00FF; + writeReg(REG_FDEV_MSB, freqDevMSB); + writeReg(REG_FDEV_LSB, freqDevLSB); + + // Apply bitrate // + short bitrate=FXOSC/fsk.bitrate; + byte bitrateMSB=bitrate>>8; + byte bitrateLSB=bitrate & 0x00FF; + writeReg(REG_BITRATE_MSB, bitrateMSB); + writeReg(REG_BITRATE_LSB, bitrate & 0x0F); + + // Apply rssi smoothing + reg=readReg(REG_RSSI_CONFIG) & 0xF8; + reg=reg|fsk.rssiSmoothing; + writeReg(REG_RSSI_CONFIG,reg); + +} + + +int fetchRSSI(){ + int value=readReg(REG_RSSI_VALUE); + value=(-value)/2; // See SX1276 datasheet page 86 + return(value); +} + diff --git a/GEOLOC/lib/fskconfig.h b/GEOLOC/lib/fskconfig.h new file mode 100644 index 0000000..ea6d771 --- /dev/null +++ b/GEOLOC/lib/fskconfig.h @@ -0,0 +1,67 @@ +#ifndef fskconfig_h +#define fskconfig_h + +#include "dragino.h" +#include "types.h" + +// Define FSK Registers +#define REG_PREAMBLE_DETECT 0x1f +#define REG_PREAMBLE_MSB 0x25 +#define REG_PREAMBLE_LSB 0x26 +#define REG_PACKET_CONFIG_1 0x30 +#define REG_PACKET_CONFIG_2 0x31 +#define REG_PAYLOAD_LENGTH 0x32 +#define REG_FIFO_THRESH 0x35 +#define REG_LNA 0x0C +#define REG_FDEV_MSB 0x04 +#define REG_FDEV_LSB 0x05 +#define REG_BITRATE_MSB 0x02 +#define REG_BITRATE_LSB 0x03 +#define REG_RSSI_CONFIG 0x0E +#define REG_RSSI_VALUE 0x11 + +// Define FSK configuration parameters values +#define CRC_ON 0x10 +#define CRC_OFF 0x00 +#define CRC_AUTOCLEAR_OFF_ON 0x08 +#define CRC_AUTOCLEAR_OFF_OFF 0x00 +#define FIXED_PAYLOAD_LENGTH_ON 0x80 +#define FIXED_PAYLOAD_LENGTH_OFF 0x00 +#define PREAMBLE_DETECTION_ON 0x80 +#define PREAMBLE_DETECTION_OFF 0x00 +#define RSSI_SAMPLE_2 0x00 +#define RSSI_SAMPLE_4 0x01 +#define RSSI_SAMPLE_8 0x02 +#define RSSI_SAMPLE_16 0x03 +#define RSSI_SAMPLE_32 0x04 +#define RSSI_SAMPLE_64 0x05 +#define RSSI_SAMPLE_128 0x06 +#define RSSI_SAMPLE_256 0x07 + + +// Define FSK Configuration +typedef struct FSKConfig FSKConfig; +struct FSKConfig { + byte preambleDetection; + short preambleSize; + short fifoThreshold; + short payloadLength; + short freqDev; + short bitrate; + byte rssiSmoothing; + byte crcOn; + byte crcAutoClearOff; + byte fixedPayloadLength; +}; + +/** + * Apply FSK configuration + */ +void applyFSKConfig(FSKConfig fsk); + +/** + * Fetch FSK RSSI + */ +int fetchRSSI(); + +#endif diff --git a/GEOLOC/lib/gps.c b/GEOLOC/lib/gps.c new file mode 100644 index 0000000..4eec6cc --- /dev/null +++ b/GEOLOC/lib/gps.c @@ -0,0 +1,147 @@ +#include "gps.h" +#include +#include +#include +#include +#include +#include + +#define GPS_DEV_FILE "/dev/ttyS0" // Define GPS serial port file +#define BUFFER_SIZE 100 // Define receive buffer size + +/** + * Configure UART channel + * TODO : Set baud rate to ???? see NMEA datasheet + */ +void configSerialPort(int fd){ + struct termios Termios; + tcgetattr(fd,&Termios); + Termios.c_lflag |= ICANON; + tcsetattr(fd,TCSANOW,&Termios); + tcflush(fd, TCIFLUSH); // Clear already received frames +} + +/** + * Fetch NMEA Frame type + * TODO : Other frame types + */ +NMEA_TYPE getNMEA_TYPE(unsigned char *data){ + unsigned char* typeChar=malloc(sizeof(char)*4); + typeChar[3]='\0'; + memcpy(typeChar, data+3,3); + if(strcmp(typeChar, "GGA")==0){ + return(GGA); + } + free(typeChar); + return(NONE); +} + +/** + * Build NMEA frame from array of char + * TODO : Other GGA parameters + */ +struct NMEA_GGA buildNMEA_GGA(unsigned char *data){ +// data="$GPGGA,095003.000,2055.9571,S,05517.4159,E,1,6,1.59,138.8,M,-9.9,M,,*5D"; // To test !!! + struct NMEA_GGA frame; + unsigned char *buffer=malloc(sizeof(char)*strlen(data)); + memcpy(buffer,data,strlen(data)); + + short i=1; + char *saveP; + char *token=strtok_r(buffer,",",&saveP); + while(token!=NULL){ + if(strlen(token)>0){ + char tmp[6]; + switch(i){ + case 2: // Fetch hour, min, sec and ms + memcpy(tmp,token,2);tmp[2]='\0'; + frame.hour=atoi(tmp); + memcpy(tmp,token+2,2); + frame.min=atoi(tmp); + memcpy(tmp,token+4,2); + frame.sec=atoi(tmp); + memcpy(tmp,token+7,3);tmp[3]='\0'; + frame.ms=atoi(tmp); + break; + case 3: // Fetch Latitude + memcpy(tmp,token,2);tmp[2]='\0'; + frame.latDeg=atoi(tmp); + memcpy(tmp,token+2,2); + frame.latMin=atoi(tmp); + memcpy(tmp,token+5,4);tmp[4]='\0'; + frame.latSec=atoi(tmp); + frame.latSec=frame.latSec/10000; + frame.latSec=(3600*frame.latSec)/60; // Convertion degrès min en degrès sec + break; + case 4: // Fetch latitude direction + frame.latDir=token[0]; + break; + case 5: // Fetch longitude + memcpy(tmp,token,3);tmp[3]='\0'; + frame.lonDeg=atoi(tmp); + tmp[2]='\0'; + memcpy(tmp,token+3,2); + frame.lonMin=atoi(tmp); + memcpy(tmp,token+6,4);tmp[4]='\0'; + frame.lonSec=atoi(tmp); + frame.lonSec=frame.lonSec/10000; + frame.lonSec=(3600*frame.lonSec)/60; // Convertion degrès min en degrès sec + break; + case 6: // Fetch longitude direction + frame.lonDir=token[0]; + break; + case 7: // Fetch GPS state + frame.state=atoi(token); + break; + case 8: // Fetch number of statellites + frame.sats=atoi(token); + break; + } + } + token=strtok_r(NULL,",",&saveP); + i++; + } + + free(buffer); + return(frame); + +} + +/** + * Fetch NMEA FRAME + */ +struct NMEA_GGA getNMEA_GGAFrame(){ + + int fd; // File descriptor + const char *device = "/dev/ttyS0"; + fd = open(device, O_RDWR); + if(fd == -1) { + printf( "Failed to open gps device.\n" ); + } + + // Configure the serial port + configSerialPort(fd); + + struct NMEA_GGA frame; // Def empty frame + short i; + // Try to feth the GGA frame (100 times max) + for(i=0;i<100;i++){ + char out[BUFFER_SIZE]; + memset(out,0,BUFFER_SIZE); + read(fd,out,BUFFER_SIZE); + if(strlen(out)>1){ + if(getNMEA_TYPE(out)==GGA){ + frame=buildNMEA_GGA(out); + //if(frame.state!=UNFIXED){ + // printf("%d:%d:%d:%d\nLat : %d deg %d min %f sec %d Dir\n",frame.hour,frame.min,frame.sec,frame.ms,frame.latDeg,frame.latMin,frame.latSec, frame.latDir); + // printf("Lon : %d deg %d min %f sec %d Dir\n",frame.lonDeg,frame.lonMin,frame.lonSec, frame.lonDir); + // printf("Sats : %d",frame.sats); + // printf("%s",out); + //} + break; // If the frame is found, exit + } + } + } + close(fd); + return(frame); +} diff --git a/GEOLOC/lib/gps.h b/GEOLOC/lib/gps.h new file mode 100644 index 0000000..49dbdd6 --- /dev/null +++ b/GEOLOC/lib/gps.h @@ -0,0 +1,53 @@ +#ifndef gps_h +#define gps_h + +/** + * Define NMEA frame types + */ +typedef enum NMEA_TYPE NMEA_TYPE; +enum NMEA_TYPE { GGA=125,NONE }; // TODO : other frame type + +/** + * Define compass N,S,E,W + */ +typedef enum COMPASS COMPASS; +enum COMPASS { NORTH=78, SOUTH=83, EAST=69, WEST=87}; + +/** + * Define GPS state + */ +typedef enum GPS_STATE GPS_STATE; +enum GPS_STATE { FIXED_GPS=1, FIXED_DGPS=2, UNFIXED=0}; + +/** + * Define NMEA GGA FRAME + */ +struct NMEA_GGA { + short hour; + short min; + short sec; + short ms; + + short latDeg; + short latMin; + float latSec; + COMPASS latDir; + + short lonDeg; + short lonMin; + float lonSec; + COMPASS lonDir; + + short sats; + GPS_STATE state; + + // TODO : Finish Frame + +}; + +/** + * Fetch the last NMEA_GGA frame + */ +struct NMEA_GGA getNMEA_GGAFrame(); + +#endif diff --git a/GEOLOC/lib/types.h b/GEOLOC/lib/types.h new file mode 100644 index 0000000..01c0e97 --- /dev/null +++ b/GEOLOC/lib/types.h @@ -0,0 +1,10 @@ +#ifndef type_h +#define type_h + +#define FXOSC 32000000 // SX1276 clock frequency (SX1276 datasheet page 14) +#define FSTEP 61 // Default FSTEP (SX1276 datasheet page 15) + +// Define byte size for convenience +typedef unsigned char byte; + +#endif diff --git a/GEOLOC/main.c b/GEOLOC/main.c new file mode 100644 index 0000000..07ef640 --- /dev/null +++ b/GEOLOC/main.c @@ -0,0 +1,51 @@ +#include "lib/dragino.h" +#include "lib/config.h" +#include "app/frame.h" +#if TARGET == ANCHOR + #include "app/anchor/app.h" +#else + #include "app/mobile/app.h" +#endif +#include +#include "lib/gps.h" + + +// NMEA_GGA Frame +struct NMEA_GGA NmeaGgaFrame; + +int main(){ + + // Init dragino pins + initPins(); + + // Init sx1276 + reset(); + + // Init configuration + Config config; + config.mod=MOD_FSK; // Choose modulation + config.mode=MODE_SLEEP; // Standby mode at startup + config.cFreq=868100000; // Choose carrier frequency + config.fsk.preambleSize=1; // Choose preamble size + config.fsk.crcOn=CRC_OFF; // ON/OFF CRC check + config.fsk.freqDev=5002; // Choose frequency deviation + config.fsk.preambleDetection=PREAMBLE_DETECTION_ON; // ON/OFF preamble detection + config.lnaGain=LNA_GAIN_G1; // Choose LNA GAIN + config.fsk.crcAutoClearOff=CRC_AUTOCLEAR_OFF_OFF; // ON/OFF CRC autoclean + config.fsk.bitrate=4800; // Choose bitrate + config.fsk.fixedPayloadLength=FIXED_PAYLOAD_LENGTH_OFF; // ON/OFF Fixed payload length + config.fsk.payloadLength=FRAME_SIZE; // Choose payload length + config.fsk.fifoThreshold=FRAME_SIZE-1; // Choose fifo threshold + config.paSelect=PA_SELECT_ON; // Toggle PA BOOST + config.maxPower=15; // Define max power + config.outputPower=17; // Set the output power + config.fsk.rssiSmoothing=RSSI_SAMPLE_256; // Set rssi sample + + // Fetch GPS position + NmeaGgaFrame=getNMEA_GGAFrame(); + + // Run ANCHOR or MOBILE application according to Makefile TARGET definition + runApp(config); + + return(0); +} diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..8a25afa --- /dev/null +++ b/Readme.md @@ -0,0 +1,6 @@ +Folders structure +================== + +#### GEOLOC + +It contains source code for turtle and gateways and a Readme for details.