Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for OpenLog micro-sd card reader #94

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions inc/drivers/OpenLog/openlog.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#pragma once

#include "STM32Pin.h"
#include "STM32Serial.h"

namespace codal {

/**
* @brief the class representing the OpenLog micro-sd card reader
*/
class OpenLog {
public:
/**
* @brief Constructor of the OpenLog class
*
* @param tx the pin used to transmit data via serial to the OpenLog
* @param rx the pin used to receive data via serial to the OpenLog
* @param reset the pin used to reset the OpenLog (via OpenLog's GRN pin)
*
* @note As serial is used to communicate with the OpenLog, serial-compatible pins must be provided
*/
OpenLog(STM32Pin& tx, STM32Pin& rx, STM32Pin& reset);
~OpenLog();

/**
* @brief Writes data to the micro-sd card, in a file which name's defined in the .cpp.
*
* @param data the text to write to the micro-sd card
* @param dataSize the size of the text to write
*
* @return Wether the write operation was successful or not
*
* @note As the OpenLog is implemented in order to allow offline sensor data logging,
* being able to set a file name has not been implemented (as not needed at the moment)
*/
bool write(const char* data, unsigned dataSize);

private:
STM32Serial* serial;
STM32Pin& resetPin;
uint8_t* buffer;

/**
* @brief an utility function to send the data via serial in fixed sized buffers
*
* @param data the data to send
* @param dataSize the size of the data to send
*
* @return an int representing the number of transmited bytes (should be equal to dataSize), or an error code
* (DEVICE_INVALID_PARAMETER or DEVICE_SERIAL_IN_USE)
*/
int sendData(const uint8_t* data, unsigned dataSize);

/**
* @brief Sets the command mode on the OpenLog, enabling file operations on the micro-sd card
* @note Can also be used to end some of the openlog commands (e.g the append command)
*/
void goToCommandMode();

/**
* @brief hard resets the OpenLog via `resetPin`
*
* @note this function is used to restart the OpenLog after this class' serial is initialized, in order to ensure
* later that the OpenLog is responding well to the send commands / text
*/
void reset();

/**
* @brief listens to the OpenLog's serial output until the character `waitchar`
*
* @param waitChar the char to wait for (must be `>` or `<`)
* @note this function is used to wait until the Openlog is ready to accept commands / text
* @see
* https://github.com/sparkfun/OpenLog/blob/master/firmware/Arduino_Examples/Example3_ReadFile/Example3_ReadFile.ino
*/
void waitUntilReady(const char waitChar);
};
} // namespace codal
89 changes: 89 additions & 0 deletions source/drivers/OpenLog/openlog.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#include "openlog.h"

#include <stdio.h>

using namespace codal;

constexpr const unsigned BUFFER_SIZE = 100;
constexpr const unsigned OPENLOG_BAUDRATE = 9600;
constexpr const char* APPEND = "append";
constexpr const char* FILE_NAME = "out.csv";
constexpr const uint8_t ESCAPE_SEQUENCE[] = {26, 26, 26};
constexpr const char READY_TO_RECEIVE_ANY = '<';
constexpr const char READY_TO_RECEIVE_COMMANDS = '>';

OpenLog::OpenLog(STM32Pin& tx, STM32Pin& rx, STM32Pin& reset) : resetPin(reset)
{
this->buffer = (uint8_t*)malloc(BUFFER_SIZE);
this->serial = new STM32Serial(tx, rx);
this->serial->init(OPENLOG_BAUDRATE);
this->reset();
this->waitUntilReady(READY_TO_RECEIVE_ANY);
this->goToCommandMode();
}

OpenLog::~OpenLog()
{
free(this->buffer);
}

bool OpenLog::write(const char* data, unsigned dataSize)
{
int sendResult;
const unsigned commandLength = strlen(APPEND) + 1 + strlen(FILE_NAME) + 1;
strcat(strcat(strcat(strcpy((char*)this->buffer, APPEND), " "), FILE_NAME), "\r");

sendResult = this->sendData(this->buffer, commandLength);
if (sendResult == DEVICE_INVALID_PARAMETER || sendResult == DEVICE_SERIAL_IN_USE) return false;

this->waitUntilReady(READY_TO_RECEIVE_ANY);
sendResult = this->sendData((uint8_t*)data, dataSize - 1); // -1 because we're not sending the trailing \0
if (sendResult == DEVICE_INVALID_PARAMETER || sendResult == DEVICE_SERIAL_IN_USE) return false;

this->goToCommandMode();

return true;
}

int OpenLog::sendData(const uint8_t* data, unsigned dataSize)
{
const unsigned maxSendSize = CODAL_SERIAL_DEFAULT_BUFFER_SIZE;
const unsigned sendNumbers = dataSize / maxSendSize + !(dataSize % maxSendSize == 0);
unsigned transmittedBytes = 0;
int sendResult;

for (unsigned i = 0; i < sendNumbers; ++i) {
unsigned currentSendSize = (i < dataSize / maxSendSize) ? maxSendSize : dataSize % maxSendSize;
buffer = (uint8_t*)memcpy(this->buffer, data + (i * maxSendSize), currentSendSize);
sendResult = this->serial->send(this->buffer, currentSendSize);

if (sendResult != DEVICE_INVALID_PARAMETER && sendResult != DEVICE_SERIAL_IN_USE)
transmittedBytes += sendResult;
else {
return sendResult;
}
}
return transmittedBytes;
}

void OpenLog::goToCommandMode()
{
this->sendData(ESCAPE_SEQUENCE, 3);
this->waitUntilReady(READY_TO_RECEIVE_COMMANDS);
}

void OpenLog::reset()
{
this->resetPin.setDigitalValue(0);
fiber_sleep(100);
this->resetPin.setDigitalValue(1);
}

void OpenLog::waitUntilReady(const char waitChar)
{
if (!(waitChar == '>' || waitChar == '<')) return;
do {
fiber_sleep(10);
this->serial->read(this->buffer, BUFFER_SIZE, ASYNC);
} while (strchr((char*)this->buffer, waitChar) == NULL);
}
Loading