OpenPLC_v3/utils/glue_generator_src/glue_generator.cpp

288 lines
7.6 KiB
C++
Executable File

#include <iostream>
#include <fstream>
#include <string>
#include <cstring>
#include <cstdlib>
using namespace std;
/// Write the header to the output stream. The header is common among all glueVars files.
/// @param glueVars The output stream to write to.
void generateHeader(ostream& glueVars)
{
glueVars << "\
//-----------------------------------------------------------------------------\r\n\
// Copyright 2015 Thiago Alves\r\n\
// This file is part of the OpenPLC Software Stack.\r\n\
//\r\n\
// OpenPLC is free software: you can redistribute it and/or modify\r\n\
// it under the terms of the GNU General Public License as published by\r\n\
// the Free Software Foundation, either version 3 of the License, or\r\n\
// (at your option) any later version.\r\n\
//\r\n\
// OpenPLC is distributed in the hope that it will be useful,\r\n\
// but WITHOUT ANY WARRANTY; without even the implied warranty of\r\n\
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r\n\
// GNU General Public License for more details.\r\n\
//\r\n\
// You should have received a copy of the GNU General Public License\r\n\
// along with OpenPLC. If not, see <http://www.gnu.org/licenses/>.\r\n\
//------\r\n\
//\r\n\
// This file is responsible for gluing the variables from the IEC program to\r\n\
// the OpenPLC memory pointers. It is automatically generated by the\r\n\
// glue_generator program. PLEASE DON'T EDIT THIS FILE!\r\n\
// Thiago Alves, May 2016\r\n\
//-----------------------------------------------------------------------------\r\n\
\r\n\
#include \"iec_std_lib.h\"\r\n\
\r\n\
TIME __CURRENT_TIME;\r\n\
extern unsigned long long common_ticktime__;\r\n\
\r\n\
//Internal buffers for I/O and memory. These buffers are defined in the\r\n\
//auto-generated glueVars.cpp file\r\n\
#define BUFFER_SIZE 1024\r\n\
\r\n\
//Booleans\r\n\
IEC_BOOL *bool_input[BUFFER_SIZE][8];\r\n\
IEC_BOOL *bool_output[BUFFER_SIZE][8];\r\n\
\r\n\
//Bytes\r\n\
IEC_BYTE *byte_input[BUFFER_SIZE];\r\n\
IEC_BYTE *byte_output[BUFFER_SIZE];\r\n\
\r\n\
//Analog I/O\r\n\
IEC_UINT *int_input[BUFFER_SIZE];\r\n\
IEC_UINT *int_output[BUFFER_SIZE];\r\n\
\r\n\
//Memory\r\n\
IEC_UINT *int_memory[BUFFER_SIZE];\r\n\
IEC_DINT *dint_memory[BUFFER_SIZE];\r\n\
IEC_LINT *lint_memory[BUFFER_SIZE];\r\n\
\r\n\
//Special Functions\r\n\
IEC_LINT *special_functions[BUFFER_SIZE];\r\n\
\r\n\
\r\n\
#define __LOCATED_VAR(type, name, ...) type __##name;\r\n\
#include \"LOCATED_VARIABLES.h\"\r\n\
#undef __LOCATED_VAR\r\n\
#define __LOCATED_VAR(type, name, ...) type* name = &__##name;\r\n\
#include \"LOCATED_VARIABLES.h\"\r\n\
#undef __LOCATED_VAR\r\n\
\r\n\
void glueVars()\r\n\
{\r\n";
}
int parseIecVars(istream& locatedVars, char *varName, char *varType)
{
string line;
char buffer[1024];
if (getline(locatedVars, line))
{
int i = 0, j = 0;
strncpy(buffer, line.c_str(), 1024);
for (i = 0; buffer[i] != '('; i++);
i++;
while (buffer[i] != ',')
{
varType[j] = buffer[i];
i++; j++;
varType[j] = '\0';
}
i++; j=0;
while (buffer[i] != ',')
{
varName[j] = buffer[i];
i++; j++;
varName[j] = '\0';
}
return 1;
}
else
{
return 0;
}
}
void findPositions(char *varName, int *pos1, int *pos2)
{
int i=4, j=0;
char tempBuffer[100];
while (varName[i] != '_' && varName[i] != '\0')
{
tempBuffer[j] = varName[i];
i++; j++;
tempBuffer[j] = '\0';
}
*pos1 = atoi(tempBuffer);
if (varName[i] == '\0')
{
*pos2 = 0;
return;
}
j = 0; i++;
while (varName[i] != '\0')
{
tempBuffer[j] = varName[i];
i++; j++;
tempBuffer[j] = '\0';
}
*pos2 = atoi(tempBuffer);
}
void glueVar(ostream& glueVars, char *varName, char *varType)
{
cout << "varName: " << varName << "\tvarType: " << varType << endl;
int pos1, pos2;
findPositions(varName, &pos1, &pos2);
if (pos2 >= 8)
{
cout << "***Invalid addressing on located variable" << varName << "***" << endl;
}
if (varName[2] == 'I')
{
//INPUT
switch (varName[3])
{
case 'X':
glueVars << "\tbool_input[" << pos1 << "][" << pos2 << "] = " << varName << ";\r\n";
break;
case 'B':
glueVars << "\tbyte_input[" << pos1 << "] = " << varName << ";\r\n";
break;
case 'W':
glueVars << "\tint_input[" << pos1 << "] = " << varName << ";\r\n";
break;
}
}
else if (varName[2] == 'Q')
{
//OUTPUT
switch (varName[3])
{
case 'X':
glueVars << "\tbool_output[" << pos1 << "][" << pos2 << "] = " << varName << ";\r\n";
break;
case 'B':
glueVars << "\tbyte_output[" << pos1 << "] = " << varName << ";\r\n";
break;
case 'W':
glueVars << "\tint_output[" << pos1 << "] = " << varName << ";\r\n";
break;
}
}
else if (varName[2] == 'M')
{
//MEMORY
switch (varName[3])
{
case 'W':
glueVars << "\tint_memory[" << pos1 << "] = " << varName << ";\r\n";
break;
case 'D':
glueVars << "\tdint_memory[" << pos1 << "] = (IEC_DINT *)" << varName << ";\r\n";
break;
case 'L':
if (pos1 > 1023)
glueVars << "\tspecial_functions[" << (pos1-1024) << "] = (IEC_LINT *)" << varName << ";\r\n";
else
glueVars << "\tlint_memory[" << pos1 << "] = (IEC_LINT *)" << varName << ";\r\n";
break;
}
}
}
void generateBottom(ostream& glueVars)
{
glueVars << "}\r\n\
\r\n\
void updateTime()\r\n\
{\r\n\
__CURRENT_TIME.tv_nsec += common_ticktime__;\r\n\
\r\n\
if (__CURRENT_TIME.tv_nsec >= 1000000000)\r\n\
{\r\n\
__CURRENT_TIME.tv_nsec -= 1000000000;\r\n\
__CURRENT_TIME.tv_sec += 1;\r\n\
}\r\n\
}";
}
void generateBody(istream& locatedVars, ostream& glueVars) {
// Start the generation process.
char iecVar_name[100];
char iecVar_type[100];
while (parseIecVars(locatedVars, iecVar_name, iecVar_type))
{
glueVar(glueVars, iecVar_name, iecVar_type);
}
}
/// This is our main function. We define it with a different name and then
/// call it from the main function so that we can mock it for the purpose
/// of testing.
int mainImpl(int argc, char *argv[])
{
// Parse the command line arguments - if they exist. Show the help if there are too many arguments
// or if the first argument is for help.
bool show_help = argc >= 2 && (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0);
if (show_help || (argc != 1 && argc != 3)) {
cout << "Usage " << endl << endl;
cout << " glue_generator [options] <path-to-located-variables.h> <path-to-glue-vars.cpp>" << endl << endl;
cout << "Reads the LOCATED_VARIABLES.h file generated by the MATIEC compiler and produces" << endl;
cout << "glueVars.cpp for the OpenPLC runtime. If not specified, paths are relative to" << endl;
cout << "the current directory." << endl << endl;
cout << "Options" << endl;
cout << " --help,-h = Print usage information and exit." << endl;
return 0;
}
// If we have 3 arguments, then the user provided input and output paths
string input_file_name("LOCATED_VARIABLES.h");
string output_file_name("glueVars.cpp");
if (argc == 3) {
input_file_name = argv[1];
output_file_name = argv[2];
}
// Try to open the files for reading and writing.
ifstream locatedVars(input_file_name, ios::in);
if (!locatedVars.is_open()) {
cout << "Error opening located variables file at " << input_file_name << endl;
return 1;
}
ofstream glueVars(output_file_name, ios::trunc);
if (!glueVars.is_open()) {
cout << "Error opening glue variables file at " << output_file_name << endl;
return 2;
}
generateHeader(glueVars);
generateBody(locatedVars, glueVars);
generateBottom(glueVars);
return 0;
}
// For testing, we need to allow omitting the main function defined here.
#ifndef OPLCGLUE_OMIT_MAIN
int main(int argc, char *argv[]) {
return mainImpl(argc, argv);
}
#endif // OPLCGLUE_OMIT_MAIN