GetMoving C++ K8097 problem

Hi all,

I am trying to write some code in order to execute two Move commands one after another on a k8097 card in C++ using the mtrapi32.dll. To do so I check GetMoving() of the appropriate motor in an empty while loop. The problem is that no matter how I try to check the motor status via GetMoving function, it always returns 0. I have read a similar topic about this issue and thus tried to declare the return value of the GetMoving as bool, int, unsigned int, unsigned long, but it always fails to return 1. On the other hand, I have no problem checking the connection status

#include <iostream>
#include <windows.h>
#include <string>
#include <stdlib.h>


using namespace std;


HINSTANCE MyDll;

int main() {
	//string DLLPath= "mtrapi32.dll";
	MyDll= LoadLibrary("mtrapi32.dll");

	
	bool WINAPI (*Connect) (char *cPort, unsigned long ulMotorCnt);
	void WINAPI (*Disconnect)(void);
	int WINAPI (*GetMoving)(unsigned long ulMotorIndx);
	bool WINAPI (*Connected) ();
	void WINAPI (*Move)(unsigned long ulMotorIdx, unsigned long ulSteps, unsigned long ulDirection, unsigned long Speed);

	*(FARPROC*)&Connect = GetProcAddress(MyDll, "SMCConnect");
	*(FARPROC*)&GetMoving =GetProcAddress(MyDll, "SMCGetMoving");
	*(FARPROC*)&Connected = GetProcAddress(MyDll, "SMCConnected");
	*(FARPROC*)&Move = GetProcAddress(MyDll, "SMCMove");
	*(FARPROC*)&Disconnect = GetProcAddress(MyDll, "SMCDisconnect");

	Connect("COM3", 4);
	
	if (Connected())
	{
		Move(0, 2000, 1, 30);
                
		// the following GetMoving returns 0 even if I postpone the calling with Sleep(100)
		while (GetMoving(0)){}

		Move(0, 1000, 0, 30);		
	}
	Disconnect();
	FreeLibrary(MyDll);
	return 0;
}

The code above makes the motor execute only the Move(0, 1000, 0, 30) command.

Console applications will not work with the DLL. GetMoving will only return true if it has actually received a message from the K8097 that the motor has stopped moving. But, a console application does not allow the DLL to receive anything from the K8097.

I don’t quite understand, what you mean. Doesn’t the GetMoving() function return the status of the motor? I mean, it is a function and it returns a value. To quote the documentation of the library “Returns True if the motor is moving, False otherwise.” Moreover, whenever I use the function Connected(), to check the connection status, it returns true. So I am receiving something from the K8097 via the console application. The same goes with the function GetInputCount(), which returns the proper value of 6. On the other hand, I can not receive the Torque status, having an analogical problem as with the GetMoving method.

After consideration, I admit that waiting in an empty loop until the Move command is executed isn’t elegant at all. Should I use some kind of a event listener? I suppose that your reply actually suggests that. Am I right? If so, I would be very much thankful for information about how to receive such messege via a listener

[quote=“Maxiim”]I don’t quite understand, what you mean. Doesn’t the GetMoving() function return the status of the motor? I mean, it is a function and it returns a value. To quote the documentation of the library “Returns True if the motor is moving, False otherwise.”[/quote]GetMoving will only return true if it has actually received a message from the K8097 that the motor is moving. In your console application, you can not receive any data, thus the library does not know that the motor is moving.

[quote]Moreover, whenever I use the function Connected(), to check the connection status, it returns true.[/quote]You are indeed connected

[quote]So I am receiving something from the K8097 via the console application.[/quote]You are not

[quote]The same goes with the function GetInputCount(), which returns the proper value of 6[/quote]This is a fixed value

[quote]On the other hand, I can not receive the Torque status, having an analogical problem as with the GetMoving method.[/quote]The torque status must also be received from the K8097.

All of this has been a choice between ease of use and complexity. The protocol is open though and communication is very simple to achieve (serial port).

Ok, I think I get it. Is there a tutorial how to communicate with the card properly?

Currently we only have what is supplied with the installer (VB.NET examples, protocol description, etc.)

I understand what you want to do and there has been a library that could chain move commands etc, but it was too complex for regular users.

In C++, you can open a serial port with CreateFile. Something similar to this:

