Serial control and waiting for a rsponse - c

I am using an esp 8266 to control an Epson projector over its serial line. I am using a computer and OSC to call functions on the esp that run Epson serial commands. The command I'm having trouble implementing is zoom. The Epson Serial command to zoom the lens in 1 "click" is
ZOOM INC\r
Once the projector executes the code it returns either a : or :ERR. In my function it is suppose to execute the command several times depending on what the user inputs. In my function I want to wait until the projector responds before executing the command again, and this is what I have been trying.
void zoom_inc(OSCMessage &msg){
OSCMessage qLab_msg("/cue/p0/name");
Serial.print("Zoom ");
lock = 1;
char cmd[10] = "ZOOM INC\r";
if(msg.getInt(0) < 0){
cmd[5] = 'D';
cmd[6] = 'E';
}
int high = (abs(msg.getInt(0)) > 50)? 50 : abs(msg.getInt(0));
Serial.print(cmd);
Serial.print(" ");
Serial.print(high);
Serial.println(" times");
unsigned long startTime;
unsigned long currentTime;
unsigned long diff;
boolean response = false;
String readString; //create response string
for(int i = 0; i < high; i++){
projSerial.write(cmd);
startTime = millis();
while(!response){
while (projSerial.available() > 0) { //look for projector response
Serial.write(projSerial.read());
delay(3);
char c = projSerial.read();
readString += c;
}
readString.trim(); //clean projector response
if(readString.length() == 1){
Serial.println("Read Data");
Serial.println(readString.length());
Serial.println(readString);
Serial.println("------------------------------------");
response = true;
}
currentTime = millis();
diff = currentTime - startTime;
if(diff >= 5000 || diff < 0){
Serial.println("Timeout");
response = true;
}
}
delay(200);
}
qLab_msg.add("Zoom Incremental");
Udp.beginPacket(qLabIP, qLabPort);
qLab_msg.send(Udp);
Udp.endPacket();
qLab_msg.empty();
}
This doesn't work because it only does about half of what its suppose to. For example if the user sends 30 it only does 14

This looks suspicious:
Serial.write(projSerial.read());
delay(3);
char c = projSerial.read();
readString += c;
You've just read two characters from projSerial. One got echoed to your main serial port, and the other will be added to the string. Losing approximately every other character from the projector's response seems consistent with getting only about half the steps you expected.
Try:
char c = projSerial.read(); // read it just once
Serial.write(c);
readString += c;
I assume the delay(3) was from an earlier guess.

Related

How can I have a conditional statement that performs two tasks? first one and then the other in a loop

