151 lines
4.9 KiB
C++
151 lines
4.9 KiB
C++
//-----------------------------------------------------------------------------
|
|
// Copyright 2019 Thiago Alves
|
|
// This file is part of the OpenPLC Software Stack.
|
|
//
|
|
// OpenPLC is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// OpenPLC is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with OpenPLC. If not, see <http://www.gnu.org/licenses/>.
|
|
//------
|
|
//
|
|
// This file is responsible for the persistent storage on the OpenPLC
|
|
// Thiago Alves, Jun 2019
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <time.h>
|
|
#include <pthread.h>
|
|
|
|
#include "ladder.h"
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Main function for the thread. Should create a buffer for the persistent
|
|
// data, compare it with the actual data and write back to the persistent
|
|
// file if the data has changed
|
|
//-----------------------------------------------------------------------------
|
|
void startPstorage()
|
|
{
|
|
unsigned char log_msg[1000];
|
|
IEC_UINT persistentBuffer[BUFFER_SIZE];
|
|
|
|
//Read initial buffers into persistent struct
|
|
pthread_mutex_lock(&bufferLock); //lock mutex
|
|
for (int i = 0; i < BUFFER_SIZE; i++)
|
|
{
|
|
if (int_memory[i] != NULL) persistentBuffer[i] = *int_memory[i];
|
|
}
|
|
pthread_mutex_unlock(&bufferLock); //unlock mutex
|
|
|
|
//Perform the first write
|
|
if (access("persistent.file", F_OK) == -1)
|
|
{
|
|
sprintf(log_msg, "Creating Persistent Storage file\n");
|
|
log(log_msg);
|
|
}
|
|
|
|
FILE *ps = fopen("persistent.file", "w"); //if file already exists, it will be overwritten
|
|
if (ps == NULL)
|
|
{
|
|
sprintf(log_msg, "Persistent Storage: Error creating persistent memory file!\n");
|
|
log(log_msg);
|
|
return 0;
|
|
}
|
|
|
|
if (fwrite(persistentBuffer, sizeof(IEC_INT), BUFFER_SIZE, ps) < BUFFER_SIZE)
|
|
{
|
|
sprintf(log_msg, "Persistent Storage: Error writing to persistent memory file!\n");
|
|
log(log_msg);
|
|
return 0;
|
|
}
|
|
fclose(ps);
|
|
|
|
//Run the main thread
|
|
while (run_pstorage)
|
|
{
|
|
|
|
//Verify if persistent buffer is outdated
|
|
bool bufferOutdated = false;
|
|
pthread_mutex_lock(&bufferLock); //lock mutex
|
|
for (int i = 0; i < BUFFER_SIZE; i++)
|
|
{
|
|
if (int_memory[i] != NULL)
|
|
{
|
|
if (persistentBuffer[i] != *int_memory[i])
|
|
{
|
|
persistentBuffer[i] = *int_memory[i];
|
|
bufferOutdated = true;
|
|
}
|
|
}
|
|
}
|
|
pthread_mutex_unlock(&bufferLock); //unlock mutex
|
|
|
|
//If buffer is outdated, write the changes back to the file
|
|
if (bufferOutdated)
|
|
{
|
|
FILE *fd = fopen("persistent.file", "w"); //if file already exists, it will be overwritten
|
|
if (fd == NULL)
|
|
{
|
|
sprintf(log_msg, "Persistent Storage: Error creating persistent memory file!\n");
|
|
log(log_msg);
|
|
return 0;
|
|
}
|
|
|
|
if (fwrite(persistentBuffer, sizeof(IEC_INT), BUFFER_SIZE, fd) < BUFFER_SIZE)
|
|
{
|
|
sprintf(log_msg, "Persistent Storage: Error writing to persistent memory file!\n");
|
|
log(log_msg);
|
|
return 0;
|
|
}
|
|
fclose(fd);
|
|
}
|
|
|
|
sleepms(pstorage_polling*1000);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// This function reads the contents from persistent.file into OpenPLC internal
|
|
// buffers. Must be called when OpenPLC is initializing. If persistent storage
|
|
// is disabled, the persistent.file will not be found and the function will
|
|
// exit gracefully.
|
|
//-----------------------------------------------------------------------------
|
|
int readPersistentStorage()
|
|
{
|
|
unsigned char log_msg[1000];
|
|
FILE *fd = fopen("persistent.file", "r");
|
|
if (fd == NULL)
|
|
{
|
|
sprintf(log_msg, "Warning: Persistent Storage file not found\n");
|
|
log(log_msg);
|
|
return 0;
|
|
}
|
|
|
|
IEC_INT persistentBuffer[BUFFER_SIZE];
|
|
|
|
if (fread(persistentBuffer, sizeof(IEC_INT), BUFFER_SIZE, fd) < BUFFER_SIZE)
|
|
{
|
|
sprintf(log_msg, "Persistent Storage: Error while trying to read persistent.file!\n");
|
|
log(log_msg);
|
|
return 0;
|
|
}
|
|
fclose(fd);
|
|
|
|
sprintf(log_msg, "Persistent Storage: Reading persistent.file into local buffers\n");
|
|
log(log_msg);
|
|
|
|
pthread_mutex_lock(&bufferLock); //lock mutex
|
|
for (int i = 0; i < BUFFER_SIZE; i++)
|
|
{
|
|
if (int_memory[i] != NULL) *int_memory[i] = persistentBuffer[i];
|
|
}
|
|
pthread_mutex_unlock(&bufferLock); //unlock mutex
|
|
} |