YunSerialTerminal Example: How does it work? [solved]

Looking at the example in the IDE - http://arduino.cc/en/Tutorial/YunSerialTerminal

I'm confused about the purpose of the last else statement that looks like this

else 
{                        //     any other key pressed?
    Serial1.write('~');           //        write '~' to Linux
    Serial1.write(c);             //        write char to Linux
}

It looks to me as though this condition should only be happened upon when submitting
things like ~4, ~5, ~6 and so on. Writing that out to the Linino chip. Do those conditions
have use cases or is this just cruft?
Doesn't seem that ~~, ~0, ~1, ~2, or ~3 are ever being written to Linux. Just used in flow.
Am I looking a the flow control completely wrong?

Have to admit, this example has been a bit hard to get my head around in trying to automate
its functionality into my own code.

The "else" clause is handling everything else from the supported commands (~0 to ~3 and ~~ for shutting down the bridge)
It means: you can type everything BUT ~0-~3 and ~~

In a simpler scenario, where all you need is just a terminal, the whole first "if" can be removed.

Looks like Federico posted an answer while I was typing… But I’ll leave mine in place since it gives a little more detail. I hope it’s not too redundant…

Most of what you type gets sent straight to the Linux side. However, there are five special commands that the serial terminal sketch can process, as indicated in the comments at the beginning of the sketch. Most of these just change the baud rate for the channel between the sketch and the Linux side, while the last can be used to send a special sequence to the Linux side to stop the Bridge client if it happens to be running (and therefore giving you access to the Linux command line.)

How do you trigger these commands? By typing the tilde (~) key followed by 0, 1, 2, 3 or another tilde. The code sees the initial tilde, then looks at the next character typed, and if it’s one of these 5 special cases, it performs the special command code.

But what if the character after the tilde is not one of these special commands? That’s where the else clause comes in. In this case, the sketch sends the characters through as if there wasn’t any special processing. The current character (stored in c) is the second character of the sequence, but the tilde that triggered the special processing has been lost. To make up for this, the else clause first sends a tilde (because it knows that was the previous character that was sent that triggered this special block of code) and then it send the current character.

The net result is that if you type “~x” for example, the Linux command line will receive both the tilde and the “x” as if there wasn’t any special code.

This is all so that you can send a tilde to the Linux side using this code (although you still can’t send a digit 0 through 3 or another tilde after the initial tilde – a bit of a nuisance at times.)

Thanks for helping me realize the last "else" is important for the use cases "after" the commands are issued.
I understand what ShapeShifter and Frederico are saying.

When I first looked at the code thought that the commands, like ~0 were being passed to bridge also,
Mainly because of the thought to signal changing baud rate on the Linux chip. That is not the case on
closer examination.

How is the Baud rate being changed on the Linux side? Does it auto-detect?

This example sketch works fine for me. However in my test after changing the baud, seem to print
out a wad of blank bytes to the monitor when sending something like "pwd" or any other ash commands.
Don't want to get too far from the OP but I'll post my modifications if it helps the discussion.

It doesn't look like the Linux side is changed by those commands. That is set by the Linux configuration at boot time. I think the reason for the baud rate options is so that the baud rate for the sketch can be set to match the previously set Linux baud rate, in case the default setting is not correct.

It could also probably be used to type the Linux command to set the baud rate (not sure of the exact command at the moment) and then change the sketch's setting to match.

ShapeShifter:
It doesn't look like the Linux side is changed by those commands. That is set by the Linux configuration at boot time. I think the reason for the baud rate options is so that the baud rate for the sketch can be set to match the previously set Linux baud rate, in case the default setting is not correct.

It could also probably be used to type the Linux command to set the baud rate (not sure of the exact command at the moment) and then change the sketch's setting to match.

Interesting, So if I'm hard coding terminal access, 250000 is the rate plain and simple is what you are saying,
unless changed with an ash command? Wonder if any on lookers know the ash command? I will with contribute,
if I find it.

Forgive me for saying this Massimo and Cristian, but this example, maybe unintentionally has a lot of red herrings.
for the human reader and does little to explain its finer points.

Using stty is a common Linux method, but doesn't appear to be supported on Yun. This was a recent discussion: http://forum.arduino.cc/index.php?topic=269120.msg1897208#msg1897208

Maybe the following example is more or less confusing than the provided example.
Non the less it is something different to look at.

https://github.com/PaulBeaudet/yunSerialTesting/blob/master/yunSerialTesting.ino

// yunSerialTesting.ino -- Gain terminal access to Yun's linux system
void setup() 
{
  Serial.begin(115200); // open serial connection via USB-Serial
  Serial1.begin(250000);// open serial connection to Linux 
  bootCheck(true);      // true denotes output <---------COMMENT IN THIS
  //delay(90000);       // wait for linux to boot <---------OR THIS
  Serial1.write((uint8_t *)"\xff\0\0\x05XXXXX\x7f\xf9", 11); //shutdown bridge
  Serial1.println();//send a new line character to enter shutdown garbage
  delay(2);// wait for the buffer to fill with garbage
  while(Serial1.available()){Serial1.read();} // read out shutdown garbage 
  Serial1.println("ls"); // list current contents of current directory
}// Serial Monitor access to Yun (ash) Terminal achieved

void loop() 
{ // send and recieve tty
  if(Serial.available()){Serial1.write(Serial.read());} 
  //"outgoing" serial buffer have bytes? write them to Open WRT
  if(Serial1.available()){Serial.write(Serial1.read());}
  //"incoming" serial buffer have bytes? write them to Serial Monitor
}

