From 1884b6ff1360a47cf2a24f00c91d54d05913e98c Mon Sep 17 00:00:00 2001
From: Josh Kropf <josh@slashdev.ca>
Date: Sun, 15 Feb 2009 12:55:56 -0500
Subject: [PATCH] Handle erase and loading of in use modules

---
 src/m_javaloader.cc |   33 +++++++++++++++++++++++++--------
 src/m_javaloader.h  |    2 +-
 src/packet.cc       |   43 +++++++++++++++++++++++++++++++++++++++++++
 src/packet.h        |    3 +++
 src/protocol.h      |    6 +++++-
 src/protostructs.h  |    8 ++++++++
 src/socket.cc       |   23 ++++++++++++++---------
 src/socket.h        |    3 +++
 8 files changed, 102 insertions(+), 19 deletions(-)

diff --git a/src/m_javaloader.cc b/src/m_javaloader.cc
index 7155173..490605c 100644
--- a/src/m_javaloader.cc
+++ b/src/m_javaloader.cc
@@ -564,18 +564,35 @@ void JavaLoader::LoadApp(CodFile &cod)
 	}
 }
 
-// This command is sent to avert that the data stream is finished
-void JavaLoader::StopStream(void)
+//
+// StopStream
+//
+/// Must be called at the end of a JavaLoader session.  The JL_GOODBYE
+/// command is sent to the device.  When the device responds with
+/// RESET_REQUIRED the device reset command will be sent when the
+/// socket is closed.
+///
+/// \return true when a device reset was required
+///
+bool JavaLoader::StopStream()
 {
-	// 7°/
-	unsigned char rawCommand[] = { 4, 0, 0x08, 0, 0x8d, 0, 0, 0 };
-	*((uint16_t*) rawCommand) = htobs(m_socket->GetSocket());
+	Data cmd(-1, 8), data(-1, 8), response;
 
-	Data command(rawCommand, sizeof(rawCommand));
-	Data response;
-	m_socket->PacketData(command, response);
+	JLPacket packet(cmd, data, response);
+	packet.Goodbye();
+	m_socket->Packet(packet);
 
 	m_StreamStarted = false;
+
+	if( packet.Command() == SB_COMMAND_JL_RESET_REQUIRED ) {
+		m_con.m_zero.SetResetOnClose(true);
+		return true;
+	}
+	else if( packet.Command() != SB_COMMAND_JL_ACK ) {
+		ThrowJLError("JavaLoader::StopStream", packet.Command());
+	}
+
+	return false;
 }
 
 void JavaLoader::SetTime(time_t when)
diff --git a/src/m_javaloader.h b/src/m_javaloader.h
index cd612fc..30225bf 100644
--- a/src/m_javaloader.h
+++ b/src/m_javaloader.h
@@ -208,7 +208,7 @@ public:
 	//////////////////////////////////
 	// API
 	void StartStream();
-	void StopStream(void);
+	bool StopStream();
 
 	// mid-stream operations
 	void SendStream(const unsigned char *buffer, int size);
diff --git a/src/packet.cc b/src/packet.cc
index ee0fcfd..e81d5e2 100644
--- a/src/packet.cc
+++ b/src/packet.cc
@@ -92,6 +92,42 @@ void ZeroPacket::GetAttribute(unsigned int object, unsigned int attribute)
 	m_send.ReleaseBuffer(size);
 }
 
+//
+// Echo
+//
+/// Builds command packet for sending echo request.  The parameter
+/// to this command is the number of microseconds elapsed since host
+/// computer startup.
+///
+void ZeroPacket::Echo(uint64_t us_ticks)
+{
+	size_t size = SB_SOCKET_PACKET_HEADER_SIZE + ECHO_COMMAND_SIZE;
+	MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(size));
+	Protocol::Packet &packet = *cpack;
+
+	packet.size = htobs(size);
+	packet.command = SB_COMMAND_ECHO;
+	packet.u.socket.socket = htobs(0x00ff);	// default non-socket request
+	packet.u.socket.sequence = 0;		// filled in by Socket class
+	packet.u.socket.u.echo.ticks = htobl(us_ticks);
+
+	m_send.ReleaseBuffer(size);
+}
+
+void ZeroPacket::Reset()
+{
+	size_t size = SB_SOCKET_PACKET_HEADER_SIZE;
+	MAKE_PACKETPTR_BUF(cpack, m_send.GetBuffer(size));
+	Protocol::Packet &packet = *cpack;
+
+	packet.size = htobs(size);
+	packet.command = SB_COMMAND_RESET;
+	packet.u.socket.socket = htobs(0x00ff);	// default non-socket request
+	packet.u.socket.sequence = 0;		// filled in by Socket class
+
+	m_send.ReleaseBuffer(size);
+}
+
 unsigned int ZeroPacket::ObjectID() const
 {
 	Protocol::CheckSize(m_receive, SB_SOCKET_PACKET_HEADER_SIZE);
@@ -137,6 +173,13 @@ unsigned char ZeroPacket::SocketSequence() const
 	return rpack->u.socket.sequence;	// sequence is a byte
 }
 
+uint8_t ZeroPacket::CommandResponse() const
+{
+	Protocol::CheckSize(m_receive, SB_SOCKET_PACKET_HEADER_SIZE);
+	MAKE_PACKET(rpack, m_receive);
+	return rpack->command;
+}
+
 
 
 //////////////////////////////////////////////////////////////////////////////
diff --git a/src/packet.h b/src/packet.h
index 61e8954..45e0514 100644
--- a/src/packet.h
+++ b/src/packet.h
@@ -91,6 +91,8 @@ public:
 	// packet building
 
 	void GetAttribute(unsigned int object, unsigned int attribute);