HANDLE WINAPI Connect(LPCTSTR szPort)
{
	HANDLE hComm;
	DCB    dcb;

	hComm = CreateFile(
		szPort,
		GENERIC_WRITE,
		0,
		NULL,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL,
		NULL
	);

	if (INVALID_HANDLE_VALUE == hComm)
		return FALSE;

	FillMemory(&dcb, sizeof(dcb), 0);
	dcb.DCBlength = sizeof(dcb);
	if (!BuildCommDCB("2400,n,8,1", &dcb)) // TODO: change to correct baud rate
		return FALSE;

	if (!SetCommState(hComm, &dcb))
		return FALSE;

	return hComm;
}

Then use WriteFile to write data to the port and use ReadFile to read data from the port.

HANDLE handle = Connect("\\.\COM1");
WriteFile(handle, ...);

Has been? Is it still attainable?

I have read about communicating through serial ports. I suppose I do not need to open the port after calling the Connect() function, right?

are those the proper communication parameters?

In order to execute Move() commands one after another should I continously read the port in a while loop until receiving feedback from the card?
How will the information look like?

[quote]I have read about communicating through serial ports. I suppose I do not need to open the port after calling the Connect() function, right?[/quote]To Windows, a serial port is similar to a file, so CreateFile opens the serial port for reading and writing.

[quote]BuildCommDCB(“2400,n,8,1”, &dcb)
are those the proper communication parameters?[/quote]This probably already works since the baud rate is not important for a virtual serial port.

[quote]In order to execute Move() commands one after another should I continously read the port in a while loop until receiving feedback from the card?[/quote]Indeed, do some stuff, read the feedback from the card, do some other stuff, read the feedback

[quote]How will the information look like?[/quote]You’ll have to read the protocol PDF. It’s bits and bytes, but C is very good at that.

There is plenty of information on the internet about serial ports, in any programming language, don’t hesitate to consult it

And where can I find the protocol PDF?

This is the protocol document from the developer
velleman.be/images/tmp/K8097_PROTOCOL.txt

So I wrote something. The following function does not throw any mistakes to the console, but still it does not read any data from the port. Any ideas why? Should I modify the timeout?


#include <iostream>
#include <windows.h>
#include <string>
#include <stdlib.h>
#include <bitset>


using namespace std;


HANDLE WINAPI ConnectPort(LPCTSTR szPort)
{
   HANDLE hComm;
   DCB    dcb;

   hComm = CreateFile(
      szPort,
      GENERIC_READ | GENERIC_WRITE,
      0,
      NULL,
      OPEN_EXISTING,
      FILE_ATTRIBUTE_NORMAL,
      NULL
   );
   if(hComm==INVALID_HANDLE_VALUE){
	   if(GetLastError()==ERROR_FILE_NOT_FOUND){
		   cout << "serial port does not exist" << endl;
	   }
	   else
	   {
		   cout << "some other error occurred." << endl;
	   }
	   return FALSE;
   }

   FillMemory(&dcb, sizeof(dcb), 0);
   dcb.DCBlength = sizeof(dcb);
   if (!BuildCommDCB("2400,n,8,1", &dcb)) // TODO: change to correct baud rate
   {
	   cout << "BuildCommDCB failed" << endl;
	   return FALSE;
   }


   if (!SetCommState(hComm, &dcb))
   {
   	   cout << "SetCommState failed" << endl;
   	   return FALSE;
   }

   return hComm;
}

int main() {
	
	HINSTANCE MyDll;

	MyDll= LoadLibrary("mtrapi32.dll");

	bool WINAPI (*Connect) (char *cPort, unsigned long ulMotorCnt);
	void WINAPI (*Disconnect)(void);
	int WINAPI (*GetMoving)(unsigned long ulMotorIndx);
	bool WINAPI (*Connected) ();
	void WINAPI (*Move)(unsigned long ulMotorIdx, unsigned long ulSteps, unsigned long ulDirection, unsigned long Speed);
	int WINAPI (*GetInputCount)();
	int WINAPI (*SetTorque)(unsigned long ulMotorIndx, bool enabled);
	int WINAPI (*GetTorque)(unsigned long ulMotorIndx);

	*(FARPROC*)&Connect = GetProcAddress(MyDll, "SMCConnect");
	*(FARPROC*)&GetMoving =GetProcAddress(MyDll, "SMCGetMoving");
	*(FARPROC*)&Connected = GetProcAddress(MyDll, "SMCConnected");
	*(FARPROC*)&Move = GetProcAddress(MyDll, "SMCMove");
	*(FARPROC*)&Disconnect = GetProcAddress(MyDll, "SMCDisconnect");
	*(FARPROC*)&GetInputCount = GetProcAddress(MyDll, "SMCGetInputCount");
	*(FARPROC*)&SetTorque = GetProcAddress(MyDll, "SMCSetTorque");
	*(FARPROC*)&GetTorque = GetProcAddress(MyDll, "SMCGetTorque");

	Connect("COM3", 4);

	Move(0, 1000, 1, 30);

	Disconnect();

//------------------------------------------------------------------------------------------------
				HANDLE handle = ConnectPort("COM3");
				if (handle != FALSE)
				{
					int n=7;
					char szBuff[n + 1];
					for (int i=0; i<n; i++)
					{
						szBuff[i]=255;
					}
					DWORD dwBytesRead = 0;
					if(!ReadFile(handle, szBuff, n, &dwBytesRead, NULL))
					{
						cout << "Can not read from port" << endl;
					}
					else
					{
						for (int i=0; i<n; i++) //printing the buffer bitwise
						{
							std::bitset<8> x(szBuff[i]);
							cout << x  << " ";
						}
					}
				}
				cout << endl;
//------------------------------------------------------------------------------------------------

	FreeLibrary(MyDll);

	return 0;
}

