SerTi

Susanna Blomqvist
Antti Korhonen
Heikki Mylläri
Pekka Pakari

Software Report 1.1
							03.07.2003

University of Jyväskylä
Department of Mathematical Information Technology

Authors:	Susanna Blomqvist (SBl), Antti Korhonen (AKo), Heikki Mylläri (HMy), Pekka Pakari (PPa)
Title:	Software Report for the SerTi Project
Abstract:	The SerTi project designed and developed the SerialTester software for Stresstech Ltd. This software report describes the structure and functionality of SerialTester.

Version history:

Table of Contents

1. Introduction
2. Terms, Acronyms and Abbreviations
3. The Software and its Background
4. User Interface
4.1 Main Window
4.2 Motor Controls
4.3 Commands and Log
4.4 Controller Status
4.5 Command Menus and Setup Dialogs
4.6 Parameter Dialog
5. The Structure of the Software
5.1 The General Structure
5.2 The Class Structure
5.3 The Command Sequence
6. The Standard C++ Classes
6.1 IControl
6.2 CSLControl
6.3 CSLPara
6.4 IComm
6.5 CSerialComm
6.6 CTermLog
7. The MFC Classes
7.1 CMainDlg
7.2 CDriveButton
7.3 CPrefDlg
7.4 CSerialTesterApp
7.5 CSLParaDlg
7.6 CSerialParaDlg
7.7 CEditEnter
8. The External Code
8.1 CDynamicLED
8.2 CSerial
9. The Structure of the Editable Configuration Files
9.1 The commands.ini file
9.2 The motor.par file
9.3 The lastmotor.par file
10. Testing, Test Results and Known bugs
11. Further development
11.1 Support for Any Number of Motors
11.2 Support for More Controllers
11.3 TCP/IP Communication
11.4 Dynamic Shortcut Keys
12. Conclusion
References

 
1. Introduction

SerTi was a student software project that was carried out in the University of Jyväskylä during spring 2003, under the supervision of the Department of Mathematical Information Technology. The project designed and developed a software called SerialTester for Stresstech Ltd. The Windows application will be used for testing and monitoring equipment controlled via the RS-232 bus.

In the beginning of the project, Stresstech Ltd delivered a few documents to the project team. The C++ Coding Standard determines the coding standard to be used in the software. SL Communication Specs describe the syntactic instruction language used to command and configure StressLogic. Motor Parameters is a description of parameters for StressLogic. The company also supplied the team with one StressLogic controller and one X-Y table for testing purposes.

In addition to this document, the SerTi group also wrote other documents related to the project and the software. Of those, the Project Plan and the Project Report are in Finnish, and the rest in English as the client requested. The Project Plan describes the intended course of the project in terms of timetables and the division of work between the members of the group. The Software Plan outlines the functions of the software, the class diagrams and the intended user interface. The Testing Plan describes the testing cases for the software and the Testing Report includes the test results. The Project Report is an overview of the project, including assessments.

This document describes the structure and the technical solutions of the finished software. Chapter 2 explains some of the terms used in this document. Chapter 3 describes the backgrounds of the software. Chapter 4 documents the user interface. Chapters 5, 6, 7 and 8 contain a description of the program code, the class structure and the interfaces. Chapter 9 describes the configuration files. Chapter 10 summarises the testing results and introduces all known bugs. Chapter 11 presents some ideas for further development of SerialTester.

2. Terms, Acronyms and Abbreviations

The following terms are used in the document:

SL	(StressLogic) is a motor driver and an I/O board manufactured by StressTech Ltd.	
ST	(SerialTester) is the testing and monitoring software for StressLogic. It was developed by the SerTi project.	
RS-232	is a PC serial communication standard.	
I/O	is the abbreviation for Input/Output.	
Spy Cable	is a special 3 headed cable used to monitor RS232 communication between two systems. The third end is connected to the PC that logs the traffic between the monitored systems.	
GUI	is the abbreviation for graphical user interface.	
View/Model

		is a design paradigm where model (the core of the software) is separated from view (GUI). In other words, no part of the actual software functionality resides within the GUI classes.	
STL	(Standard Template Library) is a C++ library that provides a set of easily composable C++ container classes and generic algorithms (template functions).	
LED	(Light Emitting Diode) is a semi-conducting electronics component which generates light. It is a graphical representation in the case of the developed software.	
X-Y Table	is a device which contains a table that moves in two dimensions. It has two servomotors and is used by StressTech Ltd. in some of their products.	
Servomotor	is an electronically controlled motor.	
MFC	(Microsoft Foundation Class) is the Microsoft’s class library for Windows software.	

3. The Software and its Background

Stresstech Group serves metal industry all over the world with solutions and high-tech instruments for non-destructive testing of the quality of components. Its clients include major companies in the automobile and aircraft industry.

Stresstech Group's main products are Barkhausen Noise analysers and sensors, custom inspection stands, X-ray Diffraction analysers and inspection stands. Several different applications use Barkhausen Noise to study magnetic properties and thus the presence or absence of material defects and residual stress levels. The various analysed components include gears, bearings, camshafts, crankshafts, universal joints and piston pins. X-ray analysers use X-ray diffraction to measure residual stresses and retained austenite contents. Stresstech Group also provides custom inspection stands for shop floor quality control.

StressLogic is a logical motor driver and I/O board manufactured by Stresstech Ltd.
It is used to control servomotors in some of their products. StressLogic is controlled and configured with a computer via the RS232 (serial) line. 

