Skip to content

Commit

Permalink
Dev dev fsm (#1)
Browse files Browse the repository at this point in the history
* Added fsm telemetry app connecting via socket
* Cleaned up logging across all fsm header files. Added ADC & DAC query commands.
* Added INDI params to send DACs. Fixed state progression.
* Adding voltage to dac & angles to actuator displacement conversion. Diagrams for the INDI commands.
* Added shmim commands. Made block diagrams for the INDI & shmim logic.
* Documentation
* Added toggle between indi & shmim
* Added ADC 'current' params that show the ADC values queried on connection and after a DAC value update.
* Added status.query INDI param to query 'adc' or 'dac' values.
* WIP test writing
  • Loading branch information
stefi07 authored Aug 6, 2024
1 parent 625176e commit 1960e66
Show file tree
Hide file tree
Showing 25 changed files with 6,537 additions and 43 deletions.
44 changes: 44 additions & 0 deletions apps/fsmCtrl/IUart.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#pragma once

#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>

class IUart
{
public:
IUart() { }
virtual ~IUart() { }

static const bool OddParity = true;
static const bool NoParity = false;
static const bool IUartOK = 0x00;
static const bool UseRTSCTS = true;
static const bool NoRTSCTS = false;


//All the following pinout functions are very hardware & device dependant, so they are declared in another class to preserve the abstraction
//virtual int init() { return(InitOK); } //note: this functiuon usually gets overloaded with different params, so it's no longer virtual anyway - probably not an issue, since it usually gets called from code with the full object, not just the base class.
//~ virtual bool dataready() { printf("\nIUart::dataready() stub!\n"); return(false); }
//~ virtual char getcqq() { printf("\nIUart::getcqq() stub!\n"); return('\0'); }
//~ virtual char putcqq(char c) { printf("\nIUart::putcqq() stub!\n"); return('\0'); }
//~ virtual void flushoutput() { printf("\nIUart::flushoutput() stub!\n"); }
//~ virtual void purgeinput() { printf("\nIUart::purgeinput() stub!\n"); }
//~ virtual bool isopen() { printf("\nIUart::isopen() stub!\n"); return(false); }
virtual bool dataready() const = 0;
virtual char getcqq() = 0;
virtual char putcqq(char c) = 0;
virtual void flushoutput() = 0;
virtual void purgeinput() = 0;
virtual bool isopen() const = 0;

void puts(const char* s, const size_t len)
{
for (size_t i = 0; i < len; i++)
{
if ('\0' == s[i]) { break; }

putcqq(s[i]);
}
}
};
10 changes: 10 additions & 0 deletions apps/fsmCtrl/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

allall: all

debug_opt: all
debug_opt: CXXFLAGS += -g

OTHER_HEADERS=
TARGET=fsmCtrl
include ../../Make/magAOXApp.mk

317 changes: 317 additions & 0 deletions apps/fsmCtrl/binaryUart.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,317 @@
//
/// Copyright (c)2007 by Franks Development, LLC
//
// This software is copyrighted by and is the sole property of Franks
// Development, LLC. All rights, title, ownership, or other interests
// in the software remain the property of Franks Development, LLC. This
// software may only be used in accordance with the corresponding
// license agreement. Any unauthorized use, duplication, transmission,
// distribution, or disclosure of this software is expressly forbidden.
//
// This Copyright notice may not be removed or modified without prior
// written consent of Franks Development, LLC.
//
// Franks Development, LLC. reserves the right to modify this software
// without notice.
//
// Franks Development, LLC [email protected]
// 500 N. Bahamas Dr. #101 http://www.franks-development.com
// Tucson, AZ 85710
// USA
//

#pragma once

#include <stdio.h>
#include <stdarg.h>
#include <stdint.h>

#include <sstream> // for stringstreams

#include "IUart.h"

#include "iPacket.hpp"

#include "cGraphPacket.hpp"
#include "fsmCommands.hpp"

namespace MagAOX
{
namespace app
{

struct BinaryUartCallbacks
{
BinaryUartCallbacks() { }
virtual ~BinaryUartCallbacks() { }

//Malformed/corrupted packet handler:
virtual void InvalidPacket(const uint8_t* Buffer, const size_t& BufferLen) { }

//Packet with no matching command handler:
virtual void UnHandledPacket(const IPacket* Packet, const size_t& PacketLen) { }

//In case we need to look at every packet that goes by...
virtual void EveryPacket(const IPacket* Packet, const size_t& PacketLen) { }

//Seems like someone, sometime might wanna handle this...
virtual void BufferOverflow(const size_t& BufferLen) { }
};


struct BinaryUart
{
//Default values
static const uint64_t RxCountInit = 0;
static const uint64_t PacketStartInit = 0;
static const uint64_t PacketLenInit = 0;
static const bool InPacketInit = false;
static const bool debugDefault = false;
static const char EmptyBufferChar = '\0';

static const size_t RxBufferLenBytes = 4096;
static const size_t TxBufferLenBytes = 4096;
uint8_t RxBuffer[RxBufferLenBytes]; //This is where the received characters go while we are building a line up from the input
uint16_t RxCount;
IUart& Pinout;
IPacket& Packet;
BinaryUartCallbacks& Callbacks;
bool debug;
bool InPacket;
size_t PacketStart;
size_t PacketLen;
size_t packetEnd = 0;
//~ const void* Argument;
uint64_t SerialNum;
static const uint64_t InvalidSerialNumber = 0xFFFFFFFFFFFFFFFFULL;

BinaryUart(struct IUart& pinout, struct IPacket& packet, struct BinaryUartCallbacks& callbacks, const uint64_t serialnum = InvalidSerialNumber)
:
RxCount(RxCountInit),
Pinout(pinout),
Packet(packet),
Callbacks(callbacks),
debug(debugDefault),
//~ debug(true),
InPacket(InPacketInit),
PacketStart(PacketStartInit),
PacketLen(PacketLenInit),
SerialNum(serialnum)

{
Init(serialnum);
}

void Debug(bool dbg)
{
debug = dbg;
}

const uint8_t* GetRxBuffer() const
{
return RxBuffer;
}

int Init(uint64_t serialnum)
{
SerialNum = serialnum;
RxCount = RxCountInit;
PacketStart = PacketStartInit;
PacketLen = PacketLenInit;
InPacket = InPacketInit;
memset(RxBuffer, EmptyBufferChar, RxBufferLenBytes);

std::ostringstream oss;
oss << "Binary Uart: Init(PktH " << Packet.HeaderLen() << ", PktF " << Packet.FooterLen() << ").";
MagAOXAppT::log<text_log>(oss.str());

return(0);
}

bool Process(MagAOX::app::PZTQuery* pztQuery)
{
//New char?
if ( !(Pinout.dataready()) ) { return(false); }

//pull it off the hardware
uint8_t c = Pinout.getcqq();

ProcessByte(c);
CheckPacketStart();
CheckPacketEnd(pztQuery);

return(true); //We just want to know if there's chars in the buffer to put threads to sleep or not...
}

void ProcessByte(const char c)
{
//Put the current character into the buffer
if (RxCount < RxBufferLenBytes)
{
RxCount++;
RxBuffer[RxCount - 1] = c;
}
else
{
if (debug)
{
std::ostringstream oss;
oss << "BinaryUart: Buffer(" << RxBuffer <<") overflow; this packet will not fit (" << RxCount << "b), flushing buffer.";
MagAOXAppT::log<software_debug>({__FILE__, __LINE__, oss.str()});
}

Callbacks.BufferOverflow(RxCount);

Init(SerialNum);
}
}

void CheckPacketStart()
{
//Packet Start?
if ( (!InPacket) && (RxCount >= Packet.HeaderLen()) )
{
if (Packet.FindPacketStart(RxBuffer, RxCount, PacketStart)) //This is wasteful, we really only need to look at the 4 newest bytes every time...
{
if (debug) { MagAOXAppT::log<software_debug>({__FILE__, __LINE__, "BinaryUart: Packet start detected! Buffering."}); }

InPacket = true;
}
}
}

bool CheckPacketEnd(MagAOX::app::PZTQuery* pztQuery)
{
packetEnd = 0;
bool Processed = false;

if (!InPacket || RxCount < (Packet.HeaderLen() + Packet.FooterLen()))
return false;

//This is wasteful, we really only need to look at the 4 newest bytes every time...
if (!Packet.FindPacketEnd(RxBuffer, RxCount, packetEnd)) {
if (debug) {
MagAOXAppT::log<software_debug>({__FILE__, __LINE__, "BinaryUart: Still waiting for packet end..."});
}
return false;
}

if (debug) {
MagAOXAppT::log<software_debug>({__FILE__, __LINE__, "BinaryUart: Packet end detected; Looking for matching packet handlers."});
}

const size_t payloadLen = Packet.PayloadLen(RxBuffer, RxCount, PacketStart);

if (RxCount < payloadLen + Packet.HeaderLen() + Packet.FooterLen())
{
if ( (payloadLen > RxBufferLenBytes) || (payloadLen > Packet.MaxPayloadLength()) )
{
if (debug)
{
std::ostringstream oss;
oss << "BinaryUart: Short packet (" << RxCount << " bytes) with unrealistic payload len; ignoring corrupted packet (should have been header() + payload(" << payloadLen << ") + footer().";
MagAOXAppT::log<software_debug>({__FILE__, __LINE__, oss.str()});
}

Callbacks.InvalidPacket(reinterpret_cast<uint8_t*>(RxBuffer), RxCount);

Init(SerialNum);

return false;
}
else
{
if (debug)
{
std::ostringstream oss;
oss << "BinaryUart: Short packet (" << RxCount << " bytes); we'll assume the packet footer was part of the payload data and keep searching for the packet end (should have been header() + payload(" << payloadLen << ") + footer().";
MagAOXAppT::log<software_debug>({__FILE__, __LINE__, oss.str()});
}

return false;
}
}

if (Packet.IsValid(RxBuffer, RxCount, PacketStart))
{
if ( (SerialNum == InvalidSerialNumber) || (SerialNum == Packet.SerialNum() ) )
{

//strip the part of the line with the arguments to this command (chars following command) for compatibility with the parsing code, the "params" officially start with the s/n
const char* Params = reinterpret_cast<char*>(&(RxBuffer[PacketStart + Packet.PayloadOffset()]));

//call the actual command
pztQuery->processReply(Params, payloadLen);

Processed = true;
}
else
{
if (debug)
{
std::ostringstream oss;
oss << "BinaryUart: Packet received, but SerialNumber comparison failed (expected: 0x" << SerialNum << "; got: 0x" << Packet.SerialNum() << ").";
MagAOXAppT::log<software_debug>({__FILE__, __LINE__, oss.str()});
}

Callbacks.UnHandledPacket(reinterpret_cast<IPacket*>(&RxBuffer[PacketStart]), packetEnd - PacketStart);
}

//Now just let the user do whatever they want with it...
Callbacks.EveryPacket(reinterpret_cast<IPacket*>(&RxBuffer[PacketStart]), packetEnd - PacketStart);
}
else
{
if (debug) { MagAOXAppT::log<software_debug>({__FILE__, __LINE__, "BinaryUart: Packet received, but invalid."}); }

Callbacks.InvalidPacket(reinterpret_cast<uint8_t*>(RxBuffer), RxCount);
}

InPacket = false;

if (RxCount > (packetEnd + 4) )
{
size_t pos = 0;
size_t clr = 0;
for (; pos < (RxCount - (packetEnd + 4)); pos++)
{
RxBuffer[pos] = RxBuffer[(packetEnd + 4) + pos];
}
for (clr = pos; clr < RxCount; clr++)
{
RxBuffer[clr] = 0;
}
RxCount = pos;
}
else
{
Init(SerialNum);
}

return Processed;
}

void TxBinaryPacket(const uint16_t PayloadType, const void* PayloadData, const size_t PayloadLen) const
{
uint8_t TxBuffer[TxBufferLenBytes];
size_t PacketLen = Packet.MakePacket(TxBuffer, TxBufferLenBytes, PayloadData, PayloadType, PayloadLen);

std::ostringstream oss;
oss << "Packet length: " << PacketLen;
MagAOXAppT::log<text_log>(oss.str());

for (size_t i = 0; i < PacketLen; i++) { Pinout.putcqq(TxBuffer[i]); }

// Log packet sent
oss.str("");
oss << "Binary Uart: Sending packet(" << PayloadType << ", " << PayloadLen << "): ";
MagAOXAppT::log<text_log>(oss.str());
oss.str("");
for(size_t i = 0; i < PacketLen; i++) { oss << std::setw(2) << std::setfill('0') << std::hex << static_cast<unsigned>(TxBuffer[i]) << ":"; }
MagAOXAppT::log<text_log>(oss.str());

}
};

} //namespace app
} //namespace MagAOX
Loading

0 comments on commit 1960e66

Please sign in to comment.