BS2 not listening to a linux program
jb9
Posts: 7
I'm trying to interface a BS2 to a computer and use a C program to talk to the BS2, but when I send data from a C program over serial, the BS2 doesn't see/process it.
I've tried every combination of communication I can think of...
1) C program to/from another PC over serial
2) minicom on the PC to/from the BS2
3) C program FROM the BS2
All of those work. The only combination that doesn't work is data from a C program on the PC to the BS2.
When I say "PC" here, I've tried all of these combinations with a raspberry pi as well as linux running in VirtualBox on a win7 PC, with the same results on both (minicom works, C program doesn't).
I've stripped down the code to the basics and I'll post it below. Any thoughts on something I could be overlooking?
thanks,
JB
BS2 program:
C Program (adapted from 'Serial Programming HOWTO' example):
I've tried every combination of communication I can think of...
1) C program to/from another PC over serial
2) minicom on the PC to/from the BS2
3) C program FROM the BS2
All of those work. The only combination that doesn't work is data from a C program on the PC to the BS2.
When I say "PC" here, I've tried all of these combinations with a raspberry pi as well as linux running in VirtualBox on a win7 PC, with the same results on both (minicom works, C program doesn't).
I've stripped down the code to the basics and I'll post it below. Any thoughts on something I could be overlooking?
thanks,
JB
BS2 program:
sData0 VAR Byte START: DO SERIN 16, 16468, [sData0] ' Do something interesting to indicate that I saw data LOOP
C Program (adapted from 'Serial Programming HOWTO' example):
#include <sys/types.h> #include <sys/stat.h> #include <string.h> #include <fcntl.h> #include <termios.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define BAUDRATE B9600 #define MODEMDEVICE "/dev/ttyS0" #define _POSIX_SOURCE 1 /* POSIX compliant source */ main(int argc, char **argv) { int fd,c, res; struct termios oldtio,newtio; char buf[255]; char readbuf[255]; /* Open modem device for reading and writing and not as controlling tty because we don't want to get killed if linenoise sends CTRL-C. */ fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY); if (fd <0) {perror(MODEMDEVICE); exit(-1); } tcgetattr(fd,&oldtio); /* save current serial port settings */ bzero(&newtio, sizeof(newtio)); /* clear struct for new port settings */ /* BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed. CRTSCTS : output hardware flow control (only used if the cable has all necessary lines. See sect. 7 of Serial-HOWTO) CS8 : 8n1 (8bit,no parity,1 stopbit) CLOCAL : local connection, no modem contol CREAD : enable receiving characters */ // newtio.c_cflag = BAUDRATE | CRTSCTS | CS8 | CLOCAL | CREAD; newtio.c_cflag = BAUDRATE | CS8 | CLOCAL | CREAD; /* IGNPAR : ignore bytes with parity errors ICRNL : map CR to NL (otherwise a CR input on the other computer will not terminate input) otherwise make device raw (no other input processing) */ newtio.c_iflag = IGNPAR | ICRNL; /* Raw output. */ newtio.c_oflag = 0; /* ICANON : enable canonical input disable all echo functionality, and don't send signals to calling program */ newtio.c_lflag = ICANON; /* initialize all control characters default values can be found in /usr/include/termios.h, and are given in the comments, but we don't need them here */ newtio.c_cc[VINTR] = 0; /* Ctrl-c */ newtio.c_cc[VQUIT] = 0; /* Ctrl-\ */ newtio.c_cc[VERASE] = 0; /* del */ newtio.c_cc[VKILL] = 0; /* @ */ newtio.c_cc[VEOF] = 4; /* Ctrl-d */ newtio.c_cc[VTIME] = 0; /* inter-character timer unused */ newtio.c_cc[VMIN] = 1; /* blocking read until 1 character arrives */ newtio.c_cc[VSWTC] = 0; /* '\0' */ newtio.c_cc[VSTART] = 0; /* Ctrl-q */ newtio.c_cc[VSTOP] = 0; /* Ctrl-s */ newtio.c_cc[VSUSP] = 0; /* Ctrl-z */ newtio.c_cc[VEOL] = 0; /* '\0' */ newtio.c_cc[VREPRINT] = 0; /* Ctrl-r */ newtio.c_cc[VDISCARD] = 0; /* Ctrl-u */ newtio.c_cc[VWERASE] = 0; /* Ctrl-w */ newtio.c_cc[VLNEXT] = 0; /* Ctrl-v */ newtio.c_cc[VEOL2] = 0; /* '\0' */ /* now clean the modem line and activate the settings for the port */ tcflush(fd, TCIFLUSH); tcsetattr(fd,TCSANOW,&newtio); sprintf(buf," CMD0 %c%c ",0x0d,0x0A); res = write(fd,buf,strlen(buf)); printf("wrote:%s:%d:%d:\n", buf, strlen(buf),res); /* restore the old port settings */ tcsetattr(fd,TCSANOW,&oldtio); }
Comments
Later on, I got it working, sort of. I set aside the C program and wrote a minicom script to do the same thing (open the serial port and send some characters), thinking that minicom definitely has all the right serial port settings. That didn't work initially, but eventually I inserted a 100ms sleep between each character sent. This caused it to work perfectly. I tried a similar inter-character delay in the C program, but so far that doesn't work. I can make this minicom hack work, but I was hoping to better understand why it's happening because this sounds more like a problem with serial port settings.
thanks,
JB
That how-to, if it's the same one I looked at, is like ten years old. Could it be outdated? As in some "under the hood" changes were made in linux which breaks the sample code? I had a similar experience where the sample code didn't work but I only made a half-baked attempt at it before getting sidetracked to something else.
Secondly, does it have to be a C program? Perl and Python both have serial comm modules and I know for a fact the Python one works (I'm 95% sure the Perl one does too).
eric
Also, I don't know if you knew this or not, but any data you send to the BASIC Stamp Module via the programming port is echoed back to the sender.
With the Propeller, I used something like this:
That just echos the characters as fast as possible back to the PC. With this, I found that the Propeller required, at most, a 1ms delay between each character. I couldn't get my terminal program (picocom with "ascii-xfr -s -c 0") to send the characters with a non-integer millisecond delay, so I couldn't try .5ms or so.
Anyway, I'd setup something similar with the BS2 and see what the minimum delay is between characters.
How is that done? I can see two options:
1. Done is hardware (result: no matter what the BS2 is doing, it will always respond with the character).
2. Done in the interpreter (result: only when it's SERIN'ing will it echo the character).
Anyway, I didn't know that. Still, my previous method will still work: you just look for doubles of each character.
To answer the question above, yes, I really do want this to work in C. I've been programming in C for almost 15 years and have only limited experience with those other languages. I tried this in perl and it isn't working.
In the code I pasted originally, I used pin 16, but I've tried pin 16 for in/out as well as other pins (8/9, maybe) with the same result. I'm back to using pin 16 now, though because I ended up with 3 serial cables coming out of my BoE and I only have 2 proper connectors. The 3rd was breadboard jumper wires going into a DB9, so a little flaky, to say the least. :-)
By the way, one other test I did was to echo output to the device, e.g. 'echo CMD0001 > /dev/ttyUSB0', but no luck there, either.
Editing to add one other note:
I reduced the inter-character delay in my minicom script to 1 ms and it still worked. When I eliminated the delay, it stopped working again.
Also, you can try your serial code by looping back in hardware your serial port connection. You should be able to remove your BS2, and put a wire between the RX pin and the TX pin (double check the schematics, first!). Then, you can take the BS2 variable out of the equation.
I've definitely narrowed it down to a BS2 issue. The same methods successfully send bytes to my laptop (via its own USB/serial adapter) as well as a desktop PC with a built-in serial port. The BS2 is the only one which won't receive them.
There is a 4.7K resistor between the SIN/SOUT pins causing the echo. It is done in hardware and is used by the IDE (required) whereas loopback is not required.
First off the "WAIT" instruction is flakey at 9600 baud, try your initial tests at 4800.
See if the SERIN instruction will recieve the "CMD" string without the other data to begin with, also when sending data from your C program always try and append a carriage return to the data. (decimal 13)
When transmitting to the BS2 clear the serial port buffer before sending, this will clear any characters that may have been echoed back and prevent them from mixing in with the new data.
One last thing I would use the SERIN with a timeout to prevent it sitting there and hanging the program because it has not received a complete packet.
Jeff T.