Previously, Stresstech had configured and tested the equipment in their products, especially the StressLogic motor controller, manually by sending commands with a terminal program such as Windows Hyperterminal. SerTi project developed the SerialTester software which makes testing more human-friendly and provides easier control for running the motors.

The software includes a graphical user interface with motor controls, status LEDs, a log and a field for entering commands manually. The status of all the motors and the controller can be read one at a time. Also an auto-polling function can be turned on for all of them to retrieve the information in a defined time interval.

The software was made using Microsoft Visual C++ and the MFC class library. The class structure uses interfaces so that the controller and the communication parts can be completely changed by re-implementing few classes.  This means that the user interface is bound to a minimal portion of the code. The controller commands can also be changed dynamically from a file, so it’s possible to change the whole command set without rebuilding the software.

4. User Interface

In this chapter the SerialTester GUI is described in detail. The main window contains all the information and controls that user usually needs. In the Preferences dialog user can change few functional settings and in the Port Settings dialog user can choose the communication settings. The Parameter dialog is for setting the parameter values of the motors.

4.1 Main Window

Figure 1 shows the main window. It’s divided into three logical wholes: the motor controls (upper left corner), the log/terminal view (upper right corner) and the controller status view (in the bottom).

Figure 1: Main window.

4.2 Motor Controls

The motor controls are split in three sets of identical controls and status displays, one for each motor. These common controls include two arrow buttons for manually driving the motor. The Start and Stop buttons start and stop the motor. The Zero button empties the target field and sets the controller position value to zero. The Cal button calibrates the motor and to the Target field the user can enter a position value. Once the Start button is clicked the motor will start to run towards the defined position value.

The status bits of the motor are shown as red LEDs. When the user clicks the Read button, SerialTester updates the status and the position of the motor in question. Clicking the Param button opens the parameter dialog (See Figure 4). 

The keyboard shortcuts for all the buttons are described in the help of the software.

4.3 Commands and Log

The Commands and Log view is divided in two parts (see Figure 1). The upper part is the log, where all the sent commands as well as SL responses are displayed, completed with relevant date and time information.

The controls for the log view are located immediately below it. The user can insert a marker row into the log by clicking the Mark button (or pressing Ctrl-M). The Save button saves the log into an ASCII text file. When the Pause button is clicked, the log updates are frozen, so that it may be inspected without hindrance from incoming data. Once this is done, the button’s label changes to Continue. A single click on it will both resume the logging as normal and update the log with all messages sent and received while the log was paused.

The lower part of the view is reserved for the Commands view. It is a multi-line input field  where the user can manually type commands and send them to SL by either clicking on Send or pressing Enter on the keyboard. In addition to this, the user can both save and load command script files (via the Save and Load buttons). All the commands in the commands view can be executed with the Run all button. 

Both parts are scrollable, and resizing the main window horizontally allows the user to expand both views. Standard Windows Copy and Paste work in the terminal view. The log is read-only, thus the user can only copy from it.

4.4 Controller Status

The bottom part of the main window is reserved for the controller status block (See Figure 1). It consists of  a large Read button, the clicking of which will update everything in the status block. The controller’s I/O byte status is shown with yellow LEDs. A green power indicator led has beside it two buttons to switch motor power on or off. Below it are two red warning LEDs.

The output LEDs are clickable, i.e. a mouse click on a LED sends a command to turn that LED on or off.

Below all of these is the status bar which is used by SerialTester to convey its own status information (error messages and such) to the user.

4.5 Command Menus and Setup Dialogs

The command menus are, as per Windows standard, located in the upper part of the screen (See Figure 1). 

The commands in the File menu are Save Log as, Load Command File, Save Command File as and Exit. Via the commands the user can save the log as well as open and save the command queue files, which are equivalent to the save/load buttons below the Commands and Log views. The menu also lets the user exit the program. 

Via the Edit menu the user can clear the log view (also empties the log from memory) with the only command Clear Log.

Via the Setup menu the user can access the command Parameters, which opens a submenu with the selections Motor A, Motor B and Motor C, each corresponding to the parameter dialog of one motor. In here, the user can set parameters for individual motors, equivalent to the Param buttons in the motor controls. The user can access the Preferences dialog, wherein the maximum log buffer size and the autostatus polling interval are set. Autostatus sets autostatus on or off (checkmarked). AutoScroll toggles automatic log view scrolling on and off.

Figure 2: Preferences dialog.

The Autostatus function provides the way to update the status of the motors, the I/O bits and the system itself automatically on a set interval (default 100 ms). This will reduce the need for manual updates, in other words, it spares the user from the trouble of clicking on one of the Read buttons each time a status check is required.

The Connection menu holds the options for opening (the command Connect) and closing (Disconnect) communications as well as sending the initialization command to SL (Initialize SL). The communication port settings dialog (in Figure 3) can also be accessed here with the command Connection Settings.

Figure 3: Port settings dialog.

Finally, the Help menu commands Help and About allow the user to view the on-line help and general information about the program.

4.6 Parameter Dialog

Figure 4 shows the motor parameter dialog. From this dialog all the parameters for the chosen motor can be set. The buttons Save, Load and Send affect all the motors. 

Figure 4: Motor parameter dialog.

5. The Structure of the Software