//******************** Other examples ***********************
boolean bootCheck(boolean startUpOutput)//pass true for verbose output
{
  boolean booting = false;//assume complete boot
  timer(17800);           //set timer for max distance between boot outputs
  // have recorded +16 sec between some outputs: important if reset midboot
  while(!timer(0))        //before the timer is up
  {
    while(Serial1.available())
    {
      bootHandler(startUpOutput);
      booting = true;    //buffer filled before user interaction was possible
    }
  }                      // timer returns true when finished exiting loop
  if (booting)
  {
    timer(50000);        //give enough time to finish booting
    while(!timer(0))     //before time is finished     
    {
      while(Serial1.available()){bootHandler(startUpOutput);}
    }                    //handle rest of output
  }
  return booting;        //in case of conditions looking for boot
}

void bootHandler(boolean startUpOutput)//pass true for verbose output
{ //mirror boot process to the serial monitor if true argument is passed
  if(startUpOutput){Serial.write(Serial1.read());} 
  else{Serial1.read();}//empty buffer with empty reads
}

boolean timer(uint32_t durration)
{//used for checking an setting timer
  static uint32_t ptimer[2] = { };// create timer to modify
  if(durration)
  {
    ptimer[1]=durration; //set durration
    ptimer[0]=millis();  // note the time set
  }
  else if(millis() - ptimer[0] > ptimer[1]){return true;}
  // if the durration has elapsed return true
  return false;
}

Still trying to figure a few things out, like maybe better detecting the boot to wait less
and actually changing the baud rate to a more reliable 115200.
(already see dropped chars every now and then)

The extra functions really show the reason for such prolific use of delay in examples…
its kinda comic to see one line commented out that replaces the three functions.

Will push commits as the other desired things are figured out, going to wrap it up for today though.

ShapeShifter:
Using stty is a common Linux method, but doesn't appear to be supported on Yun. This was a recent discussion: http://forum.arduino.cc/index.php?topic=269120.msg1897208#msg1897208

That one is a rabit hole.. Easily just spent an hour looking though related information.
Seems like, in "basic" there are two ways to go.
Pyserial - if python interfacing is your goal anyhow. Changes baud just for the python?
the arbitrary baud program - Still not quite grasping it, but seems to change baud "globally" if that makes any sense.

Would have though there might just be a config file to be edited, but guess its a bit more complex.

My goals are likely the topic of a whole new thread, so I'll leave the actually changing speed topic be, for now.
All though now I really stand by my red herring comment.

One more question about the IDE Example and I think this topic is overdue to be marked solved.

Why so long as --> ( Serial.read() != -1 ) ? The zero/null case would be something that we would want
to avoid too right? What is the significance of -1?

Interesting. My first thought was that you were waiting for the end of boot, then shutting down the bridge, then finally entering terminal mode. I was about to say that this limits the usefulness of the sketch since I use the original sketch mostly for watching the bootup process. But on a second look I see that during the wait any boot characters are sent to the USB output. A very interesting solution to the issue.

I don’t really have a problem with the original sketch’s use of tilde as an escape character. I just don’t like the idea that the chosen “escape” sequences can never be passed through to the Linux side. I think the limitation is that “" has a defined purpose of shutting down the bridge. If the command to shut down the bridge was changed to something like “~b” then the "” sequence could be used to send a single tilde character to Linux.

That way, if it were desired to send “~1” to the Linux side, one would actually type “~~1” at the terminal. The first tilde would trigger the state machine to look at the next character. The second tilde would trigger the state machine to send a single tilde and exit the special processing mode. The final ‘1’ would simply get passed straight through.

Actually, that does make sense, at least to me. The utility is changing the settings of the serial port hardware, and I would expect the new baud rate to stay until something explicitly changes it again. I’ll leave further serial port speed comments to your new thread, should you start one (and if I think I have something to contribute.)

Why so long as → ( Serial.read() != -1 ) ? The zero/null case would be something that we would want
to avoid too right? What is the significance of -1?

Serial.read() is a non-blocking read that returns immediately whether it actually read something or not. If it read something from the incoming serial data buffer, it returns the character read. If it read nothing (the buffer was empty) it returns -1. That -1 doesn’t represent valid data, so it should not be passed through.

The NULL case is not really an issue: if the Linux side transmitted a NULL, there is no harm in sending it through (in fact, it SHOULD be sent through as the serial terminal sketch really shouldn’t be modifying the data stream - for the most part it should be acting like a simple wire.)

ShapeShifter:
Serial.read() is a non-blocking read that returns immediately whether it actually read something or not. If it read something from the incoming serial data buffer, it returns the character read. If it read nothing (the buffer was empty) it returns -1. That -1 doesn't represent valid data, so it should not be passed through.

The NULL case is not really an issue: if the Linux side transmitted a NULL, there is no harm in sending it through (in fact, it SHOULD be sent through as the serial terminal sketch really shouldn't be modifying the data stream - for the most part it should be acting like a simple wire.)

Thank you ShapeShifter that clears that up, I appreciate it.

ShapeShifter:
I don't really have a problem with the original sketch's use of tilde as an escape character. I just don't like the idea that the chosen "escape" sequences can never be passed through to the Linux side. I think the limitation is that "" has a defined purpose of shutting down the bridge. If the command to shut down the bridge was changed to something like "~b" then the "" sequence could be used to send a single tilde character to Linux.

I do, there is no reason to have a mess of flow control to change the baud just on one side, when the sketches stated or implied purpose is "terminal access". Changing the baud results in no access.

However, I think your idea about how to keep all the characters clear is clever.