bool BootProtocolProcess(const void* data, size_t data_len) { assert(!data_len || data); while (data_len > 0) { if (data_len >= rx_message_remaining) { if (rx_message_state == WAIT_FILE) { int i; for (i = 0; i < rx_message_remaining; ++i) file_checksum += ((const uint8_t *) data)[i]; if (!IOIOFileHandleBuffer(data, rx_message_remaining)) return false; } else { // copy a chunk of data to rx_msg memcpy(((BYTE *) &rx_msg) + rx_buffer_cursor, data, rx_message_remaining); rx_buffer_cursor += rx_message_remaining; } data += rx_message_remaining; data_len -= rx_message_remaining; rx_message_remaining = 0; } else { if (rx_message_state == WAIT_FILE) { int i; for (i = 0; i < data_len; ++i) file_checksum += ((const uint8_t *) data)[i]; if (!IOIOFileHandleBuffer(data, data_len)) return false; } else { // copy a chunk of data to rx_msg memcpy(((BYTE *) &rx_msg) + rx_buffer_cursor, data, data_len); rx_buffer_cursor += data_len; } rx_message_remaining -= data_len; data_len = 0; } // change state if (rx_message_remaining == 0) { switch (rx_message_state) { case WAIT_TYPE: rx_message_state = WAIT_ARGS; if (rx_msg.type >= MESSAGE_TYPE_LIMIT) { log_printf("Unexpected message type: 0x%x", rx_msg.type); return false; } rx_message_remaining = incoming_arg_size[rx_msg.type]; if (rx_message_remaining) break; // fall-through on purpose case WAIT_ARGS: rx_message_state = WAIT_TYPE; rx_message_remaining = 1; rx_buffer_cursor = 0; if (!MessageDone()) return false; if (rx_message_remaining) break; // fall-through on purpose case WAIT_FILE: if (!IOIOFileDone()) { log_printf("Unexpected end of file"); return false; } else { log_printf("Image done successfully"); } SendChecksum(file_checksum); rx_message_state = WAIT_TYPE; rx_message_remaining = 1; break; } } } return true; }
//----------------------------------------------------------------------------- // Test binary data transmission. // Format in: // <byte size>:<mode> // Format out: // <4 bytes binary checksum><#size bytes data> // If echo mode, also: // Format in: // <#size bytes data> // Format out: // OK/ER - according to CRC match on incomin data // Format in: // DONE // // To Do: // o Add mode/flag specifying 5-8 bit transfer. // Test that 0xff gets masked off accordingly when transfered. // (This should be an INFO result if failing) // o Clean up the DUPLEX_ECHO implementation. Currently it's an ugly hack // that doesn't match the arguments / behavior of the two other modes. void CeCosTestSerialFilter::CMD_TestBinary(CeCosSerial &pSer, char* args) { int size; cyg_mode_t mode; unsigned char *data_out, *data_in; int i; int crc; int loop_count = 0; INIT_VALUE(args); SET_VALUE(int, size); SET_VALUE(cyg_mode_t, mode); // Change behavior for DUPLEX mode. if (MODE_DUPLEX_ECHO == mode) { loop_count = size; size = 1024; // must be at least 4*block_size } // Generate data. data_out = (unsigned char*) malloc(size); if (!data_out) { fprintf(stderr, "Could not allocate %d byte buffer for data!\n", size); throw "data_out malloc failed"; } data_in = (unsigned char*) malloc(size); if (!data_in) { fprintf(stderr, "Could not allocate %d byte buffer for data!\n", size); throw "data_in malloc failed"; } int count = 0; for (i = 0; i < size; i++) { // Output 255 chars, not 256 so that we aren't a multiple/factor of the // likely buffer sizes in the system, this can mask problems as I've // found to my cost! unsigned char c = (unsigned char) (count++ % 255); // don't allow $s and @s in the data, nor 0x03 (GDB C-c), nor flow // control chars if ('$' == c || '@' == c || 0x03 == c || 0x11 == c || 0x13 == c) c = (unsigned char) '*'; data_out[i] = c; } // Do checksum. crc = DoCRC(data_out, size); // Send checksum to target. SendChecksum(pSer, crc); // Give the target 1/10th of a sec to digest it CeCosThreadUtils::Sleep(100); switch (mode) { case MODE_NO_ECHO: { // Simple transmit. Don't expect target to echo data back. TargetWrite(pSer, data_out, size); ReceiveDone(pSer, NULL, 0); } break; case MODE_EOP_ECHO: { int in_crc; TargetWrite(pSer, data_out, size); Trace("Finished write, waiting for target echo.\n"); // Expect target to echo the data TargetRead(pSer, data_in, size); // Check echoed data, and reply OK/ER accordingly. in_crc = DoCRC(data_in, size); SendStatus(pSer, (in_crc == crc)); // Dump seen/expected on console. if (in_crc != crc) { Trace("Data seen:\n"); PrintHex(data_in, size); Trace("<end>\n"); Trace("Data expected:\n"); PrintHex(data_out, size); Trace("<end>\n"); } ReceiveDone(pSer, data_in, size); } break; case MODE_DUPLEX_ECHO: { int block_size = 64; int fail, j; // This is a simple implementation (maybe too simple). // Host sends 4 packets with the same size (64 bytes atm). // Target echoes in this way: // packet1 -> packet1 // packet2 -> packet2, packet2 // packet3 -> packet3 // packet4 -> /dev/null // // The reads/writes are interleaved in a way that should ensure // the target out buffer to be full before the target starts to read // packet3. That is, the target should be both receiving (packet3) // and sending (packet2) at the same time. // This code needs restructuring. It's not very obvious what's // happening: The same block of data is output several times, // the target echoes the data back (one of the blocks is // echoed twice). Then the echoed data is compared agains the // outgoing data block. fail = 0; while (loop_count--) { int i; for (i = 0; i < block_size*4; i++) data_in[i] = 0; // out1: block_size -> block_size TargetWrite(pSer, data_out, block_size); // out2: block_size -> 2 x block_size TargetWrite(pSer, data_out, block_size); // in1: TargetRead(pSer, data_in, block_size); // out3: block_size -> block_size TargetWrite(pSer, data_out, block_size); // in2: TargetRead(pSer, &data_in[block_size], 2*block_size); // out4: block_size -> 0 TargetWrite(pSer, data_out, block_size); // in3: TargetRead(pSer, &data_in[block_size*3], block_size); if (0 == loop_count % 10) Trace("%d loops to go\n", loop_count); // Verify data. if (!fail) { for (j = 0; j < 4 && !fail; j++) { for (i = 0; i < block_size && !fail; i++) { if (data_out[i] != data_in[j*block_size + i]) { fail = 1; Trace("Failed at byte %d\n", j*block_size + i); Trace("Data seen:\n"); PrintHex(&data_in[j*block_size], block_size); Trace("<end>\n"); Trace("Data expected:\n"); PrintHex(data_out, block_size); Trace("<end>\n"); } } } } } // Check echoed data, and reply OK/ER accordingly. SendStatus(pSer, (!fail)); ReceiveDone(pSer, data_in, block_size*4); } break; default: Trace("Unknown mode. Ignoring.\n"); } // Free buffer. free(data_in); free(data_out); }