+/* $Id$
+
+This file is part of the MSP Märklin suite
+Copyright © 2006-2008 Mikkosoft Productions, Mikko Rasa
+Distributed under the GPL
+*/
+
+#include <cstring>
+#include <unistd.h>
+#include <msp/strings/formatter.h>
+#include "constants.h"
+#include "reply.h"
+
+using namespace std;
+using namespace Msp;
+
+namespace {
+
+unsigned read_all(int fd, char *buf, unsigned size)
+{
+ unsigned pos=0;
+ while(pos<size)
+ pos+=read(fd, buf+pos, size-pos);
+
+ return pos;
+}
+
+}
+
+namespace Marklin {
+
+Reply::Reply():
+ err(ERR_NO_ERROR),
+ len(0)
+{
+ memset(data, 0, 128);
+}
+
+Reply Reply::read(int fd, Cmd cmd)
+{
+ Reply result;
+
+ char *data=reinterpret_cast<char *>(result.data);
+
+ if(cmd==CMD_EVENT)
+ {
+ for(unsigned i=0; i<3; ++i)
+ {
+ result.len+=read_all(fd, data+i, 1);
+ if(!(result.data[i]&0x80))
+ break;
+ }
+ }
+ else if(cmd==CMD_EVENT_LOK)
+ {
+ for(unsigned i=0;; i+=5)
+ {
+ result.len+=read_all(fd, data+i, 1);
+
+ if(result.data[i]&0x80)
+ break;
+
+ result.len+=read_all(fd, data+i+1, 4);
+ }
+ }
+ else if(cmd==CMD_EVENT_TURNOUT)
+ {
+ result.len+=read_all(fd, data, 1);
+ result.len+=read_all(fd, data+1, result.data[0]*2);
+ }
+ else if(cmd==CMD_EVENT_SENSOR)
+ {
+ for(unsigned i=0;; i+=3)
+ {
+ result.len+=read_all(fd, data+i, 1);
+
+ if(result.data[i]==0)
+ break;
+
+ result.len+=read_all(fd, data+i+1, 2);
+ }
+ }
+ else
+ {
+ bool expect_errcode=(cmd!=CMD_STATUS);
+
+ unsigned expected_bytes=0;
+ if(cmd==CMD_STATUS || cmd==CMD_FUNC_STATUS || cmd==CMD_TURNOUT_STATUS)
+ expected_bytes=1;
+ if(cmd==CMD_SENSOR_STATUS || cmd==CMD_TURNOUT_GROUP_STATUS)
+ expected_bytes=2;
+ if(cmd==CMD_LOK_STATUS)
+ expected_bytes=3;
+ if(cmd==CMD_LOK_CONFIG)
+ expected_bytes=4;
+
+ if(expect_errcode)
+ {
+ char c;
+ read_all(fd, &c, 1);
+ result.err=static_cast<Error>(c);
+ }
+
+ if(result.err==ERR_NO_ERROR)
+ result.len+=read_all(fd, data, expected_bytes);
+ }
+
+ return result;
+}
+
+ostream &operator<<(ostream &out, const Reply &reply)
+{
+ out<<reply.err;
+ for(unsigned i=0; i<reply.len; ++i)
+ out<<format(" %02X", static_cast<int>(reply.data[i]));
+
+ return out;
+}
+
+} // namespace Marklin