The chapter presents in detail the structure of the software. First there are the abstract description and the class diagram. Then each class and method is explained. Finally, we take a look at the basic command sequence.

5.1 The General Structure

The SerialTester software is composed of three separate logical parts: the GUI, the command interpreter and the communication class. Between these modules two interfaces exist: one separating the GUI from the command interpreter, and another one between the interpreter and the communication class (see Figure 5).

Figure 5: General structure of the SerialTester software.

Anyone of these three parts can be altered or exchanged altogether without changing the other two, as long as the replacement uses the same interface(s).

The basic command sequence is simple enough. Every command is in one way or another initiated in the GUI. It knows an abstract “controller” entity that uses a predefined interface, and through that interface it sends an abstract command (“initialize communications”, “run motor a” etc.) to the command interpreter. The interpreter, in turn, “translates” this abstract command into one which the physical controller understands. The command interpreter passes the command on to the communication class which it only knows on an equally abstract level. Finally, the communication class transfers the command string to the physical controller by whatever bus it is capable of using (in this version, only RS-232 is supported). For more details, see Chapter 5.3.

The return traffic is handled with the help of standard Windows messages. Upon connection, the communication class initiates a separate “listener” thread. Whenever that thread detects a communication event, it posts a message to the window given to it upon initialization. Once the GUI detects such a message, it sends an abstract “get data” command to the command interpreter, and the message comes as a return value.

The return value is not parsed or “tidied up” in any way. The GUI handles all visualization of the return value (the interface remains intact since the GUI doesn’t need to actually know any SL commands in order to do this). Again, for more details see Chapter 5.3.

5.2 The Class Structure

Figure 6 shows the associations between the various classes of the software, as well as a major portion of the method base of the classes. The class attributes and the MFC-based methods of the various dialogs are omitted for the sake of clarity, though they will be presented in Chapters 6 and 7.

The classes, their method base, the return values of the methods and their attributes are described in Chapters 6 and 7.

Figure 6: SerialTester class structure diagram.

5.3 The Command Sequence

Figures 7 and 8 show the basic command sequence and the standard response sequence of the software. Every command and response is handled in the same fashion, thus multiple sequence diagrams would be redundant.

The command sequence in Figure 7 is initiated by the user via one of the dialogs (which one specifically is irrelevant, as all cases are handled similarly). This triggers a call for the relevant generic command method of CSlControl, which uses CSlPara to translate the command into SL syntax and calls for the generic ‘send’ method of the communication class, CSerialComm. In addition to this, CSlControl simultaneously sends a request to log the command to CTermLog. CSerialComm then handles the actual transition.

The response routine is similar, albeit in reverse (see Figure 8). The communication class waits for serial traffic in another thread, invisibly. Once traffic is detected, it sends a message to CMainDlg, which is then processed using standard Windows message handling. This triggers a call for the CSlControl routine for requesting a response from the communication class, RequestResponse. The response string is returned, and CSlControl again sends a logging request to CTermLog.

Figure 7: Basic command sequence diagram.            Figure 8: Response sequence diagram.

6. The Standard C++ Classes

The following classes are implemented in standard C++. Basically, they form the model in the view/model hierarchy and represent the underlying mechanics of the software.

6.1 IControl

IControl is the abstract base class that holds the generic (non-SL) commands. These methods form a standard, generic interface for motor usage. Only if the command base of the underlying system is expanded significantly will this interface class be affected. Revisions in command structure and/or execution can be implemented by changing only the classes CSLControl and/or CSLPara (see Chapters 6.2 and 6.3, respectively).

As the following methods are all placeholders meant to be redefined, this section isn’t very interesting. See CSLControl for the versions that have actual functionality.

The public methods are
virtual void StartMotor(char Motor, string Position);
is the placeholder for the “start motor” abstract command.
virtual void StopMotor(char Motor);
is the placeholder for the “stop motor” abstract command.
virtual void SetParameters(char motor, bool vel);
is the placeholder for the “set motor parameters” abstract command.
virtual void SetMotorToZero(char Motor);
is the placeholder for the “set motor position to zero” abstract command.
virtual void ReadMotorStatus(string Motor);
is the placeholder for the “read motor status” abstract command.
virtual void MotorPower(bool status);
is the placeholder for the “set motor power” abstract command.
virtual void CalibrateMotor(char motor, string position);
is the placeholder for the “calibrate motor” abstract command.
virtual void InitComms();
is the placeholder for the “initialize communications” abstract command.
virtual void CloseComms();
is the placeholder for the “close communications” abstract command.
virtual BOOL IsConnectionReady();
is the placeholder for the “is connection ready” abstract command. Always returns FALSE unless overridden.
virtual void InitController();
is the placeholder for the “initialize controller” abstract command.
virtual void SetControllerOutOn(int nOutput);
is the placeholder for the “set controller output n on” abstract command.
virtual void SetControllerOutOff(int nOutput);
is the placeholder for the “set controller output n off” abstract command.
virtual void ReadControllerStatus(string sPort);
is the placeholder for the “read controller status” abstract command.
virtual void SendToController(string Line,string sender);
is the placeholder for the “send line to controller” abstract command.
virtual void ReadResponse();
is the placeholder for the “read response” abstract command.
virtual void CheckTimeout();
is the placeholder for the “check if timeout is exceeded” abstract command.

The IControl class has no attributes.

6.2 CSLControl

CSLControl is the class containing the implementation of IControl (see Chapter 6.1) for the StressLogic motor controller.