So I am trying to code a program in arduino that does a task for 2 minutes and then another task for 5 mins. first one and then the other in a loop until a different condition is met.
Ive been trying to do this with if statements and while loops but im getting lost in the time part i think
//Pneumatic feed system
double minute = 1000*60;
double vibTime = 2 * minute; //2 mins
//double vibTime = 5000;
double execTime = millis();
double waitTime = 5 * minute; //time waits between vibrating
//double waitTime = 10000;
void DoPneuFeed() {
//Serial.print("Delta:");
//Serial.println(millis()-execTime);
if(Temp_Data[T_9] < 500)
{
if(execTime + vibTime < millis())
{
//turn on vibration for 2 mins
execTime = millis();
Serial.println("VIBRATING");
}
if(execTime + waitTime < millis())
{
//turn off vibration for 5 mins
execTime = millis();
Serial.println("WAITING");
}
}
if(Temp_Data[T_9] > 500)
{
relayOff(3);
relayOff(7);
}
}
void PneuFeed()
{
if(execTime + vibTime > millis())
{
//air pressure open
relayOn(3);
//vibrator on
relayOn(7);
}
else if(execTime + waitTime > millis())
{
relayOff(3);
relayOff(7);
}
}
I want to turn on the vibration mode for 2 mins and then turn it off for 5 mins. as long as the Temp_Data(T_9) < 500. if it is greater than 500 it should stay off.
Without going into the specifics of your code (since I cannot build it to test.) I only have one quick suggestion:
Instead of using a series of if-then-else (or variations of it) consider using a state machine. Implementations often include use of a switch() inside a while(expression){...} loop. The following is a very simple example of how you might be able to do the steps you need in this construct:
(Note, this is a mix of C and pseudo code for illustration. It is close to compilable , but contains a few undefined items.)
typedef enum {
START,
SET_VIB,
CHECK_TEMP,
GET_TIME,
CLEANUP,
SLEEP,
MAX_STATE
}STATE;
enum {
IN_WORK,
FAILED,
SUCCESS
};
enum {// durations in minutes
MIN_2,
MIN_5,
MIN_10,
MAX_DUR// change/add durations as profile needs
};
const int dur[MAX_DUR] = {120, 300, 600};
int RunProcess(STATE state);
int main(void)
{
STATE state = START;
RunProcess(state);
return 0;
}
int RunProcess(STATE state)//Add arguments here for temperature,
{ //Sleep duration, Cycles, etc. so they are not hardcoded.
int status;
time_t elapsed = 0; //s
BOOL running = TRUE;
double temp, setpoint;
int duration;
time_t someMsValue;
while(running)
switch (state) {
case START:
//Power to oven
//Power to vibe
//initialize state and status variables
duration = dur[MIN_2];
state = SLEEP;
status = IN_WORK;
break;
case SET_VIB:
//test and control vibe
if(duration == dur[MIN_2])
{
duration = dur[MIN_5];
//& turn off vibe
}
else
{
duration = dur[MIN_2];
//& turn on vibe
}
//init elapsed
elapsed = 0;
status = IN_WORK;
state = CHECK_TEMP;
break;
case CHECK_TEMP:
//read temperature
if(temp < setpoint)
{
state = SLEEP;
status = IN_WORK;
}
else
{
state = CLEANUP;
status = SUCCESS;
}
break;
case GET_TIME:
elapsed = getTime();
if(elapsed > duration) state = SET_VIB;
else state = SLEEP;
status = IN_WORK;
break;
case CLEANUP:
//turn off heat
//turn off vibe
running = FALSE;
break;
case SLEEP:
Sleep(someMsValue);
state = GET_TIME;
status = IN_WORK;
break;
default:
// called with incorrect state value
// error message and exit
status = FAILED;
state = CLEANUP;
break;
}
return status;
}
Suggestion for improvement to this illustration:
Expand this code to read in a "profile" file. It could include such things as parameter values typical to your process, such as temperature profiles, vibration profiles, number of cycles, etc. With such information, all of the hard-coding used here as illustration could be replaced with run-time configurable parameters, allowing the system to use many different profiles
without having to recompile the executable each time.
Another state machine example.

receive/transmit over rs232 with arm lpc2148 on sparkfun logomatic

