need easier to maintain version of this code

How can I do sections of this smarter? Things like

    Serial.println("sending at+cgpsrst=1");
    Serial1.write('a');
    Serial1.write('t');
    Serial1.write('+');  
    Serial1.write('c');  
    Serial1.write('g');
    Serial1.write('p');
    Serial1.write('s');
    Serial1.write('r');
    Serial1.write('s');
    Serial1.write('t');
    Serial1.write('=');
    Serial1.write('1');
    Serial1.write(13);
    Serial1.write(10);

I use Serial to talk between PC and the 1284P, and Serial1 between the 1284P and the DFRobot module.

I couldn't figure it out last night, so I ended up with the attached working code for this DFRobot SIM908 GSM/GPS card:

Their code samples sucked.

Code attached. (actual phone # removed)
Results:

Starting GPS/GSM 'warmup' delay 123456789101112
GPS ready for AT?
received: +CFUN:1+CPIN:READY+PACSP:1CallReadyGPSReÿ.........

yes - sending AT
received: atOK

sending at+cgpspwr=1
received: at+cgpspwr=1OK

sending at+cgpsrst=1
received: at+cgpsrst=1OK

Setup complete

sending at+cgpsstatus?
received: at+cgpsstatus?+CGPSSTATUS:Location3DFixOK....

sending at+cgpsinf=4
received: 
at+cgpsinf=44,4222.032117,N,7131.696846,W,063328.000

Sending Text: 
sending at+cmgf=1
received: at+cmgf=1OK

sending at+cmgs=phone_number with number in quotes 
received: at+cmgs="508xxxxxxx">

sending truck # and location, time message
received: TRUCK:0001,42.22.032117,N,71.31.696846,W,TIME:06:33GMT

+CMGS: 70

OK

There's a lot of debug statements in there, almost all of the above, but the end result that shows up on your phone is:
TRUCK:0001,42.22.032117,N,71.31.696846,W,TIME:06:33GMT
which I think I parsed out nicely for human readability.

One thing I haven't figured out is catching all the incoming data here:
received: +CFUN:1+CPIN:READY+PACSP:1CallReadyGPSReÿ.........
(I strip out spaces, CR, and LF from what I store to make it easier to grab the data pieces I want)
where I think I'm losing part of GPS READY coming in during the warmup delay. Gotta catch it in a couple pieces or something so the 64 byte buffer doesn't over flow (which is what I think is occurring).
A couple things like the TRUCK # and the Phone Number I want to be in arrays at the top of the sketch so they can be easily tweaked vehicle by vehicle and by phone number if needed.

Occasionally the card reports "NORMAL POWER DOWN" and sometimes ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ for all characters, I've managed to recognize that and added this

    Serial.println("resetting...");
    asm volatile ("jmp 0");

to autoreset the processor, and recover automatically, that was a sweet discovery last night.

GPS_GSM_only.ino (10.3 KB)

Do a loop through a string.

char someString = "qwertyuiop";

printChars (someString);

printCars (*str) {

    while (*str != 0)
        Serial1.write(*str++);
}

Warning, syntax may not be correct, I haven't actually written a line of code in about 3 years :slight_smile:


Rob

Am I missing something? Why write all those single character writes, rather than simply using Serial.print??

    char *s = "at+cgpsrst=1";
    Serial.print("sending ");
    Serial.println(s);
    Serial1.println(s);

Regards,
Ray L.

Ray has asked the question I was going to ask. I have a slightly different solution.
Try this function to write to Serial and Serial1.

void send_at(const char *at)
{
  Serial.print("sending ");
  Serial.println(at);
  Serial1.print(at);
  Serial1.print("\n\r");
}

and call it with:

  send_at("at+cgpsrst=1");

But if you have to use Serial1.write:

void send_at(const char *at)
{
  Serial.print("sending ");
  Serial.println(at);
  for(char *p = (char *)at;*p;p++)Serial1.write(*p);
  Serial1.write(13);
  Serial1.write(10);
}

Pete

I assumed there was a reason for sending the chars one at a time, but we'll see when CR returns.

I'm moving the test setup to my car to try position reporting from the road tomorrow, will try out the code changes tomorrow.
It has to be Serial1.write for the 'a' chars to be received correctly by the GPS/GSM module the way I am doing it now.
I'm open to other options if the result is the GPS receiving characters the same as if I was typing them on the serial monitor.
The last part of the code for example:

  // GPS test code

  if (Serial.available()>0){
    inMonitor = Serial.read();
    Serial1.write(inMonitor);
  }

  if (Serial1.available()>0){
    inGPS = Serial1.read();
    Serial.write(inGPS);
  }

lets me send AT+commands during the time when 3 minutes is elapsing and get proper replies back, so I was able to type the messages in and look at the results coming back and then tweak the code to mimic that and handle the responses.

If you need to slow down the write, you can add a delay:

 for(char *p = (char *)at;*p;p++) {
    Serial1.write(*p);
    delay(50);
  }
  Serial1.write(13);
  delay(50);
  Serial1.write(10);

Pete

Sending at 9600 was not a problem.

It was the receiving of the random timed messages at startup that is a problem:

RDY

+CFUN: 1

+CPIN: READY

+PACSP: 1

Call Ready

GPS Ready << I lose part of this one.

The actual answer to this question is "read and understand the docs". The Serial has a number of methods for reading and writing. Read through the documentation. You don't need to memorize it, but you do need to get a feel for what's available.

Serial.write('a') and Serial.print('a') should perform EXACTLY the same operation. So, if one works, and the other does not, you have a timing problem. You'd be wise to get to the bottom of that, rather than just going with what seems to work, as it will no doubt at some point, fail.

Regards,
Ray L.

Ok, this seems to work as you say:

void setup(){
  Serial.begin(9600);
}
void loop(){
  Serial.print('a');
  Serial.write('b');
  delay (200);
}
ababababababababababababababababababab

So maybe it was other stuff in my code that was causing the problems talking to the module.

but " works the same too, on the serial monitor anyway.

void setup(){
  Serial.begin(9600);
}
void loop(){
  Serial.print("a");
  Serial.write("b");
  delay (200);
}
abababababababa

The Serial.write() method has two overloads. One takes a single byte. The other takes an array of bytes.

byte msg[] = {'a', 't', '+', 'c', 'g', 'p', 's', 'r', 's', 't', '=', '1', 13, 10);
Serial.write(msg, sizeof(msg));

Of course, you could make that even simpler:

char *msg = "at+cgpsrst=1\r\n";
Serial.write(msg, strlen(msg));

Thanks PaulS, that's what I was looking for. That's even cleaner than what el_supremo had suggested in #3.
In this case, there's a couple I want to create at the top of the sketch to make them easy to update and load into additional cards. I can have them all in one place like this?

char *msg0 = "at\r\n";

char *msg1 = "at+cgpspwr=1\r\n";

char *msg2 = "at+cgpsrst=1\r\n";
char *msg3 = "at+cgpsstatus?\r\n";
char *msg4 = "at+cgpsinf=4\r\n";
:
char *msg9 = "TRUCK: \r\n";
char *msg10 = "0001 \r\n";

char *msg11 = "at+cmgs="508xxxxxx"\r\n"; <<< will the required double quotes in here be a problem?
:
char #msg15 = "GMT\x1A";  // GMT CTRL-Z, CTRL-Z signals to module to send the message

and just call them off one by on as needed?

Serial.write(msg0, strlen(msg0));
:
:
Serial.write(msg1, strlen(msg1));
:
:
Serial.write(msg2, strlen(msg2));
:
: // etc

Test setup in my car was sending location messages successfully this morning.
Will see if I can get a copy of the texts from the recipient and plot them in maps.google.com and see what the route looked like. (should have been about 13 text). I think the route has a stretch where there is poor to no cell phone coverage, be interesting to see if that impacted text messages. And several areas with tree canopy coverage that may have blocked GPS satellite coverage (impacts satellite radio reception, but there are a lot more GPS satellites being tracked at any one time).

Or, I may have to come up with some more error handling scenarios ...

I can have them all in one place like this?

Yes.

and just call them off one by on as needed?

Yes, as long as you understand that serial data transmission is asynchronous. That is, you have to wait for the proper response before sending the next command. Nothing in the hardware or software serial classes does this for you.

Oh yeah, I will be checking for proper responses back before send the next message, same as I do now.
Just wanted to do all the Serial.writes smarter. Figure more enhancements will be requested as it starts getting used, and it's not really maintainable the way I got it working.

Ok, got it converted. However, must be missing something still, as I have these compile errors, with the first one highlighted at:

    Serial1.write(at,strlen(at));
[code]
with at set up as
[code]
char *at = "at\r\n";

so I'm sure the others are for the other conversions.

GPS_GSM_onlyRev1.ino: In function 'void setup()':
GPS_GSM_onlyRev1:120: error: invalid conversion from 'char*' to 'const uint8_t*'
GPS_GSM_onlyRev1:120: error: initializing argument 1 of 'virtual size_t Print::write(const uint8_t*, size_t)'
GPS_GSM_onlyRev1:140: error: invalid conversion from 'char*' to 'const uint8_t*'
GPS_GSM_onlyRev1:140: error: initializing argument 1 of 'virtual size_t Print::write(const uint8_t*, size_t)'
GPS_GSM_onlyRev1:160: error: invalid conversion from 'char*' to 'const uint8_t*'
GPS_GSM_onlyRev1:160: error: initializing argument 1 of 'virtual size_t Print::write(const uint8_t*, size_t)'
GPS_GSM_onlyRev1.ino: In function 'void loop()':
GPS_GSM_onlyRev1:197: error: invalid conversion from 'char*' to 'const uint8_t*'
GPS_GSM_onlyRev1:197: error: initializing argument 1 of 'virtual size_t Print::write(const uint8_t*, size_t)'
GPS_GSM_onlyRev1:219: error: invalid operands of types 'char*' and 'char*' to binary 'operator+'
GPS_GSM_onlyRev1:248: error: invalid conversion from 'char*' to 'const uint8_t*'
GPS_GSM_onlyRev1:248: error: initializing argument 1 of 'virtual size_t Print::write(const uint8_t*, size_t)'
GPS_GSM_onlyRev1:270: error: invalid conversion from 'char*' to 'const uint8_t*'
GPS_GSM_onlyRev1:270: error: initializing argument 1 of 'virtual size_t Print::write(const uint8_t*, size_t)'
GPS_GSM_onlyRev1:272: error: invalid conversion from 'char*' to 'const uint8_t*'
GPS_GSM_onlyRev1:272: error: initializing argument 1 of 'virtual size_t Print::write(const uint8_t*, size_t)'
GPS_GSM_onlyRev1:274: error: invalid conversion from 'char*' to 'const uint8_t*'
GPS_GSM_onlyRev1:274: error: initializing argument 1 of 'virtual size_t Print::write(const uint8_t*, size_t)'
GPS_GSM_onlyRev1:298: error: invalid conversion from 'char*' to 'const uint8_t*'
GPS_GSM_onlyRev1:298: error: initializing argument 1 of 'virtual size_t Print::write(const uint8_t*, size_t)'
GPS_GSM_onlyRev1:299: error: invalid conversion from 'char*' to 'const uint8_t*'
GPS_GSM_onlyRev1:299: error: initializing argument 1 of 'virtual size_t Print::write(const uint8_t*, size_t)'
GPS_GSM_onlyRev1:316: error: invalid conversion from 'char*' to 'const uint8_t*'
GPS_GSM_onlyRev1:316: error: initializing argument 1 of 'virtual size_t Print::write(const uint8_t*, size_t)'
GPS_GSM_onlyRev1:323: error: invalid conversion from 'char*' to 'const uint8_t*'
GPS_GSM_onlyRev1:323: error: initializing argument 1 of 'virtual size_t Print::write(const uint8_t*, size_t)'

[/code]

GPS_GSM_onlyRev1.ino (8.59 KB)

Cast it, I guess; the way you use serial.print, it expects a pointer to a uint8_t array.

Serial1.write((uint8_t*)at,strlen(at));

Ok, got that all compiled now. Back to test ...