31 #define dbg_printf if (dbg_flag) printf
33 WireTwiddlerWriter::~WireTwiddlerWriter() =
default;
36 int WireTwiddler::configure(
Bottle& desc,
int offset,
bool& ignored,
37 const std::string& vtag) {
40 bool is_vector =
false;
45 bool computing =
false;
53 if (kind==
"skip"||kind==
"compute") {
54 if (kind ==
"compute") {
61 if (kind.length()>0 && (kind[0]==
'>'||kind[0]==
'<')) {
62 saving = (kind[0]==
'>');
63 loading = (kind[0]==
'<');
65 var = kind.substr(1,kind.length());
70 is_vector = (kind==
"vector");
71 is_list = (kind==
"list");
72 if (kind==
"item_vector") {
85 if (is_vector||is_list) {
92 fprintf(stderr,
"Does not look like length: %s\n",
97 fprintf(stderr,
"List should have fixed length\n");
108 fprintf(stderr,
"Does not look like data: %s\n",
117 int wire_unit_length = -1;
123 if (kind==
"int8"||kind==
"uint8"||kind==
"bool") {
126 }
else if (kind==
"int16"||kind==
"uint16") {
129 }
else if (kind==
"int32"||kind==
"uint32") {
132 }
else if (kind==
"int64"||kind==
"uint64") {
135 }
else if (kind==
"float32") {
138 }
else if (kind==
"float64") {
141 }
else if (kind==
"vocab") {
144 }
else if (kind==
"string") {
148 }
else if (kind==
"blob") {
152 }
else if (kind==
"list"||kind==
"vector"||computing) {
155 fprintf(stderr,
"%s does not know about %s\n", __FILE__, kind.c_str());
159 dbg_printf(
"Type %s (%s) len %d unit %d %s\n",
161 is_list?
"LIST":(is_vector?
"VECTOR":
"PRIMITIVE"), len,
171 }
else if (is_list) {
186 buffer_start = (int)
buffer.size();
200 tmp.
copy(desc,start,offset-start-1);
211 offset = configure(desc,offset,ign,kind);
220 bool WireTwiddler::configure(
const char *txt,
const char *prompt) {
221 this->prompt = prompt;
223 std::string str(txt);
224 char *cstr = (
char *)str.c_str();
225 for (
size_t i=0; i<str.length(); i++) {
231 if (str.find(
"list") == std::string::npos &&
232 str.find(
"vector") == std::string::npos) {
248 next = configure(desc,at,ign,
"");
249 }
while (next>at&&next<desc.
size());
250 if (buffer_start!=(
int)
buffer.size()) {
254 buffer_start = (int)
buffer.size();
258 dbg_printf(
"gaps has %zu items\n", gaps.size());
259 for (
auto& gap : gaps) {
260 if (gap.buffer_length!=0) {
261 gap.byte_start = (
char *) (&
buffer[gap.buffer_start]);
262 gap.byte_length = gap.buffer_length*4;
264 gap.byte_start =
nullptr;
271 return at == desc.
size();
307 return "unsupported";
315 int len = msg.
size();
318 for (
int i=0; i<len; i++) {
338 for (
int i=0; i<len; i++) {
347 result += fromTemplate(*v.
asList());
354 void WireTwiddler::show() {
355 for (
size_t i=0; i<gaps.size(); i++) {
357 printf(
"Block #%zu (%s)\n", i, gap.
getOrigin().c_str());
363 printf(
" External data will be ignored\n");
374 for (
const auto& gap : gaps) {
383 if (gap.unit_length!=0) {
385 if (gap.length==-1 && gap.unit_length==-1) {
386 sprintf(buf,
" [4-byte length] [<length> instances of 4-byte-length bytes followed by specified number of bytes]");
387 }
else if (gap.length==-1) {
388 sprintf(buf,
" [4-byte length] [<length>*%d bytes]", gap.unit_length);
389 }
else if (gap.length==1) {
390 sprintf(buf,
" [%d bytes]", gap.unit_length);
392 sprintf(buf,
" [%d*%d bytes]", gap.length, gap.unit_length);
429 twiddled_output.
write(sos);
430 std::string result = sos.
toString();
438 if (gap.
var_name ==
"image_params") {
439 int w = prop.find(
"width").asInt32();
440 int h = prop.find(
"height").asInt32();
441 int step = prop.find(
"step").asInt32();
442 bool bigendian = prop.find(
"is_bigendian").asInt32()==1;
444 fprintf(stderr,
"Sorry, cannot handle bigendian images yet.\n");
447 std::string encoding = prop.find(
"encoding").asString();
449 int translated_encoding = 0;
470 yAssert(encoding==
"mono8"||encoding==
"mono16");
471 if (encoding ==
"mono8") {
482 if (encoding ==
"bayer_grbg8") {
485 fprintf(stderr,
"Warning automatic debayering not yet supported, keeping raw format.\n");
490 fprintf(stderr,
"Sorry, cannot handle [%s] images yet.\n",
498 while (quantum<=256) {
500 if (((w*bpp+quantum)/quantum)*quantum == step) {
509 int img_size = step*h;
511 prop.put(
"img_size",img_size);
512 prop.put(
"quantum",quantum);
513 prop.put(
"translated_encoding",translated_encoding);
520 dbg_printf(
"WireTwidderReader::read getting started\n");
522 int ct = twiddler.getGapCount();
524 fprintf(stderr,
"WireTwidderReader, nothing available\n");
533 fprintf(stderr,
"WireTwidderReader, nothing left\n");
545 if (byte_start !=
nullptr) {
546 byte_start += consumed;
547 byte_length -= consumed;
549 if (byte_start !=
nullptr && byte_length > 0) {
551 if (len>byte_length) {
554 memcpy(b.
get(),byte_start,len);
558 dbg_printf(
"WireTwidderReader sending %d boilerplate bytes:\n",len);
564 Bytes bytes(
reinterpret_cast<char*
>(&lengthBuffer),
sizeof(
NetInt32));
565 int r = is.readFull(bytes);
570 pending_length =
sizeof(lengthBuffer);
574 pending_strings = lengthBuffer;
575 pending_string_length = 0;
576 pending_string_data = 0;
582 override_length = lengthBuffer;
589 if (pending_length) {
591 if (len>pending_length) {
592 len = pending_length;
596 (
char*)(&lengthBuffer)+
sizeof(lengthBuffer)-pending_length,
598 pending_length -= len;
599 dbg_printf(
"WireTwidderReader sending %d length bytes:\n",len);
603 while (pending_strings) {
604 dbg_printf(
"### %d pending strings\n", pending_strings);
605 if (pending_string_length==0&&pending_string_data==0) {
607 Bytes bytes(
reinterpret_cast<char*
>(&lengthBuffer),
sizeof(
NetInt32));
608 int r = is.readFull(bytes);
613 pending_string_length =
sizeof(lengthBuffer);
614 pending_string_data = lengthBuffer;
616 if (pending_string_length) {
618 if (len>pending_string_length) {
619 len = pending_string_length;
623 (
char*)(&lengthBuffer)+
sizeof(lengthBuffer)-pending_string_length,
625 pending_string_length -= len;
626 dbg_printf(
"WireTwidderReader sending %d string length bytes:\n",len);
628 if (pending_string_length==0&&pending_string_data==0) { pending_strings--; }
631 if (pending_string_data) {
633 if (len>pending_string_data) {
634 len = pending_string_data;
637 int r = is.readFull(b2);
639 fprintf(stderr,
"No string payload bytes available\n");
642 pending_string_data -= r;
643 dbg_printf(
"WireTwidderReader sending %d string payload bytes\n",r);
644 if (pending_string_data==0) { pending_strings--; }
650 extern_length = override_length;
652 dbg_printf(
"extern_length %d\n", extern_length);
654 if (extern_length>sent-consumed) {
656 if (len>extern_length) {
662 r = readMapped(is,b2,gap);
664 dbg_printf(
"WireTwidderReader sending %d payload bytes:\n",r);
670 fprintf(stderr,
"No payload bytes available\n");
675 int len2 = extern_length;
679 dump.allocateOnNeed(len2,len2);
680 Bytes b3(dump.get(),len2);
682 auto* nn =
reinterpret_cast<NetInt32 *
> (dump.get());
684 if (override_length>=0) {
686 std::string((
char *)(dump.get()),
690 prop.find(gap.
var_name).asString().c_str());
691 }
else if (len2>=4) {
698 dbg_printf(
"WireTwidderReader sending %d payload bytes:\n",r);
700 dbg_printf(
" (ignoring %d payload bytes)\n",r);
711 override_length = -1;
717 fprintf(stderr,
"WireTwidderReader shrugging\n");
722 bool WireTwiddlerWriter::update() {
734 block = parent->headerLength();
735 lastBlock = parent->length()-block-1;
736 activeEmit =
nullptr;
737 activeEmitLength = 0;
738 activeEmitOffset = -1;
740 dbg_printf(
"Parent headers %zu blocks %zu\n", parent->headerLength(), parent->length());
742 for (
int i=0; i<twiddler->getGapCount(); i++) {
755 dbg_printf(
"Pass [4-byte length] [<length> instances of 4-byte-length bytes followed by specified number of bytes]\n");
756 readLengthAndPass(-1);
761 dbg_printf(
"Pass [4-byte length] [<length> bytes]\n");
762 readLengthAndPass(1);
763 }
else if (gap.
length==-1) {
769 dbg_printf(
"Need to tweak length (not correct for neg numbers yet)...\n");
770 for (
int i=0; i<gap.
length; i++) {
784 dbg_printf(
"%zu write blocks\n", srcs.size());
786 for (
size_t i=0; i<srcs.size(); i++) {
787 dbg_printf(
" write block %zu: len %d offset %d ptr %p\n", i, srcs[i].len, srcs[i].offset, srcs[i].src);
794 bool WireTwiddlerWriter::skip(
const char *start,
int len) {
796 return advance(len,
false,
false,
true);
799 bool WireTwiddlerWriter::pass(
int len) {
800 return advance(len,
true);
803 bool WireTwiddlerWriter::pad(
size_t len) {
806 for (
size_t i=0; i<len; i++) {
807 zeros.get()[i] =
'\0';
810 return emit(
zeros.get(),len);
813 bool WireTwiddlerWriter::readLengthAndPass(
int unitLength,
815 int len = readLength();
819 if (unitLength!=-1) {
821 advance(unitLength*len,
true);
823 for (
int i=0; i<len; i++) {
824 if (!transform(*gap)) {
830 for (
int i=0; i<len; i++) {
831 bool ok = readLengthAndPass(1,gap);
844 yError(
"Structure of message is unexpected (expected %s)", twiddler->getPrompt().c_str());
846 if (expected!=received) {
847 yError(
"Expected '%s', got '%s'\n",
857 int WireTwiddlerWriter::readLength() {
858 advance(4,
true,
true);
859 if (accumOffset==4) {
860 if (codeExpected!=codeReceived) {
861 if (lengthBuffer!=0) {
862 showBrokenExpectation(codeExpected,codeReceived,4);
864 codeExpected = codeReceived = 0;
871 bool WireTwiddlerWriter::advance(
int length,
bool shouldEmit,
872 bool shouldAccum,
bool shouldCheck) {
881 if (blockPtr ==
nullptr) {
882 blockPtr = parent->data(block);
883 blockLen = parent->length(block);
884 dbg_printf(
" block %d is at %ld, length %d\n",block,
885 (
long int)blockPtr, blockLen);
888 int rem = blockLen-offset;
892 if (block>lastBlock) {
902 dbg_printf(
"Type check against %ld\n", (
long int)activeCheck);
903 int result = memcmp(activeCheck,blockPtr+offset,rem);
909 t1 = *(
reinterpret_cast<const NetInt32*
>(blockPtr+offset));
910 t2 = *(
reinterpret_cast<const NetInt32*
>(activeCheck-rem));
921 showBrokenExpectation(t2,t1,rem);
927 emit(blockPtr+offset, rem);
930 if (accumOffset+rem>4) {
931 fprintf(stderr,
"ACCUMULATION GONE WRONG %d %d\n",
935 memcpy(lengthBytes.get()+accumOffset,blockPtr+offset,rem);
944 bool WireTwiddlerWriter::emit(
const char *src,
int len) {
946 if (src !=
nullptr) {
952 const auto* x =
reinterpret_cast<const NetFloat64*
>(src);
953 if (scratchOffset+4>scratch.length()) {
954 scratch.allocateOnNeed(scratchOffset+4,scratchOffset+4);
956 auto* y =
reinterpret_cast<NetFloat32*
>(scratch.get()+scratchOffset);
959 noffset = scratchOffset;
963 fprintf(stderr,
"WireTwidder::emit needs to be extended to deal with this case\n");
969 dbg_printf(
" cache %ld len %d offset %d /// activeEmit %ld %d %d\n", (
long int)src, len, noffset, (
long int) activeEmit, activeEmitLength, activeEmitOffset);
970 if (activeEmit !=
nullptr || activeEmitOffset >= 0) {
972 if (activeEmitOffset>=0 && noffset<0) {
974 }
else if (activeEmitOffset<0 && noffset>=0) {
976 }
else if (noffset==-1 && activeEmit+activeEmitLength!=src) {
980 dbg_printf(
" ** emit %ld len %d offset %d\n", (
long int)activeEmit,
981 activeEmitLength, activeEmitOffset);
982 srcs.emplace_back((
char*)activeEmit,activeEmitLength,activeEmitOffset);
983 activeEmit =
nullptr;
984 activeEmitLength = 0;
985 activeEmitOffset = -1;
987 activeEmitLength += len;
988 dbg_printf(
" ** extend %ld len %d offset %d\n", (
long int)activeEmit,
989 activeEmitLength, activeEmitOffset);
993 if (src !=
nullptr || noffset >= 0) {
995 activeEmitLength = len;
996 activeEmitOffset = noffset;
1014 fprintf(stderr,
"WireTwidder::transform needs to be extended to deal with this case\n");
1029 v = prop.find(gap.
var_name).asInt32();
1032 for (
size_t i=0; i<b.
length(); i++) {
1035 auto* nn =
reinterpret_cast<NetInt32 *
> (b.
get());
1044 for (
size_t i=0; i<b.
length(); i++) {
1064 dump.allocateOnNeed(len2,len2);
1065 Bytes b3(dump.get(),len2);
#define BOTTLE_TAG_FLOAT64
#define BOTTLE_TAG_STRING
#define BOTTLE_TAG_VOCAB32
#define BOTTLE_TAG_FLOAT32
std::string nameThatCode(int code)
A simple collection of objects that can be described and transmitted in a portable way.
static std::string describeBottleCode(int code)
Convert a numeric bottle code to a string.
void fromString(const std::string &text)
Initializes bottle from a string.
size_type size() const
Gets the number of elements in the bottle.
Value & get(size_type index) const
Reads a Value v from a certain part of the list.
void copy(const Bottle &alt, size_type first=0, size_type len=npos)
Copy all or part of another Bottle.
bool write(ConnectionWriter &writer) const override
Output a representation of the bottle to a network connection.
std::string toString() const override
Gives a human-readable textual representation of the bottle.
A simple abstraction for a block of bytes.
static bool readFromStream(PortReader &portable, InputStream &is)
static ConnectionWriter * createBufferedConnectionWriter()
Create a connection writer implementation that stores to a buffer which can be read later using getBu...
An abstraction for a block of bytes, with optional responsibility for allocating/destroying that bloc...
void copy()
Makes sure data block is owned, making a copy if necessary.
Minimal requirements for an efficient Writer.
virtual void write(OutputStream &os)
An OutputStream that produces a string.
std::string toString() const
A single value (typically within a Bottle).
virtual std::int32_t asInt32() const
Get 32-bit integer value.
virtual bool isList() const
Checks if value is a list.
virtual Bottle * asList() const
Get list value.
std::string toString() const override
Return a standard text representation of the content of the object.
virtual bool isInt32() const
Checks if value is a 32-bit integer.
virtual std::int32_t getCode() const
Get standard type code of value.
virtual std::string asString() const
Get string value.
size_t length() const
Get the length of the vector.
bool shouldIgnoreExternal() const
const std::string & getOrigin() const
std::string toString(const T &value)
convert an arbitrary type to string.
@ VOCAB_PIXEL_ENCODING_BAYER_GRBG8
std::string to_string(IntegerType x)
yarp::sig::Vector zeros(int s)
Creates a vector of zeros (defined in Math.h).
NetInt32 encode(const std::string &str)
Convert a string into a vocabulary identifier.
An interface to the operating system, including Port based communication.
yarp::conf::float32_t NetFloat32
Definition of the NetFloat32 type.
yarp::conf::float64_t NetFloat64
Definition of the NetFloat64 type.
std::int32_t NetInt32
Definition of the NetInt32 type.
constexpr yarp::conf::vocab32_t createVocab32(char a, char b=0, char c=0, char d=0)
Create a vocab from chars.
bool read(ImageOf< PixelRgb > &dest, const std::string &src, image_fileformat format=FORMAT_ANY)
bool write(const ImageOf< PixelRgb > &src, const std::string &dest, image_fileformat format=FORMAT_PPM)