The public methods are
void CheckTimeout();
checks if some of the "members" or pairs in the command queue are older than TIMEOUT .
void CalibrateMotor(char motor, string position);
sends the calibration velocity parameter to SL and then sends the “calibrate” command with the motor and position parameters.
void SelectDestination(string response);
checks the first item (command) in queue. If it has a meaningful return value, the response string is directed to the appropriate class.
CSlControl(CMainDlg *maindlg, CSerialParaDlg *pCommsDlg, CSlParaDlg *pParaDlgA, CSlParaDlg *pParaDlgB, CSlParaDlg *pParaDlgC);
is the constructor. Instances for CSLPara (see Chapter 6.3) and CSerialComm (see Chapter 6.5) are created here. The pointers are for inter-class communication.
~CSlControl();
	is the destructor. All object instances are deleted here.
void StartMotor(char Motor, string Position);
starts to drive the motor defined by the Motor parameter to the desired Position. Valid values for Motor are A, B and C.
void StopMotor(char Motor);
stops the motor defined by the Motor parameter. Valid values for Motor are A, B and C.
void SetParameters(char motor, bool vel);
requests the class behind the pointer m_pSlPara for the parameters to send to the controller and then calls the SendString function. The motor in question is defined by the motor parameter (A, B or C). The vel parameter says whether the normal or the calibration velocity should be sent.
void ReadMotorStatus(string Motor);
sends the command requesting the status information for Motor.
void SetMotorToZero(char Motor);
sets the SL’s motor position value to 0. The motor in question is defined by the Motor parameter (A, B or C).
void MotorPower(bool status);
sets the motor power on or off according to the boolean parameter status.
void InitComms();
	calls m_pComms.InitComms() to initialize the communications.
void InitController();
	sends the init command to the controller.
void CloseComms();
calls m_pComms.CloseComms() to shut down the communications.
BOOL IsConnectionReady();
returns TRUE if the port has been successfully opened, FALSE otherwise.
void ReadControllerStatus(string sPort);
sends the command requesting the status information for the StressLogic input LEDs. The sPort parameter handles the values 0 and 1 for the two controller ports.
void SetControllerOutOn(int nOutput);
is used for setting the output status bits of the controller on. NOutput is the number of the LED.
void SetControllerOutOff(int nOutput);
is used for setting the output status bits of the controller off. NOutput is the number of the LED.
void SendToController(string Line,string sender);
sends a string (the Line parameter) to the controller. At the same time it pushes all information needed (sender/receiver and time) to the command queue. Different SL commands are discerned with the sender parameter.
void ReadResponse();
asks the class behind the pointer m_pComms to read and return the controller’s response string. Once it finds \r\n it sends the string to the method SelectDestination.

The public attributes are
CMainDlg* m_pMain;
	is a pointer to the CMainDlg instance.
CSerialComm* m_pComms;
	is a pointer to the CSerialComm instance.
CSlPara* m_pSlPara;
	is a pointer to the CSlPara instance.

The private attributes are
string response;
	stores the SL response from the serial port.
queue< pair<string,SYSTEMTIME> > commandqueue;
	stores all sent commands.

6.3 CSLPara

CSLPara is a helper class used by the CSLControl (see Chapter 6.2) interpreter class. It handles the command file and stores the motor parameters.

The public methods are
CSlPara();
	is the constructor. It opens the file commands.ini and reads its contents to m_Commands map. It also calls the method LoadMotorParams with the file name lastmotor.par that contains the parameters last used. 
virtual ~CSlPara();
is the destructor. It calls the method SaveMotorParamsInFile with the file lastmotor.par. 
string GetCommand(string key);
	returns the value corresponding to key. If it doesn’t find the key, it returns ERROR. 
string SendMotorParams(char motor, bool vel);
	returns a string that contains all the parameters of the specified motor with parameter ids. 
void SaveMotorParam(char motor, string key, string value);
saves given value corresponding to key to the map that is defined by motor. 
void LoadMotorParams(string file);
	reads motor parameters from given file and saves them to the maps m_motorAParams, m_motorBParams and m_motorCParams.
void SaveMotorParamsInFile(string file);
	saves motor parameters into the given file.
string GetMotorParam(char motor, string key);
	returns the value corresponding to the given key.

The private attributes are
map<string,string> m_Commands;
	contains commands that are to be sent to StressLogic. 
map<string,string> m_motorAParams;  
	contains the motor parameters of the motor A. 
map<string,string> m_motorBParams;
	contains the motor parameters of the motor B.
map<string,string> m_motorCParams;
	contains the motor parameters of the motor C.
6.4 IComm

IComm class is the interface for the communication class. The command interpreter class (SLControl, see Chapter 6.2) knows only an abstract communication protocol, while the actual protocol and the medium are hidden behind IComm. This allows one to rewrite the entire communication class, if necessary, with no changes to the interpreter.

As with IControl, these methods are all placeholders that don’t do anything particularly interesting until overridden. See CSerialComm in Chapter 6.5 for the versions with actual functionality.

The public methods are
IComm();
	is the constructor. Has no additional functionality.
virtual ~IComm();
	is the destructor. Has no additional functionality.
