mirror of
https://gitee.com/js-yhsec/energy_storage.git
synced 2026-05-28 03:09:24 +08:00
275 lines
9.1 KiB
C
275 lines
9.1 KiB
C
|
|
/***************************************************************************
|
||
|
|
rlstate.h - description
|
||
|
|
-------------------
|
||
|
|
begin : Sat Dec 29 2012
|
||
|
|
copyright : (C) 2012 by R. Lehrig
|
||
|
|
email : lehrig@t-online.de
|
||
|
|
***************************************************************************/
|
||
|
|
|
||
|
|
/***************************************************************************
|
||
|
|
* *
|
||
|
|
* This library is free software; you can redistribute it and/or modify *
|
||
|
|
* it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE as *
|
||
|
|
* published by the Free Software Foundation *
|
||
|
|
* *
|
||
|
|
***************************************************************************/
|
||
|
|
#ifndef _RL_STATE_H
|
||
|
|
#define _RL_STATE_H
|
||
|
|
|
||
|
|
#include <stdio.h>
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <string.h>
|
||
|
|
#include <ctype.h>
|
||
|
|
#include "rlthread.h"
|
||
|
|
|
||
|
|
/*! <pre>
|
||
|
|
This class is used to implement a statemachine.
|
||
|
|
|
||
|
|
Under pvbaddon/templates/statemachine/plc you find the statemachine consisting of several threads.
|
||
|
|
The main thread will read/write a Modbus PLC.
|
||
|
|
The statemachine stm2 will handle a small demo statemachine.
|
||
|
|
The statemachine stm1 will start stm2 if the user selects this function.
|
||
|
|
|
||
|
|
The data will be stored in a shared memory.
|
||
|
|
The shared memory contains a complex datastructure (typedef struct {...} USER_DEFINED_STRUCTURE;) which can be used to exchange values between several processes.
|
||
|
|
|
||
|
|
The pvbrowser visualization server is located under pvbaddon/templates/statemachine/pvs
|
||
|
|
There we use a SVG graphic (stm2.svg) showing the statemachine.
|
||
|
|
This graphic is generated by graphviz from stm2.dot
|
||
|
|
pvs and plc exchange data only via shared memory.
|
||
|
|
|
||
|
|
Please start both (plc and pvs) in a separate terminal and then start the pvbrowser client
|
||
|
|
|
||
|
|
Here is some sourcecode from the template:
|
||
|
|
// ***************************************************************************
|
||
|
|
// main.cpp - description
|
||
|
|
// -------------------
|
||
|
|
// begin : Sa. Mai 4 09:29:07 2013
|
||
|
|
// generated by : pvdevelop (C) Lehrig Software Engineering
|
||
|
|
// email : lehrig@t-online.de
|
||
|
|
// ***************************************************************************
|
||
|
|
#include "plcapp.h"
|
||
|
|
|
||
|
|
SHM_DATA *shm_data;
|
||
|
|
rlSharedMemory shm("/srv/automation/shm/plc.shm", sizeof(SHM_DATA));
|
||
|
|
rlSerial tty;
|
||
|
|
rlModbus mb;
|
||
|
|
rlMutex mb_mutex;
|
||
|
|
rlState sm1, sm2;
|
||
|
|
|
||
|
|
//// helper functions
|
||
|
|
int printBinByte(unsigned char val)
|
||
|
|
{
|
||
|
|
if(val & BIT7) printf("1");
|
||
|
|
else printf("0");
|
||
|
|
if(val & BIT6) printf("1");
|
||
|
|
else printf("0");
|
||
|
|
if(val & BIT5) printf("1");
|
||
|
|
else printf("0");
|
||
|
|
if(val & BIT4) printf("1");
|
||
|
|
else printf("0");
|
||
|
|
printf(":");
|
||
|
|
if(val & BIT3) printf("1");
|
||
|
|
else printf("0");
|
||
|
|
if(val & BIT2) printf("1");
|
||
|
|
else printf("0");
|
||
|
|
if(val & BIT1) printf("1");
|
||
|
|
else printf("0");
|
||
|
|
if(val & BIT0) printf("1");
|
||
|
|
else printf("0");
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int printBin(unsigned char *data)
|
||
|
|
{
|
||
|
|
printf("BinData: ");
|
||
|
|
printBinByte(data[0]);
|
||
|
|
printf(" - ");
|
||
|
|
printBinByte(data[1]);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
//// Schneider PLC: first 4 bits are outputs then 6 bits input follow
|
||
|
|
static int readIO()
|
||
|
|
{
|
||
|
|
unsigned char data[256];
|
||
|
|
int ret;
|
||
|
|
|
||
|
|
MB_readInputStatus(1,0,10,data); // read all IO values from modbus
|
||
|
|
shm_data->plc.in.in1 = mb.data2int(data); // store data in shared memory
|
||
|
|
|
||
|
|
if(trace)
|
||
|
|
{
|
||
|
|
printf("readIO:: ret=%d ", ret);
|
||
|
|
printBin(data);
|
||
|
|
printf(" in1=%x\n", shm_data->plc.in.in1);
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int writeIO()
|
||
|
|
{
|
||
|
|
unsigned char coils[8];
|
||
|
|
int ret;
|
||
|
|
|
||
|
|
coils[0] = shm_data->plc.out.out1 & 0x0ff;
|
||
|
|
MB_forceMultipleCoils(1,0,4,coils); // write the 4 output bits to modbus
|
||
|
|
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int main()
|
||
|
|
{
|
||
|
|
if(trace) printf("plc starting ...\n");
|
||
|
|
if(trace) printf("shm.status=%d\n", shm.status);
|
||
|
|
if(shm.status != rlSharedMemory::OK)
|
||
|
|
{
|
||
|
|
printf("ERROR: shared memory status is not ok\n");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
shm_data = (SHM_DATA *) shm.getUserAdr();
|
||
|
|
memset(shm_data,0,sizeof(SHM_DATA));
|
||
|
|
if(tty.openDevice("/dev/ttyUSB0",B9600,1,1,8,1,rlSerial::NONE) < 0)
|
||
|
|
{
|
||
|
|
printf("ERROR: openDevice(\"/dev/tty/USB0\")\n");
|
||
|
|
}
|
||
|
|
mb.registerSerial(&tty);
|
||
|
|
|
||
|
|
startStepsStm1(&sm1, 100); // start statemachine 1
|
||
|
|
startStepsStm2(&sm2, 100); // start statemachine 2
|
||
|
|
printf("going to IO loop\n");
|
||
|
|
while(1)
|
||
|
|
{
|
||
|
|
readIO();
|
||
|
|
writeIO();
|
||
|
|
rlsleep(10);
|
||
|
|
}
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// *****************************************************************************
|
||
|
|
// stm2.cpp - description
|
||
|
|
// -------------------
|
||
|
|
// begin : Sa. Mai 4 09:29:07 2013
|
||
|
|
// generated by : pvdevelop (C) Lehrig Software Engineering
|
||
|
|
// email : lehrig@t-online.de
|
||
|
|
// A simple template for implementing your own statemachine
|
||
|
|
// See: pvbaddon/templates/statemachine
|
||
|
|
// *****************************************************************************
|
||
|
|
#include "plcapp.h"
|
||
|
|
|
||
|
|
////TODO: define our states
|
||
|
|
//// Your states are defined by static functions which get a pointer to the statemachine
|
||
|
|
//// The pointer sm->user might be used to transfer the address of a user defined datastructure
|
||
|
|
//// A transition from one state to the next is done by sm->gotoState(theNextState);
|
||
|
|
//// Your statemachine runs within a separate thread and the current state is called within "cycletime" intervals
|
||
|
|
static void stStart(rlState *sm);
|
||
|
|
static void stProcess(rlState *sm);
|
||
|
|
static void stFinish(rlState *sm);
|
||
|
|
|
||
|
|
////TODO: implement our states
|
||
|
|
static void stStart(rlState *sm)
|
||
|
|
{
|
||
|
|
shm_data->plc.out.out1 = 1; // set output 1 in shared memory
|
||
|
|
if(sm->stepCounter > 20)
|
||
|
|
{
|
||
|
|
shm_data->plc.out.out1 = 2; // reset output 1 in shared memory
|
||
|
|
strcpy(shm_data->plc.state.stm2_name,"Process"); // set next state name in shared memory
|
||
|
|
sm->gotoState(stProcess); // goto the next state
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static void stProcess(rlState *sm)
|
||
|
|
{
|
||
|
|
shm_data->plc.out.out1 = sm->stepCounter; // set output 1 in shared memory
|
||
|
|
if(sm->stepCounter > 30)
|
||
|
|
{
|
||
|
|
strcpy(shm_data->plc.state.stm2_name,"Finish"); // set next state name in shared memory
|
||
|
|
sm->gotoState(stFinish); // goto the next state
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static void stFinish(rlState *sm)
|
||
|
|
{
|
||
|
|
shm_data->plc.out.out1 = 1; // set output 1 in shared memory
|
||
|
|
if(sm->stepCounter > 30)
|
||
|
|
{
|
||
|
|
shm_data->plc.out.out1 = 0; // reset output 1 in shared memory
|
||
|
|
strcpy(shm_data->plc.state.stm2_name,"NULL"); // set next state name NULL
|
||
|
|
shm_data->plc.state.stm2_running = 0; // reset running in shared memory
|
||
|
|
sm->gotoState(NULL); // goto NULL state
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int startStepsStm2(rlState *sm, int cycletime) // start our statemachine
|
||
|
|
{
|
||
|
|
if(trace) printf("stm2 starting\n");
|
||
|
|
shm_data->plc.state.stm2_running = 1; // set running in shared memory
|
||
|
|
strcpy(shm_data->plc.state.stm2_name,"Start"); // set next state name in shared memory
|
||
|
|
sm->gotoState(stStart); // goto nextState
|
||
|
|
sm->startSteps(cycletime); // start a thread which handles the statemachine
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
// ***************************************************************************
|
||
|
|
// stm1.cpp - description
|
||
|
|
// -------------------
|
||
|
|
// begin : Sa. Mai 4 09:29:07 2013
|
||
|
|
// generated by : pvdevelop (C) Lehrig Software Engineering
|
||
|
|
// email : lehrig@t-online.de
|
||
|
|
// ***************************************************************************
|
||
|
|
#include "plcapp.h"
|
||
|
|
extern rlState sm2;
|
||
|
|
|
||
|
|
////TODO: define our states
|
||
|
|
static void stStart(rlState *sm);
|
||
|
|
|
||
|
|
////TODO: implement our states
|
||
|
|
static void stStart(rlState *sm)
|
||
|
|
{
|
||
|
|
shm_data->plc.out.out2 = sm->stepCounter;
|
||
|
|
if(shm_data->plc.state.stm2_running == 0)
|
||
|
|
{
|
||
|
|
if(shm_data->pvs.state.button_start_stm2 == 1)
|
||
|
|
{
|
||
|
|
startStepsStm2(&sm2, 100); // start statemachine 2 thread
|
||
|
|
}
|
||
|
|
else if(shm_data->plc.in.in1 & BIT1)
|
||
|
|
{
|
||
|
|
startStepsStm2(&sm2, 100); // start statemachine 2 thread
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int startStepsStm1(rlState *sm, int cycletime) // start our statemachine
|
||
|
|
{
|
||
|
|
if(trace) printf("Start stm1\n");
|
||
|
|
shm_data->plc.state.stm1_running = 1; // set running within shared memory
|
||
|
|
sm->gotoState(stStart); // goto nextState
|
||
|
|
sm->startSteps(cycletime); // start a thread that will handle our statemachine
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
</pre>
|
||
|
|
*/
|
||
|
|
|
||
|
|
class rlState
|
||
|
|
{
|
||
|
|
public:
|
||
|
|
rlState();
|
||
|
|
~rlState();
|
||
|
|
int startSteps(int cycletime);
|
||
|
|
int runSteps(int cycletime);
|
||
|
|
void gotoState(void (*funcPtr)(rlState *sm));
|
||
|
|
void *user;
|
||
|
|
int stepCounter;
|
||
|
|
int cycletime;
|
||
|
|
static const long MAX_STEP = 1000*1000*1000;
|
||
|
|
void (*nextStep)(rlState *sm);
|
||
|
|
void (*lastState)(rlState *sm);
|
||
|
|
rlThread thread;
|
||
|
|
};
|
||
|
|
|
||
|
|
#endif
|
||
|
|
|