Try reading in a loop

Mind that the K8097 doesn’t send anything if nothing has happened (motor started moving, etc)

Try writing this, it is a command to move the first motor 300 steps to the left, speed 30:

unsigned char buffer[] = {0xFF, 0x1C, 0x2C, 0x1, 0x0, 0x0, 0x1E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x99, 0x0}; // = 28 bytes

The communication had been working. It was a foolish mistake - I was chcecking only the last byte of the bufffer.
Yet, there is a slight problem that occured while reading the port in a loop with a Sleep() interval. Sometimes the function can not read anything so the buffer stays the same (the dwBytesRead variable is 0). To obtain the mentioned functionality I initialize bytes of the buffer with the value of 255 (I assume that after sending the Move() command the motor is actualy running).
I would be grateful for a more elegant way of solving the problem.

dwBytesRead tells you how many bytes have been read, so you will need to use that to collect data and make sense out of it

[quote]Try writing this, it is a command to move the first motor 300 steps to the left, speed 30:

Code:
unsigned char buffer[] = {0xFF, 0x1C, 0x2C, 0x1, 0x0, 0x0, 0x1E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x99, 0x0};
// = 28 bytes[/quote]

How do I code the number of steps in terms of the bytes order? I see from above how to code a 2byte number, but how does it go with bigger numbers (e.g. 300 000 000 - hex=11E1A00)? Is it little or big endian?

Hi all. I have succesfully written a console application in c++ eclipse which is able to complete several Move() commands. I don’t know how elegant my solution is but I use a loop in which I read the status command and check the appropriate motor status and then wait some time. In a console this works fine.

Now I am working on a gui based version permiting the user to define a changable set of commands. The gui app is written in Visual Studio 2013 in c++. The Move function looks as follows:

void Move(int motor, int steps, int direction, int speed, System::IO::Ports::SerialPort^  serialPort)
		{
				 //forming the message sent to the motor driver
				 array<unsigned char, 1> ^WriteBuffer = { 0xFF, 0x1C, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 };
				 //steps
				 WriteBuffer[2 + motor * 6] = steps & 0xFF;
				 WriteBuffer[3 + motor * 6] = (steps >> 8) & 0xFF;
				 WriteBuffer[4 + motor * 6] = (steps >> 16) & 0xFF;
				 WriteBuffer[5 + motor * 6] = (steps >> 24) & 0xFF;
				 //speed
				 WriteBuffer[6 + motor * 6] = speed & 0xFF;
				 //direction
				 WriteBuffer[7 + motor * 6] = direction & 0xFF;

				 //message checksum
				 unsigned char checksum = 0x1C;
				 for (int i = 0; i<6; i++)
				 {
					 checksum += WriteBuffer[2 + motor * 6 + i];
				 }
				 checksum = (~checksum) + 1;
				 WriteBuffer[26] = checksum;
// sending the message
				 serialPort->Write(WriteBuffer,0,WriteBuffer->Length);

				 array<System::Byte, 1> ^ReadBuffer = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
				 Sleep(100);
				 int BytesRead = 7;
				 int remainder = 1;

				 while (remainder == 1))
				 {
					 Sleep(50);
					 
					 BytesRead = serialPort->Read(ReadBuffer, 0, ReadBuffer->Length);
					 remainder = (ReadBuffer[2] >> motor) % 2;

				 }
}

Yet, I have a problem that after the first reading I get the ReadBuffer equal to:

ReadBuffer ={0xFF, 0x7, 0x0, 0x0, 0xBF, 0x3A, 0x0}

So my question is why do i get a 0x00 in the third byte of status command while the motor is running?