public static byte[] ReadEV3File(String fullname) { try { lock (sync) { // if not already done, memorize the start time and fire up the communication MemorizeStartTime(); EstablishConnection(); // prepare the pinger packet to keep the remote-controll target alive during large file transfer ByteCodeBuffer c = new ByteCodeBuffer(); c.OP(0x3A); // Move32_32 c.CONST(42); // move this value c.GLOBVAR(0); // to global variable 0-3 c.OP(0x7E); // Memory_Write c.CONST(1); // program slot 1 = user slot c.CONST(0); // write to global variables c.CONST(0); // to global variable 0 c.CONST(4); // write 4 bytes c.GLOBVAR(0); // take the prepared value 42 // finally execute the command return(con.ReadEV3File(fullname, c)); } } catch (Exception) { // no connection or other severe error - must terminate immediately System.Environment.Exit(1); } return(null); }
// must be called while holding a lock on sync private static void EstablishConnection() { // the first action also involves passing some SystemCommands and DirectCommands if (con == null) { // try to start up connection (when failing, an exception is thrown) con = ConnectionFinder.CreateConnection(false, true); String filename = "/tmp/EV3-Basic Session.rbf"; // download the watchdog program as a file to the brick con.CreateEV3File(filename, HexDumpToBytes(EV3Communication.Properties.Resources.WatchDog)); // before loading the watchdog program, check if there is no other program running ByteCodeBuffer c = new ByteCodeBuffer(); c.OP(0x0C); // opProgram_Info c.CONST(0x16); // CMD: GET_STATUS = 0x16 c.CONST(1); // program slot 1 = user slot c.GLOBVAR(8); // load and start it c.OP(0xC0); // opFILE c.CONST(0x08); // CMD: LOAD_IMAGE = 0x08 c.CONST(1); // slot 1 = user program slot c.STRING(filename); c.GLOBVAR(0); c.GLOBVAR(4); c.OP(0x03); // opPROGRAM_START c.CONST(1); // slot 1 = user program slot c.GLOBVAR(0); c.GLOBVAR(4); c.CONST(0); // after starting, check if indeed running now c.OP(0x0C); // opProgram_Info c.CONST(0x16); // CMD: GET_STATUS = 0x16 c.CONST(1); // program slot 1 = user slot c.GLOBVAR(9); // as additional startup-action, reset the hardware (sensors and motors) c.OP(0x99); // opInput_Device (CMD, …) c.CONST(0x0A); // CLR_ALL = 0x0A c.CONST(-1); // LAYER – Specify chain layer number [0-3] (-1 = All) byte[] response = con.DirectCommand(c, 10, 0); if (response == null || response[8] != 0x0040 || response[9] == 0x0040) { throw new Exception("Could not start EV3 remote client on device"); } // set up local ping thread to periodically send a command to the watchdog // program to keep it alive (and check if the brick is still operating) (new System.Threading.Thread(runpings)).Start(); } }
public byte[] DirectCommand(ByteCodeBuffer bytecodes, int globalbytes, int localbytes) { // increase message counter (neccesary to check if request and respond match) messagecounter++; byte[] sendpacket = new byte[2 + 1 + 2 + bytecodes.Length]; sendpacket[0] = (byte)(messagecounter & 0xff); sendpacket[1] = (byte)((messagecounter >> 8) & 0xff); sendpacket[2] = 0x00; // DIRECT_COMMAND_REPLY sendpacket[3] = (byte)(globalbytes & 0xff); sendpacket[4] = (byte)(((globalbytes >> 8) & 0x3) + (localbytes << 2)); bytecodes.CopyTo(sendpacket, 5); SendPacket(sendpacket); for (; ;) { byte[] packet = ReceivePacket(); if (packet.Length < 3) { throw new Exception("Reply has no message counter"); } // wait until reply arrives that has a counter that matches the command ushort ctr = (ushort)(packet[0] + (packet[1] << 8)); // Console.WriteLine("Expected counter: "+messagecounter+ " received counter: " + ctr); if (ctr != messagecounter) { continue; } // check if the direct command caused an error if (packet[2] == 0x04) { return(null); } // check if problems with received packet if (packet[2] != 0x02) { throw new Exception("Reply is not of correct type"); } if (packet.Length != globalbytes + 3) { throw new Exception("Reply size unexpected: " + packet.Length + " instead of " + (globalbytes + 3)); } // extract data byte[] replydata = new byte[packet.Length - 3]; System.Array.Copy(packet, 3, replydata, 0, packet.Length - 3); return(replydata); } }
public static byte[] DirectCommand(ByteCodeBuffer bytecodes, int globalbytes, int localbytes) { try { lock (sync) { // if not already done, memorize the start time and fire up the communication MemorizeStartTime(); EstablishConnection(); // if requested to only queue the command, and the queue is not too full, and there is no expected response if (queue_active && globalbytes == 0 && queue.Length + bytecodes.Length < 900) // prevent to exceed 1024 bytes in single transmission { bytecodes.CopyTo(queue); queue_locals = Math.Max(queue_locals, localbytes); queue_active = false; return(new byte[0]); } else { queue_active = false; // remove queue-status in any case } // if there is data in the queue, try to merge it with the new command if (queue.Length > 0) { // when total length is not too big, can send together with new command if (queue.Length + bytecodes.Length < 900) { bytecodes.CopyTo(queue); byte[] response = con.DirectCommand(queue, globalbytes, Math.Max(localbytes, queue_locals)); queue.Clear(); queue_locals = 0; return(response); } // if can not be merged, send queued commands seperately con.DirectCommand(queue, 0, queue_locals); queue.Clear(); queue_locals = 0; } // finally execute the command return(con.DirectCommand(bytecodes, globalbytes, localbytes)); } } catch (Exception) { // no connection - must terminate immediately System.Environment.Exit(1); } return(null); }
// Periodically modify a flag in the global variables of program slot 1. // The program in slot 1 is a watchdog program that will notice when this "pings" no longer // arrive and will stop itself and shut down motors and sensors gracefully. // On the other side, the pinger will monitor if the watchdog is still running (could have // been stopped manually by the user) and if so, terminates the Basic program also. private static void runpings() { ByteCodeBuffer c = new ByteCodeBuffer(); c.OP(0x3A); // Move32_32 c.CONST(42); // move this value c.GLOBVAR(0); // to gloval variable 0-3 c.OP(0x7E); // Memory_Write c.CONST(1); // program slot 1 = user slot c.CONST(0); // write to global variables c.CONST(0); // to global variable 0 c.CONST(4); // write 4 bytes c.GLOBVAR(0); // take the prepared value 42 c.OP(0x0C); // opProgram_Info c.CONST(0x16); // CMD: GET_STATUS = 0x16 c.CONST(1); // program slot 1 = user slot c.GLOBVAR(0); for (; ;) { lock (sync) { byte[] packet = null; try { packet = con.DirectCommand(c, 4, 0); } catch (Exception e) { throw e; } // detected communication error or watchdog progam is no longer running if (packet == null || packet.Length <= 0 || packet[0] == 0x40) { System.Environment.Exit(1); } } System.Threading.Thread.Sleep(500); } }
private static EV3Connection TestConnection(EV3Connection con) { try { // perform a tiny direct command to check if communication works ByteCodeBuffer c = new ByteCodeBuffer(); c.OP(0x30); // Move8_8 c.CONST(74); c.GLOBVAR(0); byte[] response = con.DirectCommand(c, 1, 0); if (response == null || response.Length != 1 || response[0] != 74) { throw new Exception("Test DirectCommand delivers wrong result"); } return(con); } catch (Exception e) { con.Close(); throw e; } }
public byte[] ReadEV3File(String fullname, ByteCodeBuffer pingercommand = null) { long nextping = DateTime.Now.Ticks + 500; int chunksize = 900; // start the transfer BinaryBuffer b = new BinaryBuffer(); b.Append16(0); // transfer no content right now b.AppendZeroTerminated(fullname); byte[] response = SystemCommand(BEGIN_UPLOAD, b); if (response == null) { throw new Exception("No response to BEGIN_UPLOAD"); } if (response.Length < 6) { throw new Exception("Response too short for BEGIN_UPLOAD"); } if (response[0] != SUCCESS && response[0] != END_OF_FILE) { throw new Exception("Unexpected status at BEGIN_UPLOAD: " + response[0]); } int len = ((int)response[1]) + (((int)response[2]) << 8) + (((int)response[3]) << 16) + (((int)response[4]) << 24); int handle = response[5] & 0xff; // Console.WriteLine("Start uploading file of size: " + len + ". handle=" + handle); byte[] buffer = new byte[len]; int pos = 0; // transfer bytes in small chunks while (pos < len) { int transfernow = Math.Min(len - pos, chunksize); b.Clear(); b.Append8(handle); b.Append16(transfernow); response = SystemCommand(CONTINUE_UPLOAD, b); if (response == null) { throw new Exception("No response to CONTINUE_UPLOAD"); } if (response.Length < 2 + transfernow) { throw new Exception("Response too short for CONTINUE_UPLOAD"); } if (response[0] != SUCCESS && response[0] != END_OF_FILE) { throw new Exception("Unexpected status at CONTINUE_UPLOAD: " + response[0]); } for (int i = 0; i < transfernow; i++) { buffer[pos + i] = response[2 + i]; } pos += transfernow; // check if it is necessary to send intermediary pings to the watchdog program if (pingercommand != null && DateTime.Now.Ticks > nextping) { DirectCommand(pingercommand, 4, 0); nextping = DateTime.Now.Ticks + 500; } } return(buffer); }