I am trying to program the logomatic by sparkfun, and yes I have used their forum with no responses, and having some issues. I am trying to send characters to the UART0 and I want the logomatic to respond with specific characters and not just an echo. For example, I send 'ID?' over the terminal (using RealTerm), and the logomatic sends back '1'. All it will so now is echo.
I am using c with programmers notepad with the WinARM toolchain. The following snippet is from the main.c file. I only included this, because I am fairly certain that this is where my problem lies
void Initialize(void)
{
rprintf_devopen(putc_serial0);
PINSEL0 = 0xCF351505;
PINSEL1 = 0x15441801;
IODIR0 |= 0x00000884;
IOSET0 = 0x00000080;
S0SPCR = 0x08; // SPI clk to be pclk/8
S0SPCR = 0x30; // master, msb, first clk edge, active high, no ints
}
Notice the rprintf_devopen function, below is from the rprintf.c file, and due to my mediocre skills, I do not understand this bit of code. If I comment out the rprintf_devopen in main, the chip never initializes correctly.
static int (*putcharfunc)(int c);
void rprintf_devopen( int(*put)(int) )
{
putcharfunc = put;
}
static void myputchar(unsigned char c)
{
if(c == '\n') putcharfunc('\r');
putcharfunc(c);
}
Now, below is from the serial.c file. So my thought was that I should be able to just call one of these putchar functions in main.c and that it would work, but it still just echoes.
int putchar_serial0 (int ch)
{
if (ch == '\n')
{
while (!(U0LSR & 0x20));
U0THR = CR; // output CR
}
while (!(U0LSR & 0x20));
return (U0THR = ch);
}
// Write character to Serial Port 0 without \n -> \r\n
int putc_serial0 (int ch)
{
while (!(U0LSR & 0x20));
return (U0THR = ch);
}
// Write character to Serial Port 1 without \n -> \r\n
int putc_serial1 (int ch)
{
while (!(U1LSR & 0x20));
return (U1THR = ch);
}
void putstring_serial0 (const char *string)
{
char ch;
while ((ch = *string))
{
putchar_serial0(ch);
string++;
}
}
I have tried calling the different putchar functions in main, also with the rprintf_devopen. Still just echoes. I have altered the putchar functions and still just echoes. I have tried just writing to the U0THR register in main.c and no luck. Keep in mind that I am still a student and my major is electrical engineering, so the only programming classes that I have taken are intro to c, and an intro to vhdl. I am more of a math and physics guy. I was working on this for an internship I was doing. The internship ended, but it just bugs me that I cannot figure this out. Honestly, working on this program taught me more that the c class that I took. Anyways, I appreciate any help that can be offered, and let me know if you want to see the entire code.
Below is an update to the question. This function is in main.c
static void UART0ISR(void)
{
char temp;
trig = 13; //This is where you set the trigger character in decimal, in this case a carriage return.
temp = U0RBR; //U0RBR is the receive buffer on the chip, refer to datasheet.
if(temp == query1[counter1]) //This segment looks for the characters "ID?" from the U0RBR
{ //query1 is defined at the top of the program
counter1++;
if(counter1 >= 3)
{
flag1 = 1; //This keeps track of whether or not query1 was found
counter1 = 0;
stat(1,ON);
delay_ms(50);
stat(1,OFF);
RX_in = 0;
temp = 0;
//rprintf("\n\rtransmission works\n");
putc_serial1(49);
}
}
if(temp == query2[counter2] && flag1 == 1) //This segment looks for "protov?" from the U0RBR, but only after query1 has been found
{
counter2++;
if(counter2 >= 7)
{
flag2 = 1; //This keeps track of whether or not query2 was found
counter2 = 0;
stat(1,ON);
delay_ms(50);
stat(1,OFF);
RX_in = 0;
temp = 0;
putc_serial1(49);
}
}
if(temp == stop[counter3]) //This if segment looks for certain characters in the receive buffer to stop logging
{
counter3++;
if(counter3 >= 2)
{
flagstop = 1; //This flagstop keeps track of whether or not stop was found. When the stop characters are found,
flag1 = 0; //the query1 and query2 flags will be reset. So, in order to log again these queries must be sent again
flag2 = 0; //this may seem obvious, but deserves mention.
counter3 = 0;
stat(1,ON);
delay_ms(500);
stat(1,OFF);
RX_in = 0;
temp = 0;
}
flagstop = 0; //Reset the stop flag in order to wait once again for the query 1&2
}
if(RX_in == 0)
{
memset (RX_array1, 0, 512); // This clears the RX_array to make way for new data
memset (RX_array2, 0, 512);
}
if(RX_in < 512 && flag1 == 1 && flag2 == 1) //We cannot log data until we see both flags 1 & 2 and after we see these flags,
{ //we must then see the trigger character "carriage return"
RX_array1[RX_in] = temp;
RX_in++;
if(temp == trig)
{
RX_array1[RX_in] = 10; // delimiters
log_array1 = 1;
RX_in = 0;
}
}
else if(RX_in >= 512 && flag1 == 1 && flag2 == 1) //This else if is here in case the RX_in is greater than 512 because the RX_arrays are defined to
{ //be of size 512. If this happens we don't want to lose data, so we must put the overflow into another register.
RX_array2[RX_in - 512] = temp;
RX_in++;
RX_array1[512] = 10; // delimiters
RX_array1[512 + 1] = 13;
log_array1 = 1;
if(RX_in == 1024 || temp == trig)
{
RX_array2[RX_in - 512] = 10; // delimiters
log_array2 = 1;
RX_in = 0;
}
}
temp = U0IIR; // have to read this to clear the interrupt
VICVectAddr = 0;
}

