using System; using Microsoft.SPOT; using Microsoft.SPOT.IO; using Microsoft.SPOT.Hardware; using System.IO; using System.IO.Ports; using System.Text; using CPF.FileTransfer; namespace CPF.PosixClient { public class PosixSession { // Constants public enum ERROR : int { NOLOGIN = -1, NOCARRIER = -2, NOZMODEM = -3, NORESP = -4 }; protected const int SUCCESS = 0; protected const ushort MAXLOGINS = 5; protected const ushort MAXCALLS = 2; protected const ushort MAXZMODEM = 5; protected const ushort MAXBUFF = 1024; /// /// This constant drives the effective timeout of the system, /// in combination with how long a port has to respond. /// protected ushort MAXERR = 10; protected const ushort READTIMEOUT = 10; //in tenths of seconds protected const byte CR = 13; protected const byte LF = 10; //Delegates public delegate void ExpectedHandler(); public delegate void ExpectedHandlerWithOutput(string output); // Private members protected byte[] txbuff; protected ushort _callatt, _loginatt, _zmodematt; protected bool bLoggedIn = false; protected string _username; protected string _password; protected bool bSendExtraCRLF = true; protected byte[] buff = new byte[MAXBUFF]; //Properties public string Username { get { return _username; } set { _username = value; } } public string Password { set { _password = value; } } public string LoginPrompt { get; set; } public string CommandPrompt { get; set; } public string PasswordPrompt { get; set; } // Members protected SerialPort sp; public PosixSession(SerialPort sPort) { sp = sPort; LoginPrompt = "login:"; CommandPrompt = "$ "; PasswordPrompt = "Password:"; } public int ZModemSendTransaction(string filename) { WaitForPrompt(); writeLine("rz -t 50 -B 1024 -w 1024 -r\r"); //writeLine("rz \r"); while (_zmodematt < MAXZMODEM) { //GET ZPAD ZDLE sequence if (Expect("*\x18", () => { Debug.Print("GOT ZMODEM ZRINIT"); }) < 0) { ++_zmodematt; continue; } else break; } if (_zmodematt >= MAXZMODEM) return (int)ERROR.NOZMODEM; ZmodemSender zs = new ZmodemSender(sp, filename); // zmodem transmit on our side while (zs.doTasks()) { } return SUCCESS; } public int ZModemReceiveTransaction(string remotefilename, string localdirectory) { //writeLine("sz -r -t 50 " + remotefilename + "\r\n"); int resp = 0; WaitForPrompt(); while (_zmodematt < MAXZMODEM) { writeLine("sz " + remotefilename + "\r\n"); if ((resp = Expect("*\x18", () => { Debug.Print("GOT ZMODEM ZRQINIT"); })) < 0) { ++_zmodematt; continue; } else break; } if (resp < 0) return resp; ZmodemReceiver zr = new ZmodemReceiver(sp, true); zr.filePrefix = localdirectory; while (zr.doTasks()) { } return SUCCESS; } public int Logout() { if (!WaitForPrompt()) return (int)ERROR.NORESP; Debug.Print("Logging Out."); //Temporarily removed due to nature of the RUDICS connection. writeLine("exit \r\n"); return SUCCESS; } private readonly char[] _trimChars = {'\r' ,'\n'}; public int Broadcast(string msg) { if (!WaitForPrompt()) return (int)ERROR.NORESP; StringBuilder command = new StringBuilder("broadcast "); command.Append(msg.Trim(_trimChars)); command.Append("\r\n"); Debug.Print("Broadcasting Message: "+ command); writeLine(command.ToString()); return SUCCESS; } private bool WaitForPrompt() { writeCRLF(); int _promptatt = 0; while (_promptatt < MAXLOGINS) { if (Expect(CommandPrompt, () => { Debug.Print("GOT PROMPT"); }) < 0) { ++_promptatt; writeCRLF(); } else break; } if (_promptatt >= MAXLOGINS) return false; return true; } protected void writeLine(string msg) { txbuff = Encoding.UTF8.GetBytes(msg); sp.Write(txbuff, 0, txbuff.Length); Debug.Print("Sending:::"); Debug.Print(msg); } protected void writeCRLF() { sp.WriteByte(CR); sp.WriteByte(LF); } public int CheckForPrompt() { writeCRLF(); int resp = ExpectEither("NO CARRIER", CommandPrompt); switch (resp) { case 0: //NO CARRIER Debug.Print("Connection Dropped"); return (int)ERROR.NOCARRIER; case 1: //Prompt Debug.Print("GOT CONSOLE PROMPT, LOGGED IN."); bLoggedIn = true; return SUCCESS; default: return (int)ERROR.NORESP; } } public int Login() { bool bLoginPrompted = false; int resp = 0; _loginatt = 0; while (_loginatt < MAXLOGINS && !bLoggedIn) { // Attempt to trigger a login prompt if (!bLoginPrompted && bSendExtraCRLF && _loginatt > 0) { writeCRLF(); Debug.Print("SENDING CR LF"); } resp = ExpectEither("NO CARRIER", LoginPrompt, PasswordPrompt, CommandPrompt); //handle response switch (resp) { case 0: // "NO CARRIER" Debug.Print("Connection Dropped"); return (int)ERROR.NOCARRIER; case 1: // "login:" bLoginPrompted = true; Debug.Print("LOGIN PROMPT RECEIVED"); // send username Debug.Print("Sending UserName: " + _username); writeLine(_username+"\r"); ++_loginatt; break; case 2: // "Password:" Debug.Print("GOT PASSWORD PROMPT"); // send password Debug.Print("Sending Password."); writeLine(_password+"\r"); break; case 3: // "~$ prompt" Debug.Print("GOT CONSOLE PROMPT, LOGGED IN."); bLoggedIn = true; break; default: ++_loginatt; bLoginPrompted = false; Debug.Print("LOGIN ERROR: " + resp.ToString()); break; } } //Test if we're logged in if (!bLoggedIn) { return (int)ERROR.NOLOGIN; } else return SUCCESS; } protected ushort buffl = 0; public int Expect(string query, ExpectedHandler handler) { StringBuilder sb = new StringBuilder(); int errcount = 0; int c; buffl = 0; Array.Clear(buff, 0, MAXBUFF); while (true) { if ((c = Zmodem.readline(sp, READTIMEOUT)) > 0) { buff[buffl++] = (byte)(c & 0x7F); //restrict to 128 ASCII set sb.Append(Encoding.UTF8.GetChars(buff, buffl - 1, 1)); //Debug.Print(sb.ToString()); } else errcount++; // let's check for our string if (buffl > 0) { if (sb.ToString().IndexOf(query) >= 0) { Debug.Print(sb.ToString()); //We got it, dump the rest of the buffer... if (sp.BytesToRead > 0) sp.DiscardInBuffer(); handler(); return 0; } } if (buffl >= MAXBUFF) { return -2; } if (errcount > MAXERR) { Debug.Print("MAX Attempts reached, This came in:" + sb.ToString()); return -1; } } } public int ExpectEither(ushort maxattempts, params string[] queries) { ushort frmr = MAXERR; MAXERR = maxattempts; int resp = ExpectEither(queries); MAXERR = frmr; return resp; } public int ExpectEither(params string[] queries) { StringBuilder sb = new StringBuilder(); int errcount = 0; int c, n; buffl = 0; Array.Clear(buff, 0, MAXBUFF); while (true) { if ((c = Zmodem.readline(sp, READTIMEOUT)) > 0) { buff[buffl++] = (byte)(c & 0x7F); //restrict to 128 ASCII set sb.Append(Encoding.UTF8.GetChars(buff, buffl - 1, 1)); //Debug.Print(sb.ToString()); } else errcount++; // let's check for our string if (buffl > 0) { // input order of the queries does imply priority, as the first // encountered is what's return. for (n = 0; n < queries.Length; n++) { if (sb.ToString().IndexOf(queries[n]) >= 0) { Debug.Print("ExpectEither(): " + sb.ToString()); //We got it, dump the rest of the buffer... if (sp.BytesToRead > 0) sp.DiscardInBuffer(); //Debug.Print(sb.ToString()); //handler(); return n; } } } if (buffl >= MAXBUFF) { return -2; } if (errcount > MAXERR) { Debug.Print("MAX Attempts reached, This came in:" + sb.ToString()); return -1; } } } public int SendCommand(string p) { writeLine(p); int resp = ExpectEither("NO CARRIER", CommandPrompt); switch (resp) { case 0: Debug.Print("NO CARRIER RECEIVED"); return (int)ERROR.NOCARRIER; case 1: //command complete return (int)SUCCESS; default: return (int)ERROR.NORESP; } } } }