virtual void InitComms(CWnd* pMainDlg);
is used, once overridden, to initialize whatever means of communication is used.
virtual void CloseComms();
is used, once overridden, to shut down the communications, performing whatever additional cleanup is necessary.
virtual LONG SendString(string MsgToBeSent);
is the placeholder for the generic “send this exact string to the controller” routine. The return value is reserved for transferring the communication class’s possible error codes and is always 0 unless overridden.
virtual string ReceiveString();
is used, once overridden, for the return traffic. See CSerialComm, Chapter 6.5. Always returns an empty string unless overridden.
virtual BOOL IsConnectionReady();
is the placeholder for the method that checks whether the connection is ready. Always returns FALSE unless overridden.

6.5 CSerialComm

What CSLControl (Chapter 6.2) is to IControl (Chapter 6.1), CSerialComm is to IComm (Chapter 6.4). CSerialComm inherits the IComm interface class and defines the functionality of its abstract communication operations, using the standard RS-232 serial bus. In doing this it makes use of the external CSerial helper class (see Chapter 8.2).

The public methods are
CSerialComm();
is the constructor. It sets up the port handle and reads the port settings from port.cfg.
virtual ~CSerialComm();
is the destructor. It saves the communication settings, closes the connection (and the listener thread, if active). Shouldn’t really be virtual, but project time constraints do not allow another recompile at this point. The virtual descriptor doesn’t affect anything.
void InitComms(CWnd* pMainDlg);
configures the port using the member variable values, then opens it and binds serial events to given dialog using the default event mask. The helper class CSerialWnd starts the listener thread at this point. Whenever the listener thread detects a port anomaly, it posts a message in the window at pMainDlg.
void CloseComms();
closes the port. CSerialWnd takes care of all necessary cleanup and kills the listener thread.
LONG SendString(string MsgToBeSent);
writes the string given via MsgToBeSent to the port. The return value is the CSerial’s error code. This is transferred to the controller so that if necessary, it could be forwarded to the GUI for visualization.
string ReceiveString();
is the core of the return traffic. Whenever the listener thread detects data in the port, the helper class CSerialWnd posts a standard Windows message into the main dialog’s message queue. Via normal Windows message handling the controller’s ReadResponse method is eventually called, which in turn calls this. All data in the port is read, and the return value is the string read.
BOOL IsConnectionReady();
checks whether the connection is ready (ie. if the port is open). CSerial has its own method specifically for this, thus the implementation is very simple. It returns TRUE if open, FALSE otherwise.

The following six  Get public methods are used by the CSerialParaDlg dialog class to read the stored communication settings. The return values are strings that correspond to the Port Settings dialog combobox texts. Check the member variables of CSerialParaDlg if you wish to know the valid settings.

string GetPort();
returns the used port as a string.
string GetBaudrate();
returns the baud rate as a string.
string GetDatabits();
	returns the number of data bits as a string.
string GetParity();
	returns the parity as a string.
string GetStopbits();
	returns the number of stop bits as a string.
string GetHandshaking();
	returns the type of flow control as a string.

The following six Set public methods are used by the CSerialParaDlg dialog class to alter the stored communication settings. The parameters are strings that correspond to the Port Settings dialog combobox texts. Check the member variables of CSerialParaDlg if you wish to know the valid settings

void SetPort(string sNewPort);
sets the used port setting, given as the parameter.
void SetBaudrate(string sNewBaudrate);
	sets the baud rate, given as the parameter.
void SetDatabits(string sNewDatabits);
	sets the number of data bits, given as the parameter.
void SetParity(string sNewParity);
	sets the parity, given as the parameter.
void SetStopbits(string sNewStopbits);
	sets the number of stop bits, given as the parameter.
void SetHandshaking(string sNewHandshaking);
	sets the type of flow control, given as the parameter.

The public attributes are
CSerialMFC *m_Serial;
	represents one COM port.

The private attributes are the stored port settings.

string m_sPort;
is the port used.
string m_sBaudrate;
	is the baud rate.
string m_sDatabits;
	is the number of data bits.
string m_sParity;
	is the parity.
string m_sStopbits;
	is the number of stop bits.
string m_sHandshaking;
	is the type of flow control used.

6.6 CTermLog

CTermLog is a class that handles two different kinds of strings: log lines and commands. The strings are saved in an STL vector.

The public methods are
void ClearLog();
	clears the LogLines vector.
CTermLog();
	is the constructor.
virtual ~CTermLog();
	is the destructor.
void LogCommand(string p_sCommandLine);
adds the parameter string to the LogLines vector. The method checks if the vector (log buffer) is ‘full’. In that case it deletes the first string before adding a new one.
void LogResponse(string p_sResponseLine);
is same as the LogCommand method, but for the response lines. It doesn’t really do anything in this version.
void SendCommand(string p_sCommandLine);
	adds the parameter string to the command vector.
void AddMark(int p_nLineNumber);
adds to the end of the LogLines vector the marker string. The parameter is the mark number.
void SaveLog(string p_sFileName) const;
saves the strings in the LogLines vector in the file given as the parameter.
void SaveTerminal(string p_sFileName) const;
saves the strings in the Commands vector in the file given as the parameter.
void LoadCommandFile(string p_sCommandFile);
	opens and reads the defined command file to the command window.
void Pause();
	pauses the log so that the lines won’t appear to the window.
void Continue();
	continues printing the lines to the window.
void SetPauseSetOn(int p_nLineNumber)
	sets the parameter line number when the Pause button is pushed.
int  GetPauseSetOn(void) const
	returns the line number when the Pause button is pushed.