Comparion of values won't work without delay

I'm writing an application that will time mouse latency for our product.
The way it works is that it sends a mouse movement, and measures the time between then and when we get a pixel change on screen.
Why does this delay affect the program.
int check_for_pixel_change() {
// Gets the pixels R value
unsigned char value = *((unsigned char *) (0x100));
// If this delay is not here then the loop will always return 1
usleep(5);
if(value == (0x80)) return 0;
else return 1;
}
int main() {
// Send move / start timer
while(check_for_pixel_change());
// stop timer
return 0;
}
Here is the code that worked.
Thanks to #barak-manos && #santosh-a.
I needed to change the char to volatile because it would be constantly changing by a different program.
int check_for_pixel_change() {
// Gets the pixels R value
volatile unsigned char value = *(volatile unsigned char *) (0x100);
if(value == (0x80)) return 0;
else return 1;
}
int main() {
// Send move / start timer
while(check_for_pixel_change());
// stop timer
return 0;
}

Arduino Variable size Array Declaration

I get an error while trying to run the following code:
int SizeOfReadArray = 10;
int PacketLength = 5;
unsigned char rmessage[SizeOfReadArray];
unsigned long flag = 0;
unsigned char DataPacket[PacketLength];
int alternate = 1;
int remaining;
int Index;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
}
void loop() {
PacketExtraction();
}
void PacketExtraction(){
// Read Serial Buffer store in array
Serial.readBytes(rmessage,SizeOfReadArray);
// onetime execution for getting exact message from serial buffer
if (flag == 0){
for (int j=0;j<SizeOfReadArray;j++){
// check for start of packets through header bytes
if (rmessage[j+0] == 65 && rmessage[j+1] == 65){
// store the Index for extracting packet from message array
Index = j;
remaining = SizeOfReadArray-Index+PacketLength;
flag = 1;
}
}
}
// actual packet extraction
/* take PacketLength of data from serial burffr and store the rest
for remaining bytes for next data packet construction */
if (alternate == 1){
for (int k=0;k<5;k++){
DataPacket[k]=rmessage[k+Index];
}
// storing remaining bytes form next execution
unsigned char previouspacket[remaining];
for (int k=0;k<remaining;k++){
previouspacket[k] = rmessage[k+Index+PacketLength];
}
alternate = 0;
}
/* now this time take the previously saved remaining bytes of packet
and merge them with the current packet data */
else{
for (int k=0;k<remaining;k++){
DataPacket[k] = previouspacket[k];
}
for (int k=0;k<(remaining+1);k++){
DataPacket[k+remaining] = rmessage[k];
}
alternate = 1;
}
}
Error Message:
Arduino: 1.6.1 (Windows 7), Board: "Arduino Mega or Mega 2560,
ATmega2560 (Mega 2560)"
sketch_apr04b.ino: In function 'void PacketExtraction()':
sketch_apr04b.ino:52:23: error: 'previouspacket' was not declared in
this scope
Error compiling.
This report would have more information with "Show verbose output
during compilation" enabled in File > Preferences.
previouspacket is only declared in the first branch of the if…then blocks.
You should move unsigned char previouspacket[remaining]; before the if statement

Confused with output to console, C / USB CDC / PIC18F2550

