Problem with C++ access to SSC8

I’m having trouble accessing the COM3 port to control a Serial-8 Servo Controller.

My code is below, I used pieces of code found in the internet and customized it.

	HANDLE comPort = 0;
	DCB comSettings = {0};
	TCHAR *portName = TEXT("COM3");
	comPort = CreateFile(portName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
	
	if(comPort == INVALID_HANDLE_VALUE) {
		cerr << "Error opening COM port!" << endl;
		return 1;
	}

	if(GetCommState(comPort, &comSettings)) {
		comSettings.BaudRate = CBR_19200; //9600;
		if(!SetCommState(comPort, &comSettings)) {
			cerr << "ERROR SETCOMMSTATE!!!!" << endl;
		};
	}

	COMMTIMEOUTS timeouts={0};
	timeouts.ReadIntervalTimeout=1000;
	timeouts.ReadTotalTimeoutConstant=1000;
	timeouts.ReadTotalTimeoutMultiplier=1000;
	timeouts.WriteTotalTimeoutConstant=1000;
	timeouts.WriteTotalTimeoutMultiplier=1000;

	if(!SetCommTimeouts(comPort,&timeouts)){
		cerr << "Timeout Setting Error\n";
		return 1;
	}

	unsigned short int buffer[6];
	DWORD bytesWritten;

	/*buffer[0] = 255;
	buffer[1] = 0;
	buffer[2] = 25;*/

	unsigned short int temp;
	unsigned char pos_hi,pos_low;

	int angle = 3500;

	temp=angle&0x1f80;
	pos_hi=temp>>7;
	pos_low=angle & 0x7f;

	buffer[0]=0x80;//start byte
	buffer[1]=0x01;//device id
	buffer[2]=0x04;//command number
	buffer[3]=0x07;//servo number
	buffer[4]=pos_hi;//data1
	buffer[5]=pos_low;//data2

	BOOL teste = false;

	teste = WriteFile(comPort, &buffer, 6, &bytesWritten, NULL);
	FlushFileBuffers(comPort);

	if(teste)
		cout << "OK!!!" << endl;

	CloseHandle(comPort);

All this code is in my main function, there is no extra code beyond that.

I can access the COM port, but when I execute the WriteFile function, none of my servos move. And the function returns TRUE, as if it had sent the bytes correctly.

If anyone can help me, I’d be grateful.
Thanks!

Looks like you need to change the type of your buffer array from “unsigned short int” to “unsigned char”.

Short ints are two bytes (at least on Win32 systems), so even though you’re filling your array with {0x80,0x01,0x04,0x07,0x1B,0x2C}, when you pass the pointer to your array to WriteFile and tell it to write six bytes starting there, what actually comes out is {0x80,0x00,0x01,0x00,0x04,0x00} (the bytes are stored in little endian format, with the lest significant byte first).

Everything else looks good, does that fix it?

-Adam

Hi Adam!
Thanks for your reply!
Actually, “unsigned char” was the first thing I tried, but I compared a working C# code during debug with my C++ code and I saw differences in the values being passed in the buffer. As the C# code used byte data type, and there is no byte in C++, I tried short.

Keeping it simple: it doesn’t work with “unsigned char” or “unsigned short int”.

Any more suggestions?
Thank you!

Oh, by the way, I’m using Visual C++ 2008.

Hmm, that’s very strange. It compiles and runs fine for me if I just change that type of buffer to unsigned char: “unsigned char buffer[6];”

I’m using DevC++, an open-source IDE. Hey, and your pos_hi and pos_low variables are unsigned chars! Looking at the MSDN website here, it looks “unsigned char” should be allowed, but you might also try “unsigned __int8”.

If nothing will work, you could keep the type as short, and merge your byte pairs.

Visual C++ always causes me trouble!

-Adam

Hi again, Adam!

I compiled the code in Code::Blocks, which use GCC compiler, and it didn’t work as well. I tried a code of yours I found in this forum (poluloserialservocontrol.c, version 1.0, Adam Borrell) in GCC and VC++, and it didn’t work as well.

As soon as it opens the COM port, the yellow LED in the controller goes off. In the C# code I have here, it goes off only when the command is sent to the port, so this made me curious. What could I be doing wrong opening the port? Besides, what could be different in my configuration, since it’s the same code you said it worked with you. I’m using Windows XP.

And “unsigned __int8” didn’t work as well :confused:
I may try merge the bits as you said, but I have to figure out how to do this, I never did it before.

Thanks again.

My demo code (this one?) sends out commands to send all servos to their neutral positions on startup, then as an example it pauses for a second, then moves servo 0 a little off center (and then gives you keyboard control). This would make the yellow light go out (and should be making the green light blink a little). If you’re not seeing any of this do you have the mode selection and DTR/RTS reset jumpers removed?

Wow, I can’t even get this to build in Visual Studio (2005), can you post your complete code? Are you trying to build this as a Win32 console application?

It occurs to me that a simpler fix would be to leave your buffer array as a short int, and write one byte at a time in a loop, like this:

for(int i=0;i<6;i++){
	teste = WriteFile(comPort, &buffer[i], 1, &bytesWritten, NULL);
}

It’s a little cumbersome in the execution, but for such a short string it shouldn’t cause any problems, and it should get things going!

-Adam

My mode selection jumper is removed, but the DTR/RTS is not. It is selected as RTS. When I remove the DTR/RTS jumper and plug the cable in the PC, the red light goes on and the green light keeps flashing quickly.

I tried the for loop you said above with short int, unsigned __in8 and unsigned char. None of them worked.
My complete code is below.

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

using namespace std;

int main()
{
	HANDLE comPort = 0;
	DCB comSettings = {0};
	TCHAR *portName = TEXT("COM3");
	comPort = CreateFile(portName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);

	if(comPort == INVALID_HANDLE_VALUE) {
		cerr << "Error opening COM port!" << endl;
		return 1;
	}

	if(GetCommState(comPort, &comSettings)) {
		comSettings.BaudRate = CBR_19200; //9600;
		comSettings.fDtrControl = 0;
		comSettings.fRtsControl = 1;
		comSettings.ByteSize = 8;
		comSettings.StopBits = ONESTOPBIT;
		comSettings.Parity = NOPARITY;
		if(!SetCommState(comPort, &comSettings)) {
			cerr << "ERROR SETCOMMSTATE!!!!" << endl;
		};
	}

	COMMTIMEOUTS timeouts={0};
	timeouts.ReadIntervalTimeout=50;
	timeouts.ReadTotalTimeoutConstant=50;
	timeouts.ReadTotalTimeoutMultiplier=10;
	timeouts.WriteTotalTimeoutConstant=50;
	timeouts.WriteTotalTimeoutMultiplier=10;

	GetCommState(comPort, &comSettings);

	if(!SetCommTimeouts(comPort,&timeouts)){
		cerr << "Timeout Setting Error\n";
		return 1;
	}

	unsigned short buffer[6];
	DWORD bytesWritten;

	/*buffer[0] = 255;
	buffer[1] = 0;
	buffer[2] = 25;*/

	unsigned short temp;
	unsigned short pos_hi,pos_low;

	int angle = 3500;

	temp=angle&0x1f80;
	pos_hi=temp>>7;
	pos_low=angle & 0x7f;

	buffer[0]=0x80;//start byte
	buffer[1]=0x01;//device id
	buffer[2]=0x04;//command number
	buffer[3]=0x00;//servo number
	buffer[4]=pos_hi;//data1
	buffer[5]=pos_low;//data2

	BOOL teste = false;

	for(int i=0;i<6;i++) {
		teste = WriteFile(comPort, &buffer[i], 1, &bytesWritten, NULL);
	}
	FlushFileBuffers(comPort);

	if(teste)
		cout << "OK!!!" << endl;

	CloseHandle(comPort);
}

Adam, I managed to get your code working now!
I had to remove the DTR/RTS jumper AFTER plugin the cable in the PC (I’m using a serial-to-usb converter cable).
I tested my code under the same conditions, and it worked as well. Thank God, my brain was collapsing haha.

Do you know why it only works under this conditions?
Thank you very much for all your help!

It sounds like the adapter is sending out some garbagey-bytes when at some point, which is confusing your servo controller, so any kind of reset (power-cycling would probably work too) will make it happy again. If you want to look into it, you could try using the software reset at the beginning of your code by putting the reset jumper to the RTS side and starting with something like:

EscapeCommFunction(comPort,CLRRTS);//clear RTS pin
sleep(10);
EscapeCommFunction(comPort,SETRTS);//set RTS pin

I may have the SET and CLEAR commands backwards though, I don’t have one of the software resettable servo controllers.

Glad you got it working!

-Adam

The “EscapeCommFunction” thing worked pretty well.

Thanks for your patience, Adam. It helped a lot.

Excellent!

So did it work in that order then? With CLRRTS pulling the servo controller into reset and SETRTS bringing it back into operation again? I don’t have one of the resettable ones myself, and I’ve been wondering about this.

-Adam

Actually, it worked executing just the CLRRTS. If I execute the SETRTS after CLRRTS, I get back to my original situation, when it didn’t worked. As soon as I executed the CLRRTS, the yellow light went on. When the execution control passed by SETRTS, the yellow light went off again, and the problem returned, so I used just the CLRRTS.