bool GetPauseState(void) const
	returns whether the pause is on (TRUE) or off (FALSE).
string GetLogLine(int p_nLineNumber) const
	returns the log line given as the parameter.
string GetCommandLine(int p_nCommandNumber) const
	returns the command line given as the parameter.
int GetLogSize(void) const
	return the size of the LogLines vector.
int GetCommandsSize(void) const
	return the size of the Commands vector.
void ClearCommands(void)
	clears the command vector.
string GetLastLogLine(void) const;
	returns the last log line.
string GetLastCommandLine(void) const;
	returns the last command line.
void SetLogBufferFull(bool p_bFull=true)
	sets the log buffer state to full (TRUE) or not full (FALSE).
bool GetLogBufferFull(void) const
	returns whether the log buffer is full (TRUE) or not (FALSE).

The private attributes are
int m_nMarkNumber;
	is the running mark number.
int m_nPauseSetOn;
	is used to keep track of the line number while the pause is set on.
bool m_bPauseOn;
	tells whether the pause is on or off.
bool m_bLogBufferFull;
	tells whether the log buffer is full or not.
vector<string> m_LogLines;
	is the vector for the log lines.
vector<string> m_Commands;
	is the vector for the command lines.

7. The MFC Classes

The following classes are user interface specific and were implemented using the MFC libraries. Each of them represents a dialog, and thus has the standard MFC methods (OnOK, UpdateData etc.). These will not be covered here.

7.1 CMainDlg

CMainDlg is the application’s main dialog class.

The public methods are
string GetLogFileName();
	returns the name for the log file.
void SwitchOffLed(string command);
switches a led off if it's not already switched off. The LED is identified by the parameter command.
void SwitchOnLed(string command);
switches a led on if it's not already switched on. The LED is identified by the parameter command.
void SetParamsSent(char motor,bool boolean);
sets the Boolean variable m_bParamXSent according to the parameter boolean if parameters are sent, so that running, stopping or calibrating motors doesn't open a parameter dialog.
void UpdateControllerStatus(string response,int port);
updates the controller status LEDs. The parameter response contains the response from SL and the port specifies the port number (0 or 1).
void OnInitMenuPopup(CMenu *pPopupMenu, UINT nIndex,BOOL bSysMenu);
	is used for getting the command menu items (check marks) to display
correctly. Overridden from default MFC methods.
void OnDriveBtnUp(UINT nID);
is a handler to catch the state changes in the driving buttons. The message is specified by the parameter nID.
void OnDriveButton(UINT nID);
	is a handler to catch the state changes in the driving buttons.
void UpdateMotorStatus(string Motor,string response);
updates the motor status LEDs. The motor in question is defined by the Motor parameter (A, B or C). response contains the response from SL.
void SetBuffer(int buffersize);
sets the buffer size of the log according to the parameter buffersize.
int GetBuffer();
	returns the size of the log buffer.
void SetInterval(int intervalparam);
	sets the autostatus interval according to intervalparam.
int GetInterval();
	is used to get the autostatus interval.
void InitLeds();
	sets up all the status LEDs.
CMainDlg(CWnd* pParent = NULL);
is the constructor. Initializes various variables, reads the preferences from prefs.cfg.
~CMainDlg();
is the destructor. Frees all the object instances and saves the preferences prefs.cfg.
void OnLEDClick( UINT nID );
is called when a LED is clicked on. It’s used for setting the controller output states. The LED ID is specified by the parameter nID.
string GetEditLine(int nLineNumber);
	returns the line where the caret is from the Commands view.
void UpdateLogView(void);
	writes the new log line to the end of the Log view.
void UpdateTerminal(void);
	writes the new command to the end of the Commands view.
CString GetSysTime(void) const;
	returns the current time in format yyyy-mm-dd hh:mm:ss,s.
void SendString(string p_sLine, string recvd);
sends the parameter string p_sLine to the target controller and writes it to the log and to the command field. The command is identified with the recvd parameter.
void ReceiveString(string p_sLine);
	adds the string p_sLine to the log.

The protected methods are
void SetLedStatus(string hexstring, int Led,int n, CDynamicLED* p_Led);
is used to switch a led (parameter Led) on or off according to the wanted bit in hexstring. It works for an array of leds (p_Led) with size n.
void CreateParamDlg(char motorchar);
is responsible for showing the correct parameter dialog to the user. The motor in question is defined by the motorchar parameter (A, B or C).

The public attributes are
CDynamicLED m_LedMotorA[11];
	is an array containing all the status LEDs for motor A.
CDynamicLED m_LedMotorB[11];
	is an array containing all the status LEDs for motor B.
CDynamicLED m_LedMotorC[11];
	is an array containing all the status LEDs for motor C.
CDynamicLED m_LedSLIn[16];
	is an array containing all the status LEDs for the SL inputs.
CDynamicLED m_LedSLOut[16];
	is an array containing all the status LEDs for the SL outputs.
CDynamicLED m_LedSLMotors[3];
	is an array containing all the status LEDs common for all the motors.

IControl *m_pController;
	is a pointer to the Icontrol instance.
CSerialParaDlg *m_pCommsDlg;
	is a pointer to the CSerialParaDlg instance.

CSlParaDlg *m_pParamDlgA;
	is a pointer to the CSlParaDlg instance reserved for motor A.