I have a problem that is probably a simple misunderstanding on my end.
I have a PIC18F2550 device with a USB CDC firmware. I would like to send it a command to output something to the console every second. However, it doesn't seem to work. I put in a loop to iterate for 5 seconds and display an output message every second, but it won't actually output anything. It passes through the 5 second loop until the end where it DOES display the final message after the loop was executed. It won't output anything DURING the loop though.
I included my entire ProcessIO function because I think it's important for this issue, but I commented where I placed the exact command I'm trying to figure out.
Thanks for any suggestions you guys have, I appreciate it. I'm a mechanical engineer trying to learn some embedded stuff.
/********************************************************************
* Function: void ProcessIO(void)
* Overview: This function is a place holder for other user
* routines. It is a mixture of both USB and
* non-USB tasks.
*******************************************************************/
void ProcessIO(void)
{
BYTE numBytesRead;
// User Application USB tasks
if((USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1)) return;
if (USBUSARTIsTxTrfReady())
{
if((CDCattached == 0x01) && (CDCattachedcount == 2))
{
putUSBUSART((char*)"Text Message\r\n",49);
CDCTxService();
CDCattachedcount = 0;
CDCattached = 0x00;
}
numBytesRead = getsUSBUSART(USB_Out_Buffer, 64);
if (numBytesRead == 1)
{
if ((USB_Out_Buffer[0] == '\r')) //Received ENTER? Ues-> End of Command
{
if (pos >0)
{
command_recvd = 0x01;
Command[pos++] = '\0';
pos = 0;
}
}
else if ((USB_Out_Buffer[0] == 0x7F) || (USB_Out_Buffer[0] == 0x08))
{
if (pos > 0) pos--;
Command[pos] = '\0';
putUSBUSART ((char*) USB_Out_Buffer, 1);
}
else
{
Command[pos++] = USB_Out_Buffer[0];
putUSBUSART((char*) USB_Out_Buffer, 1);
Command[pos]='\0';
} //No:- Store Character to String
}
else if ((numBytesRead > 1))
{
strncpy(Command,USB_Out_Buffer,numBytesRead);
for(int indx = numBytesRead; indx < 64; indx++)
{
Command[indx]='\0';
}
pos = numBytesRead--;
command_recvd = 0x01;
Command[pos++] = '\0';
// putUSBUSART((char*) USB_Out_Buffer, 1);
pos = 0;
}
if (command_recvd == 0x01)
{
for (int aaa = 0; aaa <= 63; aaa++)
{
output_message[aaa]= '\0';
}
************** THIS IS WHERE MY TEST COMMAND IS ***************
if (strnicmp((char*) Command, (char*) "test", 4) == 0)
{
sprintf(output_message, "\r\nStarting loop...\r\n");
for int bbb = 0; bbb < 5; bbb++)
{
sprintf(output_message, "\r\nLooping...\r\n");
for (delayIndex = 0; delayIndex < 1000; delayIndex++)
{
__delay_ms(1);
}
}
sprintf(output_message, "\r\nLoop finished!\r\n");
}
else
{
invalidCommand:
sprintf(output_message, "\r\nInvalid Command Received. Please Retry.\r\n\0");
}
command_recvd = 0x00;
}
}
CDCTxService();
}
You should call putUSBUSART() and CDCTxService() before overwriting output_message
Also, CDCTxService() needs to be called frequently, so you have to call it during the delay loop.
for int bbb = 0; bbb < 5; bbb++)
{
sprintf(output_message, "\r\nLooping...\r\n");
putsUSBUSART(output_message);
for (delayIndex = 0; delayIndex < 1000; delayIndex++)
{
__delay_ms(1);
if(USBUSARTIsTxTrfReady()) {
sprintf(output_message, "\r\nInside inner loop\r\n");
putsUSBUSART(output_message);
}
CDCTxService();
}
}
Although that kind of bloking delays could work ( __delay_ms() ), a better aproach is to check for an ellapsed timer, or a timestamp. Something like:
for int bbb = 0; bbb < 5; bbb++)
{
sprintf(output_message, "\r\nLooping...\r\n");
putsUSBUSART(output_message);
timestamp = TickGet();
while (TickDiff(timestamp, TickGet()) < TICK_SECOND)
{
if(USBUSARTIsTxTrfReady()) {
sprintf(output_message, "\r\nInside inner loop\r\n");
putsUSBUSART(output_message);
}
CDCTxService();
}
}
TickGet and TickDiff are functions you have to implement yourself, however there are lots of examples on Microchip libraries
Short version: this approach won't work. You'll need to rethink how you're doing this.
USB devices cannot delay while processing events — they must be able to respond promptly to every request sent from the host. Delaying for as long as a second will typically cause the host to assume the device has been disconnected.
It's critical to understand here that the USB device model is based (almost) entirely around the host sending requests to a device, and the device replying. Devices cannot generate unsolicited responses.
Now, the reason you're not seeing the expected results here is because sprintf() doesn't send the results to the host; all it does is put a message into a buffer to prepare it to be sent back. Calling it multiple times overwrites that buffer, rather than sending multiple messages back.

Resources