+	void Echo(uint64_t us_ticks);
+	void Reset();
 
 
 	//////////////////////////////////
@@ -102,6 +104,7 @@ public:
 	unsigned int RemainingTries() const;
 	unsigned int SocketResponse() const;
 	unsigned char SocketSequence() const;
+	uint8_t CommandResponse() const;
 };
 
 
diff --git a/src/protocol.h b/src/protocol.h
index 728eaae..1143aae 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -23,6 +23,10 @@
 #define __BARRY_PROTOCOL_H__
 
 // packet commands (Packet.command: has response codes too)
+#define SB_COMMAND_ECHO			0x01
+#define SB_COMMAND_ECHO_REPLY		0x02
+#define SB_COMMAND_RESET		0x03
+#define SB_COMMAND_RESET_REPLY		0x04
 #define SB_COMMAND_FETCH_ATTRIBUTE	0x05
 #define SB_COMMAND_FETCHED_ATTRIBUTE	0x06
 #define SB_COMMAND_SELECT_MODE		0x07
@@ -67,7 +71,7 @@
 // JavaLoader response
 #define SB_COMMAND_JL_ACK		0x64
 #define SB_COMMAND_JL_READY		0x01
-#define SB_COMMAND_JL_ERROR		0x78	// Device has accepted the application, but it can't installed !
+#define SB_COMMAND_JL_RESET_REQUIRED	0x78	// Occurs after GOODBYE when handheld reset is required
 #define SB_COMMAND_JL_COD_IN_USE	0x6c	// Perhaps "BUSY" is also a good name?
 #define SB_COMMAND_JL_COD_NOT_FOUND	0x69
 
diff --git a/src/protostructs.h b/src/protostructs.h
index 5c1454c..ef20635 100644
--- a/src/protostructs.h
+++ b/src/protostructs.h
@@ -399,6 +399,13 @@ struct ModeSelect
 	} __attribute__ ((packed)) response;
 } __attribute__ ((packed));
 
+struct Echo
+{
+	uint64_t	ticks;			// number of microseconds since
+						// host system startup
+} __attribute__ ((packed));
+#define ECHO_COMMAND_SIZE		(sizeof(Barry::Protocol::Echo))
+
 
 ///////////////////////////////////////////////////////////////////////////////
 // Protocol command structures
@@ -417,6 +424,7 @@ struct SocketCommand
 		AttributeFetch		fetch;
 		ModeSelect		mode;
 		uint8_t			raw[1];
+		Echo			echo;
 
 	} __attribute__ ((packed)) u;
 } __attribute__ ((packed));
diff --git a/src/socket.cc b/src/socket.cc
index b19c130..77d3124 100644
--- a/src/socket.cc
+++ b/src/socket.cc
@@ -68,7 +68,8 @@ SocketZero::SocketZero(	Device &dev,
 	m_halfOpen(false),
 	m_challengeSeed(0),
 	m_remainingTries(0),
-	m_sequencePacket(true)
+	m_sequencePacket(true),
+	m_resetOnClose(false)
 {
 }
 
@@ -568,6 +569,17 @@ void SocketZero::Close(Socket &socket)
 		throw Error("Socket: Bad CLOSED packet in Close");
 	}
 
+	if( m_resetOnClose ) {
+		Data send, receive;
+		ZeroPacket reset_packet(send, receive);
+		reset_packet.Reset();
+
+		Send(reset_packet);
+		if( reset_packet.CommandResponse() != SB_COMMAND_RESET_REPLY ) {
+			throw Error("Socket: Missing RESET_REPLY in Close");
+		}
+	}
+
 //	// and finally, there always seems to be an extra read of
 //	// an empty packet at the end... just throw it away
 //	try {
@@ -732,6 +744,7 @@ void Socket::PacketData(Data &send, Data &receive, int timeout)
 			case SB_COMMAND_JL_READY:
 			case SB_COMMAND_JL_ACK:
 			case SB_COMMAND_JL_HELLO_ACK:
+			case SB_COMMAND_JL_RESET_REQUIRED:
 				done = true;
 				break;
 
@@ -747,14 +760,6 @@ void Socket::PacketData(Data &send, Data &receive, int timeout)
 				}
 				break;
 
-			case SB_COMMAND_JL_ERROR: {
-				std::ostringstream oss;
-				oss << "Device can't install the application. Check that the application isn't already installed !";
-				eout(oss.str());
-				throw Error(oss.str());
-				}
-				break;
-
 			default:
 				// unknown packet, pass it up to the
 				// next higher code layer
diff --git a/src/socket.h b/src/socket.h
index d175885..304c36c 100644
--- a/src/socket.h
+++ b/src/socket.h
@@ -60,6 +60,8 @@ class BXEXPORT SocketZero
 
 	bool m_sequencePacket;
 
+	bool m_resetOnClose;
+
 private:
 	static void AppendFragment(Data &whole, const Data &fragment);
 	static unsigned int MakeNextFragment(const Data &whole, Data &fragment,
@@ -79,6 +81,7 @@ protected:
 	bool GetSequencePacket() { return m_sequencePacket; }
 
 public:
+	void SetResetOnClose(bool flag) { m_resetOnClose = flag; }
 	void SetSequencePacket(bool flag) { m_sequencePacket = flag; }
 	explicit SocketZero(SocketRoutingQueue &queue, int writeEndpoint,
 		uint8_t zeroSocketSequenceStart = 0);
-- 
1.6.1.3

