- Implement new ApplicationCore:
- Manage Tools: Log, DataTree, JSONparser & Selector
- Load configuration, Manage FunctionBlocks
- FunctionCore & dirived classes, SignalCore:
- affects: SelectableCore, DeviceCore, FileCore, WatchdogCore
- Do not pass Log()
- Define and pass Type
- Update/reduce included headers
- Use ProcessName and Application global vars
- Get Log, DataTree from Application
- Use virtual Init() function to set must have Channels/Handles
- DataTreeCore:
- Bug fix: Check if child members exist and destroy in SetValuePtr()
- Add method GetFirstChild with BaseMember & Path
- Bug fix: do not use RootMember if no Parent in GetChildxxx() methods
- SignalCore, SelectCore:
- Use Application->Log()
- FunctionCore:
- Add itself to Application (function list)
- Add parameter: LinkConfigMember, Type
- Use virtual LoadConfigData() to configure from DataTree
- Rename methods: LoadConfig() -> InitConfig(),
InitLogging() -> SetLogParam(), SetDebugLevel() -> SetLogLevel()
- Add method: GetType(), LoadChannelLinkData(), InitChannelLinks()
- Modify LinkIn/OutputChannel() to use name for InFunction, not pointer
- SelectableCore & Dirived classes:
- Affects DeviceCore & WatchdogClient
- Rename parameter: Select -> Selector, BaseMember -> ConfigMember
- Get Selector from Application->Selector
- Change Handles JSON structure from Array to Key:Value pairs
- Bug fix: check if Selector exist during Input()
- Bug fix: do not set PortNo if not exist
306 lines
7.7 KiB
C++
306 lines
7.7 KiB
C++
/*
|
|
* FileCore.cpp
|
|
*
|
|
* Created on: 1 Jun 2016
|
|
* Author: wentzelc
|
|
*/
|
|
|
|
// redA Libraries
|
|
#include "ApplicationCore.h"
|
|
#include "FileCore.h"
|
|
|
|
// Standard C/C++ Libraries
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
// Global Vars
|
|
//extern char * ProcessName;
|
|
//extern CApplication * Application;
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
CFileCore::CFileCore( const char * pName, const char * pType ) :
|
|
CFunctionCore( pName, pType )
|
|
{
|
|
FirstFile = NULL;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
CFileCore::~CFileCore()
|
|
{
|
|
TFileHandle * NextFile = NULL;
|
|
|
|
// Destroy file specs
|
|
while (FirstFile)
|
|
{
|
|
// Close file if open
|
|
CloseFile( FirstFile );
|
|
|
|
// Destroy file parameters
|
|
if (FirstFile->Name)
|
|
free( FirstFile->Name );
|
|
if (FirstFile->Path)
|
|
free( FirstFile->Path );
|
|
|
|
// Destroy File
|
|
NextFile = FirstFile->Next;
|
|
delete FirstFile;
|
|
FirstFile = NextFile;
|
|
}
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
TFileHandle * CFileCore::AddFile( const char * Name, const char * Path, bool Append, bool CreateChannel )
|
|
{
|
|
TFileHandle ** FileHandle = NULL;
|
|
|
|
// Validate
|
|
if (!Name || !*Name || !Path || !*Path) {
|
|
return NULL;
|
|
}
|
|
|
|
// Find File or End of list
|
|
FileHandle = &FirstFile;
|
|
while (*FileHandle && strcmp( Name, (*FileHandle)->Name )) {
|
|
FileHandle = &((*FileHandle)->Next);
|
|
}
|
|
|
|
// Check if found
|
|
if (!*FileHandle)
|
|
{
|
|
// Create new
|
|
*FileHandle = (TFileHandle*)calloc( 1, sizeof(TFileHandle) );
|
|
|
|
// Set name & Path
|
|
(*FileHandle)->Name = (char*)malloc( strlen(Name)+1 );
|
|
strcpy( (*FileHandle)->Name, Name );
|
|
(*FileHandle)->Path = (char*)malloc( strlen(Path)+1 );
|
|
strcpy( (*FileHandle)->Path, Path );
|
|
}
|
|
|
|
// Create Channel if necessary
|
|
if (CreateChannel) {
|
|
AddChannel( Name );
|
|
}
|
|
|
|
// Set Parameters
|
|
(*FileHandle)->Append = Append;
|
|
(*FileHandle)->FD = NO_FD;
|
|
|
|
// Return File
|
|
return (*FileHandle);
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CFileCore::SetFilePersistence( TFileHandle * FileHandle, bool Persistent, int PersistTimeout )
|
|
{
|
|
// Validate
|
|
if (!FileHandle) {
|
|
return false;
|
|
}
|
|
|
|
// Set parameters
|
|
FileHandle->Persistent = Persistent;
|
|
FileHandle->PersistTimeout = PersistTimeout;
|
|
|
|
// Open persistent file
|
|
if (Persistent && (!PersistTimeout)) {
|
|
OpenFile( FileHandle );
|
|
SetStartTime( &(FileHandle->PersistTime) );
|
|
}
|
|
// Close non-persistent file
|
|
else if (!Persistent && isOpen(FileHandle)) {
|
|
CloseFile( FileHandle );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CFileCore::OpenFile( TFileHandle * FileHandle )
|
|
{
|
|
// Validate
|
|
if (!FileHandle) {
|
|
return false;
|
|
}
|
|
|
|
// Open file if not already open
|
|
if (!isOpen( FileHandle ))
|
|
{
|
|
// GEt file handle
|
|
(FileHandle)->FD = open( FileHandle->Path, O_WRONLY | O_CREAT | ((FileHandle->Append)? O_APPEND : O_TRUNC), 0664 );
|
|
|
|
// Report event
|
|
if (isOpen(FileHandle))
|
|
{
|
|
// Set timer
|
|
SetStartTime( &(FileHandle->PersistTime) );
|
|
|
|
// Report result
|
|
if (Log) Log->Message( LogLevel, dlHigh, "%s: File '%s' - Opened", Name, FileHandle->Name );
|
|
}
|
|
}
|
|
|
|
// Check if failed
|
|
if (!isOpen(FileHandle))
|
|
{
|
|
// Report result
|
|
if (Log) Log->Message( LogLevel, dlHigh, "%s: File '%s' - Could not open (%d) %s", Name, FileHandle->Name, errno, strerror(errno) );
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CFileCore::CloseFile( TFileHandle * FileHandle )
|
|
{
|
|
// Validate
|
|
if (!FileHandle) {
|
|
return false;
|
|
}
|
|
|
|
// Close file if not already open
|
|
if (isOpen(FileHandle))
|
|
{
|
|
// Close file
|
|
close( FileHandle->FD );
|
|
FileHandle->FD = NO_FD;
|
|
|
|
// Report result
|
|
if (!isOpen(FileHandle)) {
|
|
if (Log) Log->Message( LogLevel, dlHigh, "%s: File '%s' - Closed", Name, FileHandle->Name );
|
|
} else {
|
|
if (Log) Log->Message( LogLevel, dlHigh, "%s: File '%s' - Could not close", Name, FileHandle->Name );
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
int CFileCore::ReadFromFD( int FD, char * Data, int MaxLen )
|
|
{
|
|
int BytesRead = 0;
|
|
int TotalRead = 0;
|
|
int DataRemain = 0;
|
|
|
|
// Check if buffer created
|
|
if ((FD == -1) || !Data) {
|
|
return 0;
|
|
}
|
|
|
|
// Read Data into buffer
|
|
DataRemain = (MaxLen == -1)? strlen(Data) : MaxLen;
|
|
while (DataRemain)
|
|
{
|
|
// Read from file descriptor
|
|
BytesRead = read( FD, &Data[TotalRead], DataRemain );
|
|
if (BytesRead <= 0)
|
|
break;
|
|
|
|
// Update Data Pointers
|
|
TotalRead += BytesRead;
|
|
DataRemain -= BytesRead;
|
|
}
|
|
|
|
return TotalRead;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
int CFileCore::WriteToFD( int FD, const char * Data, int Len )
|
|
{
|
|
int BytesWritten = 0;
|
|
int TotalWritten = 0;
|
|
int DataRemain = 0;
|
|
|
|
// Check if buffer created
|
|
if ((FD == -1) || !Data) {
|
|
return 0;
|
|
}
|
|
|
|
// Read Data into buffer
|
|
DataRemain = (Len == -1)? strlen(Data) : Len;
|
|
while (DataRemain)
|
|
{
|
|
// Read from file descriptor
|
|
BytesWritten = write( FD, &Data[TotalWritten], DataRemain );
|
|
if ((BytesWritten <= 0) && (errno != EAGAIN))
|
|
break;
|
|
|
|
// Update Data Pointers
|
|
TotalWritten += BytesWritten;
|
|
DataRemain -= BytesWritten;
|
|
}
|
|
|
|
return TotalWritten;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
// Manual Data Input/Output
|
|
int CFileCore::Input( const char * ChannelName, const char * Data, int MaxLen )
|
|
{
|
|
TFileHandle * FileHandle = NULL;
|
|
int BytesWritten = 0;
|
|
|
|
// Validate
|
|
if (!ChannelName || !Data) {
|
|
return 0;
|
|
}
|
|
else if (MaxLen == -1) {
|
|
MaxLen = strlen( Data );
|
|
};
|
|
|
|
// Get Channel
|
|
if (!(FileHandle = GetFile( ChannelName )))
|
|
{
|
|
// Log event
|
|
if (Log) Log->Message( LogLevel, dlHigh, "%s: Channel '%s' - Input rejected, Channel not found", Name, ChannelName );
|
|
return 0;
|
|
}
|
|
|
|
// Log event
|
|
Log->Output( LogLevel, dlHigh, LogOutput, Data, MaxLen, "%s: Channel '%s' - IN:", Name, ChannelName );
|
|
|
|
// Open file
|
|
if (!OpenFile( FileHandle )) {
|
|
return 0;
|
|
}
|
|
|
|
// Handle Incoming data
|
|
BytesWritten = WriteToFD( FileHandle->FD, Data, MaxLen );
|
|
SetStartTime( &(FileHandle->PersistTime) );
|
|
|
|
// Return processed bytes
|
|
return BytesWritten;
|
|
}
|
|
//---------------------------------------------------------------------------
|
|
|
|
bool CFileCore::Process()
|
|
{
|
|
TFileHandle * FileHandle;
|
|
|
|
// Close Persistent files not used
|
|
FileHandle = FirstFile;
|
|
while (FileHandle)
|
|
{
|
|
if (isOpen(FileHandle) &&
|
|
(!FileHandle->Persistent ||
|
|
(FileHandle->PersistTimeout && Timeout( FileHandle->PersistTime, FileHandle->PersistTimeout )))) {
|
|
CloseFile( FileHandle );
|
|
}
|
|
|
|
// Next
|
|
FileHandle = FileHandle->Next;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
//---------------------------------------------------------------------------
|