CSlParaDlg *m_pParamDlgB;
	is a pointer to the CSlParaDlg instance reserved for motor B.
CSlParaDlg *m_pParamDlgC;
	is a pointer to the CSlParaDlg instance reserved for motor C.

bool m_bAutoSave;
	is used to check if the log is saved automatically.
bool m_bAutoStatus;
	is a variable used to check if the autostatus function is on.
bool bVelocity;
is a variable used to check whether the actual velocity or the calibration velocity should be sent to the controller.

CPrefDlg *m_pPref;
	is a pointer to the CPrefDlg instance.
CString sCommandStr;
	is a variable in which the labels of the target fields are read to.
CBrush* m_pEditBkBrush;
	is used to set the log background view to a white color.
CTermLog *m_TermLog;
	is a pointer to the CTermLog instance.

The protected attributes are used to track whether specific driving keys are currently being pressed in the keyboard.

bool m_bKeyUpDown;
is used to track whether the ‘up’ key is up or down.
bool m_bKeyDownDown;
is used to track whether the ‘down’ key  is up or down.
bool m_bKeyLeftDown;
is used to track whether the ‘left’ key is up or down.
bool m_bKeyRightDown;
is used to track whether the ‘right’ key is up or down.
bool m_bKeyNextDown;
is used to track whether the ‘page down’ key is up or down.
bool m_bKeyPriorDown;
is used to track whether the ‘page up’ key is up or down.

7.2 CDriveButton

CDriveButton is a TButton subclassed control. It calls a function in CMainDlg (see Chapter 7.1) both when it's pressed down and when it's released in order to stop the motors on the button release.

7.3 CPrefDlg

CprefDlg takes care of the Preferences dialog. It stores the maximum buffer size, the autopolling interval and the automatic log saving on/off status as three member variables and manipulates the respective variables in CMainDlg (see Chapter 7.1) directly on UpdateData.

CPrefDlg carries only standard MFC-generated methods and no attributes.

7.4 CSerialTesterApp

CserialTesterApp is the automatically generated main class of the SerialTester application. It carries only standard MFC-generated methods and no attributes

7.5 CSLParaDlg

CSLParaDlg is the parameters dialog class.

The public methods are
BOOL OnHelpInfo(HELPINFO* pHelpInfo);
is used for overriding the Windows standard help file call when F1 is pressed.
string CheckValues();
	checks if all the fields in parameter dialog are numeric. If not, it returns a string that contains the names of the fields that are not numeric. 
CSlParaDlg(CDialog* pParent, char motorparam);
sets the parameter values for a given motorparam.
void GetValues();
asks the CSLPara instance for the values of the fields and sets the values to fields. 

void UseThis(CSlPara* pPr);
is used by SlControl to establish a direct yet interface-preserving link between the dialog and CSLPara. See the same method in CserialParaDlg in Chapter 7.6.

The protected methods are
void PostNcDestroy();
	is used for getting rid of the window properly.
void SetValues();
	sends the values in the fields to the attribute m_pPara. 
afx_msg void OnButtonLoad();
	opens a Windows file dialog and asks the user for the name of the file. Then it loads the values to parameter dialog. 
afx_msg void OnButtonSave();
	checks first if all the fields are numeric. If they are, it opens a standard Windows file dialog and asks the user the name for the file. Finally the method calls the SaveMotorParamsInFile method that saves motor parameters in the given file.
afx_msg void OnButtonSend();
	checks first if all the fields are numeric. If they are, it calls the SetValues method that sends the values to the CSLPara instance. Finally it asks the CSLControl instance m_pController to send the values to the controller. 

The public attributes are
CSlPara* m_pPara;
	is a pointer to CSlPara class. 
bool m_bScaleError;
is the result of the check whether the scale value is acceptable to StressLogic.

The protected attributes are
char motor;
	indicates which motor parameters dialog is shown. 

7.6 CSerialParaDlg

CSerialParaDlg class represents the Port Settings dialog.

The public methods are
CSerialParaDlg(CWnd* pParent = NULL;)
is the standard constructor. pParent holds a pointer to the dialog’s parent, in this case the main dialog. The member variables that represent the combobox texts are set to empty strings here.

void CSerialParaDlg::UseThis(CSerialComm* pCs);
is the UseThis method, used by the overridden interpreter class, sets up a direct connection between this specialized dialog and the communication class while keeping the view/model structure and the interfaces intact. The parameter is a pointer to the communication class, and the dialog’s MFC-specific UpdateData method makes use of it while reading and setting the port setting variables stored in CSerialComm.

The public attributes are
CSerialComm *m_pComms
	This is the attribute in which the CSerialComm pointer is stored.

7.7 CEditEnter

CeditEnter is a class inherited from the CEdit class that handles the return press from a multilined editbox.

The public methods are
virtual ~CEditEnter();
	is the destructor.
void SetLines(void);
	sets the number of the lines in the editbox.
int GetLines(void);
	returns the number of the lines in the editbox.
int CharFromPosFix(CPoint pt);
replaces the Windows function  that returns the line index of the parameter (CharFromPos()).
CString GetTextAt(int line_index);
	returns the text from the parameter line index.

8. The External Code

SerialTester makes use of the following external classes.

8.1 CDynamicLED

CDynamicLED is the graphic LED class. 

The original DynamicLED component was made by V. Girish. It can be downloaded from http://www.codeguru.com/controls/DynLED.html.

