|
|
General things
|
|
|
--------------
|
|
|
|
|
|
#### 1) Copyrigth
|
|
|
|
|
|
You will find different Licence policies along the code: while Miosix's code was released unde the GPL license, Boardcore's lincensing is still under discussion.
|
|
|
|
|
|
Anyways, you should indeed put a copyright statement as a first thing in every file.
|
|
|
|
|
|
#### 2) Includes
|
|
|
*Pro Tip*: In src/shared/Common.h you will find many frequently used headers. Check them!
|
|
|
|
|
|
#### 3)Using namespace
|
|
|
*WARNING*: Putting namespaces in header files is bad practice and can cause trouble.
|
|
|
To know more see <https://stackoverflow.com/questions/4872373/why-is-including-using-namespace-into-a-header-file-a-bad-idea-in-c>
|
|
|
|
|
|
#### 4)Defines
|
|
|
*WARNING*: DON'T abuse defines: they're difficult to read (and can create side effects).
|
|
|
|
|
|
Example of what you **DON'T** want to do (real life example):
|
|
|
```cpp
|
|
|
#define SENSOR(NAME, CSPORT, CSPIN) \
|
|
|
typedef Gpio<GPIO##CSPORT##_BASE, CSPIN> CS_##NAME; \
|
|
|
typedef ProtocolSPI<busSPI1, CS_##NAME> spi##NAME
|
|
|
```
|
|
|
|
|
|
#### 5)Typedefs
|
|
|
|
|
|
```cpp
|
|
|
typedef Gpio<GPIOA_BASE, 5> SomePin; //On a Discovery board, this would rapresent the PA5 pin
|
|
|
```
|
|
|
|
|
|
*Pro Tip*: you can move gpio typedefs, constants defines and other configuration stuff
|
|
|
in an external config.h file (in the same directory) and then `#include` it.
|
|
|
This will help other people change configuration without having to touch your code.
|
|
|
|
|
|
#### 6)Global Variables
|
|
|
#### 7)Functions prototypes
|
|
|
|
|
|
|
|
|
Drivers
|
|
|
-------------------
|
|
|
|
|
|
*TODO FILE NAMING CONVENTIONS*
|
|
|
|
|
|
--------------------------------
|
|
|
### Headers
|
|
|
|
|
|
This example is taken from the piksi class that you can find in src/shared/drivers/piksi.
|
|
|
|
|
|
```cpp
|
|
|
/* Copyright (c) 2017 Skyward Experimental Rocketry
|
|
|
* Authors: Federico Terraneo
|
|
|
*
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
|
* in the Software without restriction, including without limitation the rights
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
|
* furnished to do so, subject to the following conditions:
|
|
|
*
|
|
|
* The above copyright notice and this permission notice shall be included in
|
|
|
* all copies or substantial portions of the Software.
|
|
|
*
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
* THE SOFTWARE.
|
|
|
*/
|
|
|
|
|
|
#ifndef PIKSI_H
|
|
|
#define PIKSI_H
|
|
|
|
|
|
#include <pthread.h>
|
|
|
#include "contiguous_queue.h"
|
|
|
|
|
|
/**
|
|
|
* The GPS information
|
|
|
*/
|
|
|
struct GPSData
|
|
|
{
|
|
|
// timestamp in ms (anakin time, not GPS time). getTick()-timestamp tells
|
|
|
// you how "old" the data is.
|
|
|
long long timestamp;
|
|
|
|
|
|
double latitude; ///< [deg]
|
|
|
double longitude; ///< [deg]
|
|
|
double height; ///< [m]
|
|
|
float velocityNorth; ///< [m/s]
|
|
|
float velocityEast; ///< [m/s]
|
|
|
float velocityDown; ///< [m/s]
|
|
|
int numSatellites; ///< [1]
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Class to access the Piksi GPS.
|
|
|
*
|
|
|
* Should be connected to the Piksi UARTB configured as
|
|
|
* MODE SBP
|
|
|
* SBP message mask 65280
|
|
|
* telemetry radio on boot False
|
|
|
* baudrate 115200
|
|
|
*/
|
|
|
class Piksi
|
|
|
{
|
|
|
public:
|
|
|
/**
|
|
|
* Constructor
|
|
|
* \param serialPath path to the device file of the Piksi serial port
|
|
|
* \throws runtime_error if the serial port cannot be opened
|
|
|
*/
|
|
|
Piksi(const char *serialPath);
|
|
|
|
|
|
/**
|
|
|
* \return the latest GPS data, or throws if the GPS has not yet got a fix.
|
|
|
* If the GPS has lost the fix, the same data is returened repeatedly,
|
|
|
* use the timestamp field of the GPSData struct to know this.
|
|
|
* \throws runtime_error is no data is available
|
|
|
*/
|
|
|
GPSData getGpsData();
|
|
|
|
|
|
/**
|
|
|
* \return the latest GPS data. If the GPS has yet got a fix or has lost
|
|
|
* the fix, this function will block until the fix is regained
|
|
|
*/
|
|
|
GPSData waitForGpsData();
|
|
|
|
|
|
/**
|
|
|
* Destructor
|
|
|
*/
|
|
|
~Piksi();
|
|
|
|
|
|
private:
|
|
|
Piksi(const Piksi &) = delete;
|
|
|
Piksi &operator=(const Piksi &) = delete;
|
|
|
|
|
|
// The queue should be large enough to contain the largest message (256+8)
|
|
|
ContiguousQueue<uint8_t, 384> bytes;
|
|
|
int fd;
|
|
|
pthread_t thread;
|
|
|
pthread_mutex_t mutex;
|
|
|
pthread_cond_t cond;
|
|
|
GPSData data, partialData;
|
|
|
uint32_t gpsTimestamp = 0;
|
|
|
bool pos = false;
|
|
|
bool vel = false;
|
|
|
bool firstFixReceived = false;
|
|
|
volatile bool quit = false;
|
|
|
|
|
|
/**
|
|
|
* Launches run() from the background thread
|
|
|
* \param arg this
|
|
|
*/
|
|
|
static void *threadLauncher(void *arg);
|
|
|
|
|
|
/**
|
|
|
* Piksi main processing loop
|
|
|
*/
|
|
|
void run();
|
|
|
|
|
|
/**
|
|
|
* Fill a buffer from the serial port where the piksi is connected
|
|
|
* \param buffer where to store read data
|
|
|
* \param size how many bytes to read
|
|
|
*/
|
|
|
unsigned int readData(unsigned char *buffer, unsigned int size);
|
|
|
|
|
|
};
|
|
|
|
|
|
#endif // PIKSI_H
|
|
|
|
|
|
```
|
|
|
|
|
|
-----------------------------------------
|
|
|
### Classes
|
|
|
|
|
|
```cpp
|
|
|
/* Copyright (c) 2017 Skyward Experimental Rocketry
|
|
|
* Authors: Federico Terraneo
|
|
|
* .... See above
|
|
|
*/
|
|
|
|
|
|
#include "piksi.h"
|
|
|
#include <fcntl.h>
|
|
|
#include <sys/stat.h>
|
|
|
#include <sys/types.h>
|
|
|
#include <termios.h>
|
|
|
#include <time.h>
|
|
|
#include <unistd.h>
|
|
|
#include <algorithm>
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
#ifdef _MIOSIX
|
|
|
|
|
|
#include <miosix.h>
|
|
|
|
|
|
using namespace miosix;
|
|
|
|
|
|
#endif //_MIOSIX
|
|
|
|
|
|
//
|
|
|
// class Piksi
|
|
|
//
|
|
|
|
|
|
Piksi::Piksi(const char *serialPath)
|
|
|
{
|
|
|
fd = open(serialPath, O_RDWR);
|
|
|
if (fd < 0)
|
|
|
throw runtime_error(string("Cannot open ") + serialPath);
|
|
|
if (isatty(fd))
|
|
|
{
|
|
|
termios t;
|
|
|
tcgetattr(fd, &t);
|
|
|
t.c_lflag &= ~(ISIG | ICANON | ECHO);
|
|
|
#ifndef _MIOSIX
|
|
|
cfsetospeed(&t, B115200);
|
|
|
cfsetispeed(&t, B115200);
|
|
|
#endif //_MIOSIX
|
|
|
tcsetattr(fd, TCSANOW, &t);
|
|
|
}
|
|
|
pthread_create(&thread, NULL, &threadLauncher, this);
|
|
|
pthread_mutex_init(&mutex, NULL);
|
|
|
pthread_cond_init(&cond, NULL);
|
|
|
}
|
|
|
|
|
|
GPSData Piksi::getGpsData()
|
|
|
{
|
|
|
GPSData result;
|
|
|
pthread_mutex_lock(&mutex);
|
|
|
if (!firstFixReceived)
|
|
|
{
|
|
|
pthread_mutex_unlock(&mutex);
|
|
|
throw runtime_error("No fix");
|
|
|
}
|
|
|
result = data;
|
|
|
pthread_mutex_unlock(&mutex);
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
GPSData Piksi::waitForGpsData()
|
|
|
{
|
|
|
GPSData result;
|
|
|
pthread_mutex_lock(&mutex);
|
|
|
pthread_cond_wait(&cond, &mutex);
|
|
|
result = data;
|
|
|
pthread_mutex_unlock(&mutex);
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
Piksi::~Piksi()
|
|
|
{
|
|
|
quit = true;
|
|
|
pthread_join(thread, NULL);
|
|
|
pthread_mutex_destroy(&mutex);
|
|
|
pthread_cond_destroy(&cond);
|
|
|
close(fd);
|
|
|
}
|
|
|
|
|
|
void *Piksi::threadLauncher(void *arg)
|
|
|
{
|
|
|
reinterpret_cast<Piksi *>(arg)->run();
|
|
|
return nullptr;
|
|
|
}
|
|
|
|
|
|
void Piksi::run()
|
|
|
{
|
|
|
do
|
|
|
{
|
|
|
bytes.added(readData(bytes.addEnd(), bytes.availableToAdd()));
|
|
|
bytes.removed(
|
|
|
lookForMessages(bytes.removeEnd(), bytes.availableToRemove()));
|
|
|
} while (quit == false);
|
|
|
}
|
|
|
|
|
|
unsigned int Piksi::readData(unsigned char *buffer, unsigned int size)
|
|
|
{
|
|
|
int result = read(fd, buffer, size);
|
|
|
if (result > 0)
|
|
|
return result;
|
|
|
usleep(10000); // We want to retry but avoid 100% CPU utilization
|
|
|
return 0; // To go to a loop of run() and notice the quit flag
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
---------------------------------------------
|
|
|
### Entrypoints (Boards and Tests)
|
|
|
|
|
|
```Cpp
|
|
|
/* Copyright (c) 2015-2016 Skyward Experimental Rocketry
|
|
|
* Authors: ...
|
|
|
*.... See above
|
|
|
*/
|
|
|
|
|
|
#include <Common.h>
|
|
|
#include "Miosix.h"
|
|
|
//...
|
|
|
|
|
|
using namespace std;
|
|
|
using namespace miosix;
|
|
|
|
|
|
#define DEBUG
|
|
|
|
|
|
typedef Gpio<GPIOA_BASE, 5> SomePin; //On a Discovery board, this would rapresent the PA5 pin
|
|
|
|
|
|
int _globalInt;
|
|
|
|
|
|
void useLongNames(int explicitArg);
|
|
|
|
|
|
/*
|
|
|
Put a comment here that explains well how to setup/use the file.
|
|
|
*/
|
|
|
int main()
|
|
|
{
|
|
|
//Local variables declaration (all at the start of the function)
|
|
|
int localInt;
|
|
|
|
|
|
//DO STUFF
|
|
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
Put a comment before every function, telling what args they want and what they do.
|
|
|
\arg explicitArg explain what is expected
|
|
|
\return explain what it returns
|
|
|
*/
|
|
|
void useLongNames(int explicitArg)
|
|
|
{
|
|
|
//BODY of function
|
|
|
}
|
|
|
``` |