It was modified for SerialTester to not blink, to draw itself properly and
to work as a custom control.

8.2 CSerial
CSerial is the serial communication helper class used extensively by CserialComm (see Chapter 6.5). It was written by Ramon de Klein (R.de.Klein@iaf.nl) and released as free software in 2002.

CSerial is the base serial class, which provides a wrapper around the Win32 API. It is a lot easier to use, because it combines all relevant calls in one single class. It allows the programmer to mix overlapped and non-overlapped calls, provides reasonable default settings and better readability.

CSerialEx adds an additional thread to the serial class, which can be used to handle the serial events. This releases the main GUI thread from the serial burden. The main disadvantage of this class is that it introduces threading to the architecture, which slightly complicates things.

CSerialWnd fits in the Windows event driven model. Whenever a communication event occurs a message is posted to the owner window, which can process the event.

CSerialMfc is an MFC wrapper around CSerialWnd, which makes the serial classes fit better in MFC based programs.

9. The Structure of the Editable Configuration Files

The software uses few configuration files. The chapter describes the meaning and the structure of these files.

In addition to these, SerialTester uses the files port.cfg and prefs.cfg. These two files will not be covered here. They are for SerialTester’s internal use and should never be edited by the user. However note, that manually deleting the file port.cfg will safely reset SerialTester’s port settings to their default values. The same applies for the file prefs.cfg and the settings in the Preferences dialog.

9.1 The commands.ini file

This is the only file required by the software. It can’t be changed with the software, only manually.

In the file there is one command per line. First there is the command used by the software, which is separated with a space from the command sent to the device. For an example, one line might look like this:

init IN

9.2 The motor.par file

The file name is selectable. To the files with the extension .par you can save the motor parameters and load them to the software. The file can contain also comment lines which start with the semicolon sign (;).

In every line of the file there is the name of the parameter, then the equal sign (=) and after that the value of the parameter. Extra spaces don’t make any difference.
For an example, one line might look like this:

MOTOR_A_ACCELERATION=	10000

9.3 The lastmotor.par file

The file where the software automatically saves the last used parameters when the program was closed. The structure is equal to the motor.par file.

10. Testing, Test Results and Known bugs

The project group carried out the test cases described in the Testing Plan [4]. The software has passed the tests. The customer reported some minor bugs after carrying out the tests and these bugs were fixed.

The tests were carried out twice, because at the first time some of the test cases were failed. At the second time the tests were also carried out in a computer that doesn’t contain the developing tool. Both testing times are documented in the Test Report [5].

At the moment there is only one known bug in the software. When giving a non-numeric or a too big value in the Preferences dialog from the Setup menu, the program shows two error messages.

11. Further development

This chapter introduces a few ideas to further develop SerialTester.

11.1 Support for Any Number of Motors

This feature was originally included in the SerialTester General Specification [3]. It was left out of the program during the project to simplify the coding process. The decision was made by the Stresstech representatives. 

In the current software, the number of motors is hard-coded to three. The feature should not be too hard to implement, because the class structure was originally planned to include any number of motors.

11.2 Support for More Controllers

At the moment, SerialTester only supports one controller, the StressLogic. Adding new controller functionality could be done by adding the required functions to the IControl class. The implementation could be added to the SLControl class. The command base is already dynamic.

11.3 TCP/IP Communication

The software communicates with the controller via the RS232 bus. In the beginning of the project, the client requested that SerialTester’s class structure was to be built in a way that would help implementing TCP/IP instead of RS232. By rewriting the CSerialComm class, the communication interface can changed to support TCP/IP or any other protocol.

11.4 Dynamic Shortcut Keys

During the project, the representatives of the client said that it would be good if they could adjust the shortcuts themselves whenever they wanted to. This feature was left out due to lack of time. It could be done similarly as the dynamic command base, i.e. by using text files to read the sent commands from.

12. Conclusion

SerTi project implemented software for testing and monitoring StressLogic and other equipment. This document described how the software and its components were implemented.

The original “SerialTester General Specification” [3] was provided to the SerTi group by Stresstech. In the planning phase of the project, those requirements were expanded in cooperation with Stresstech representatives (see “SerTi Project Requirement Specification” [6]).

Constant fine-tuning of the requirements took place during the project. The only more significant change was the limitation of the motors supported by the application to three.

The final application meets all the requirements agreed to during the project. It also partially exceeds them. For example in the case of the Commands and Log views who have more functionality than required.

References

[1]	Hoff Todd, “C++ Coding Standard, an Edited Version”, Stresstech Oy, 2002.

[2]	Pietilä Ilkka and Urtamo Ilkka, ”SL Comm. Specs”, Stresstech Oy, 2002.

[3]	Urtamo Ilkka, “SerialTester General Specification”, Stresstech Oy, 2002.

[4]	Blomqvist Susanna, Korhonen Antti, Mylläri Heikki and Pakari Pekka, “SerialTester Testing Plan”, University of Jyväskylä, Department of Mathematical Information Technology, 2003.

[5]	Blomqvist Susanna, Korhonen Antti, Mylläri Heikki and Pakari Pekka, “SerialTester Test Report”, University of Jyväskylä, Department of Mathematical Information Technology, 2003.

[6]	Blomqvist Susanna, Korhonen Antti, Mylläri Heikki and Pakari Pekka, “SerTi Project Requirement Specification”, University of Jyväskylä, Department of Mathematical Information Technology, 2003.