예제 #1
0
void FLIP2D::step(float dt)
{
    LOG_OUTPUT("Stepping with dt = " << dt << " seconds.");
    float tStep = 0;
    while (tStep < dt) {
        _grid->sampleVelocities(_particles);
        const float t = min(_grid->CFL(), dt - tStep);
        if (t != dt) {
            LOG_OUTPUT("Substepping with dt = " << dt << " seconds.");
        }
        
        _fluid->reconstructSurface(_particles, _settings->R, _settings->r);
        _fluid->reinitialize(_settings->numPhiSweepIterations);
        _fluid->extrapolateIntoSolid(_solid);
        _grid->applyGravity(_settings->gravity, t);
        _grid->extrapolateVelocities(_fluid, _settings->numVelSweepIterations);
        _pressureSolver->buildLinearSystem(_grid, _solid, _fluid, t);
        _pressureSolver->solveLinearSystem(_fluid, t);
        _grid->pressureProjection(_pressureSolver->pressure(), _fluid, t);
        _grid->extrapolateVelocities(_fluid, _settings->numVelSweepIterations);
        _grid->enforceBoundaryConditions(_solid);
        _particles->advect(_grid->u(), _grid->v(), t);
        _particles->updateVelocities(_grid->u(), _grid->v());
        tStep += t;
    }
}
예제 #2
0
파일: openocd.c 프로젝트: EmuxEvans/openocd
/* normally this is the main() function entry, but if OpenOCD is linked
 * into application, then this fn will not be invoked, but rather that
 * application will have it's own implementation of main(). */
int openocd_main(int argc, char *argv[])
{
	int ret;

	/* initialize commandline interface */
	struct command_context *cmd_ctx;

	cmd_ctx = setup_command_handler(NULL);

	if (util_init(cmd_ctx) != ERROR_OK)
		return EXIT_FAILURE;

	if (ioutil_init(cmd_ctx) != ERROR_OK)
		return EXIT_FAILURE;

	LOG_OUTPUT("For bug reports, read\n\t"
		"http://openocd.sourceforge.net/doc/doxygen/bugs.html"
		"\n");

	command_context_mode(cmd_ctx, COMMAND_CONFIG);
	command_set_output_handler(cmd_ctx, configuration_output_handler, NULL);

	/* Start the executable meat that can evolve into thread in future. */
	ret = openocd_thread(argc, argv, cmd_ctx);

	unregister_all_commands(cmd_ctx, NULL);

	/* free commandline interface */
	command_done(cmd_ctx);

	adapter_quit();

	return ret;
}
예제 #3
0
파일: sdf.cpp 프로젝트: karlssonper/flip2D
void SolidSDF::createWeights(const CornerArray2f & phi,
                             FaceArray2Xf & uw,
                             FaceArray2Yf & vw)
{
    LOG_OUTPUT("Creating solid/fluid weights for velocities.");
    int iEnd = uw.nx() - 1;
    for (int j = 0; j < uw.ny(); ++j) {
        for (int i = 0; i < uw.nx(); ++i) {
            uw.face<LEFT>(i,j) = _weight(phi.corner<TOP_LEFT>(i,j),
                                         phi.corner<BOTTOM_LEFT>(i,j));
        }
        uw.face<RIGHT>(iEnd,j) = _weight(phi.corner<TOP_RIGHT>(iEnd,j),
                                         phi.corner<BOTTOM_RIGHT>(iEnd,j));
    }
        
    int jEnd = vw.ny() - 1;
    for (int i = 0; i < vw.nx(); ++i) {
        for (int j = 0; j < vw.ny(); ++j) {
            vw.face<BOTTOM>(i,j) = _weight(phi.corner<BOTTOM_RIGHT>(i,j),
                                           phi.corner<BOTTOM_LEFT>(i,j));
        }
        vw.face<TOP>(i,jEnd) = _weight(phi.corner<TOP_RIGHT>(i,jEnd),
                                       phi.corner<TOP_LEFT>(i,jEnd));
    }
}
예제 #4
0
/* normally this is the main() function entry, but if OpenOCD is linked
 * into application, then this fn will not be invoked, but rather that
 * application will have it's own implementation of main(). */
int openocd_main(int argc, char *argv[])
{
	int ret;

	/* initialize commandline interface */
	command_context_t *cmd_ctx;

	cmd_ctx = setup_command_handler();

#if BUILD_IOUTIL
	if (ioutil_init(cmd_ctx) != ERROR_OK)
	{
		return EXIT_FAILURE;
	}
#endif

	LOG_OUTPUT("\n\nBUGS? Read http://svn.berlios.de/svnroot/repos/openocd/trunk/BUGS\n\n\n");

	print_version();

	command_context_mode(cmd_ctx, COMMAND_CONFIG);
	command_set_output_handler(cmd_ctx, configuration_output_handler, NULL);

	if (parse_cmdline_args(cmd_ctx, argc, argv) != ERROR_OK)
		return EXIT_FAILURE;

	ret = parse_config_file(cmd_ctx);
	if ( (ret != ERROR_OK) && (ret != ERROR_COMMAND_CLOSE_CONNECTION) )
		return EXIT_FAILURE;

#if BUILD_HTTPD
	if (httpd_start()!=ERROR_OK)
		return EXIT_FAILURE;
#endif

	if (ret != ERROR_COMMAND_CLOSE_CONNECTION)
	{
		command_context_mode(cmd_ctx, COMMAND_EXEC);
		if (command_run_line(cmd_ctx, "init")!=ERROR_OK)
			return EXIT_FAILURE;

		/* handle network connections */
		server_loop(cmd_ctx);
	}

	/* shut server down */
	server_quit();

#if BUILD_HTTPD
	httpd_stop();
#endif

	unregister_all_commands(cmd_ctx);

	/* free commandline interface */
	command_done(cmd_ctx);


	return EXIT_SUCCESS;
}
예제 #5
0
FLIP2D::FLIP2D(Settings::Ptr s) : _settings(s)
{
    LOG_OUTPUT("Initiating FLIP2D simulation");
    
    _grid = Grid::create(s);
    _particles = Particles::create();
    _fluid = FluidSDF::create(s);
    _solid = SolidSDF::create(s);

    if (s->usePCG) {
        _pressureSolver = PCG::create(s);
    } else if (s->useMultigrid) {
        _pressureSolver = Multigrid::create(s);
    } else if (s->useGaussSeidel) {
        _pressureSolver = GaussSeidel::create(s);
    } else if (s->useJacobi) {
        _pressureSolver = Jacobi::create(s);
    } else {
        LOG_ERROR("Could not create a pressure solver.");
    }

    // Init Solid SDF and spawn fluid particles
    _solid->initBoxBoundary(s->solidWidth);
    _particles->initSphere(_solid->phi(),
                           _settings->initialFluidCenter,
                           _settings->initialFluidRadius,
                           _settings->particlesPerCell,
                           _settings->initialVelocity);
}
예제 #6
0
void Particles::updateVelocities(const FaceArray2Xf & u, const FaceArray2Yf & v)
{
    LOG_OUTPUT("Updating particle velocities from grid.");
    for(int i = 0; i < _pos.size(); ++i) {
        _vel[i] = Vec2f(u.bilerp(_pos[i]), v.bilerp(_pos[i]));
    }
}
예제 #7
0
void Particles::advect(const FaceArray2Xf & u, const FaceArray2Yf & v, float dt)
{
    LOG_OUTPUT("Advecting particles position in the grid velocity field");
    Vec2f mid;
    for(int i = 0; i < _pos.size(); ++i) {
        mid = _pos[i] + 0.5f * dt * Vec2f(u.bilerp(_pos[i]),v.bilerp(_pos[i]));
        _pos[i] = mid + 0.5f * dt * Vec2f(u.bilerp(mid), v.bilerp(mid));
    }
}
예제 #8
0
파일: sdf.cpp 프로젝트: karlssonper/flip2D
void FluidSDF::extrapolateIntoSolid(const CornerArray2f & solid, Array2f & phi)
{
    LOG_OUTPUT("Extrapolating fluid surface into solid.");
    for (int i = 0; i < phi.nx(); ++i) {
        for (int j = 0; j < phi.ny(); ++j) {
            if (phi(i,j) < 0.5 * phi.dx() && solid.center(i,j) < 0) {
                phi(i,j) = -0.5f * phi.dx();
            }
        }
    }
}
예제 #9
0
파일: sdf.cpp 프로젝트: karlssonper/flip2D
void FluidSDF::reinitialize(int numSwepIterations)
{
    LOG_OUTPUT("Reinitializing fluid SDF with " << numSwepIterations <<
               " sweep iterations");
    for (int i = 0; i < numSwepIterations; ++i) {
        _sweep(1,_phi.nx(), 1,_phi.ny());
        _sweep(_phi.nx() - 2, -1,_phi.ny() - 2, -1);
        _sweep(1, _phi.nx(), _phi.ny() - 2, -1);
        _sweep(_phi.nx()-2, -1, 1, _phi.ny());
    }
}
예제 #10
0
파일: lt.c 프로젝트: dparnell/raopd
void lt(struct lt_facility *custom_facility,
        lt_mask_t mask,
        lt_level_t level,
        const char *file,
        const char *function,
        int line,
        const char *fmt,
        ...)
{
    va_list args;
    struct lt_facility *facility;
    char msg[MAX_LT_MSG_LEN];
    char file_func_line[MAX_FUNCTION_NAME_LEN];
    char bits[128];
    size_t used = 0, func_name_used;
    int i;

    bits_to_string((uint64_t)mask, sizeof(mask), bits, sizeof(bits));

    facility = (custom_facility ? custom_facility : &default_facility);

    if ((*facility).masks[level] & mask) {

        func_name_used = syscalls_snprintf(file_func_line,
                                           sizeof(file_func_line),
                                           "%s:%d %s ",
                                           file, line, function);

        for (i = 0 ; i < MAX_FUNCTION_NAME_LEN ; i++) {
            func_name_used += syscalls_snprintf(file_func_line +
                                                func_name_used,
                                                sizeof(file_func_line) -
                                                func_name_used, " ");
        }

        used += syscalls_snprintf(msg + used, sizeof(msg) - used,
                                  "%s ", file_func_line);

        va_start(args, fmt);
        used += syscalls_vsnprintf(msg + used, sizeof(msg) - used, fmt, args);
        va_end(args);

        if (used == MAX_LT_MSG_LEN) {
            msg[MAX_LT_MSG_LEN - 1] = '\n';
        }

        LOG_OUTPUT("%s", msg);
    }

    return;
}
예제 #11
0
bool FLIP2D::write(const char * filename) const
{
    std::ofstream out(filename, std::ios::out | std::ios::binary);
    if (out.is_open()) {
        LOG_OUTPUT("Writing simulation output to " << filename);
        _settings->write(out);
        _particles->write(out);    
        out.close();
        return true;
    } else {
        LOG_ERROR("Could not write simulation output to " << filename);
        return false;
    }
}
예제 #12
0
bool FLIP2D::read(const char * filename, Settings::Ptr s, Particles::Ptr p)
{
    std::ifstream in(filename, std::ios::in | std::ios::binary);
    if (in.is_open()) {
        LOG_OUTPUT("Reading simulation input from " << filename);
        s->read(in);
        p->read(in);
        in.close();
        return true;
    } else {
        LOG_ERROR("Could not read simulation input from " << filename);
        return false;
    }
}
예제 #13
0
void print_version(void)
{
	/* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
	/* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
	/* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
	/* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
	/* DANGER!!! make sure that the line below does not appear in a patch, do not remove */
	LOG_OUTPUT("$URL: http://svn.berlios.de/svnroot/repos/openocd/trunk/src/openocd.c $\n");
	/* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
	/* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
	/* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
	/* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
	/* DANGER!!! make sure that the line above does not appear in a patch, do not remove */
}
예제 #14
0
static int embKernel_get_tasks_details(struct rtos *rtos, int64_t iterable, const struct embKernel_params *param,
                                       struct thread_detail *details, const char* state_str)
{
    int64_t task = 0;
    int retval = target_read_buffer(rtos->target, iterable + param->iterable_task_owner_offset, param->pointer_width,
                                    (uint8_t *) &task);
    if (retval != ERROR_OK)
        return retval;
    details->threadid = (threadid_t) task;
    details->exists = true;
    details->display_str = NULL;

    int64_t name_ptr = 0;
    retval = target_read_buffer(rtos->target, task + param->thread_name_offset, param->pointer_width,
                                (uint8_t *) &name_ptr);
    if (retval != ERROR_OK)
        return retval;

    details->thread_name_str = malloc(EMBKERNEL_MAX_THREAD_NAME_STR_SIZE);
    if (name_ptr) {
        retval = target_read_buffer(rtos->target, name_ptr, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE,
                                    (uint8_t *) details->thread_name_str);
        if (retval != ERROR_OK)
            return retval;
        details->thread_name_str[EMBKERNEL_MAX_THREAD_NAME_STR_SIZE - 1] = 0;
    } else {
        snprintf(details->thread_name_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "NoName:[0x%08X]", (unsigned int) task);
    }

    int64_t priority = 0;
    retval = target_read_buffer(rtos->target, task + param->thread_priority_offset, param->thread_priority_width,
                                (uint8_t *) &priority);
    if (retval != ERROR_OK)
        return retval;
    details->extra_info_str = malloc(EMBKERNEL_MAX_THREAD_NAME_STR_SIZE);
    if (task == rtos->current_thread) {
        snprintf(details->extra_info_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "Pri=%u, Running",
                 (unsigned int) priority);
    } else {
        snprintf(details->extra_info_str, EMBKERNEL_MAX_THREAD_NAME_STR_SIZE, "Pri=%u, %s", (unsigned int) priority,
                 state_str);
    }

    LOG_OUTPUT("Getting task details: iterable=0x%08X, task=0x%08X, name=%s\n", (unsigned int)iterable,
               (unsigned int)task, details->thread_name_str);
    return 0;
}
예제 #15
0
/* NB! this fn can be invoked outside this file for non PC hosted builds
 * NB! do not change to 'static'!!!!
 */
struct command_context *setup_command_handler(Jim_Interp *interp)
{
	log_init();
	LOG_DEBUG("log_init: complete");

	const char *startup = openocd_startup_tcl;
	struct command_context *cmd_ctx = command_init(startup, interp);

	/* register subsystem commands */
	typedef int (*command_registrant_t)(struct command_context *cmd_ctx_value);
	static const command_registrant_t command_registrants[] = {
		&openocd_register_commands,
		&server_register_commands,
		&gdb_register_commands,
		&log_register_commands,
		&transport_register_commands,
		&interface_register_commands,
		&bitbang_register_commands,
		&swd_register_commands,
		&target_register_commands,
		&flash_register_commands,
		&nand_register_commands,
		&pld_register_commands,
		&mflash_register_commands,
		NULL
	};
	for (unsigned i = 0; NULL != command_registrants[i]; i++)
	{
		int retval = (*command_registrants[i])(cmd_ctx);
		if (ERROR_OK != retval)
		{
			command_done(cmd_ctx);
			return NULL;
		}
	}
	LOG_DEBUG("command registration: complete");

	LOG_OUTPUT(OPENOCD_VERSION "\n"
			"Licensed under GNU GPL v2\n");

	global_cmd_ctx = cmd_ctx;

	return cmd_ctx;
}
예제 #16
0
파일: sdf.cpp 프로젝트: karlssonper/flip2D
void SolidSDF::initBoxBoundary(int width)
{
    LOG_OUTPUT("Initiating solid SDF with box boundaries.");
    _phi.set(-1.5f + width + 3);
    float x = -1.5f;
    int m = 0;
    while (m < width + 3) {
        for (int i = m; i < _phi.nx() - m; ++i) {
            _phi.corner<BOTTOM_LEFT>(i,m) = x * _phi.dx();
            _phi.corner<TOP_RIGHT>(i,_phi.ny()-1-m) = x * _phi.dx();
        }
    
        for (int j = m; j < _phi.ny() - m; ++j) {
            _phi.corner<TOP_LEFT>(m,j) = x * _phi.dx();;
            _phi.corner<BOTTOM_RIGHT>(_phi.nx()-1-m,j) = x * _phi.dx();;
        }
        ++m;
        x+= 1.0f;
    }
}
예제 #17
0
void Particles::initSphere(const Array2f & solidPhi,
                           const Vec2f & center,
                           float radius,
                           int particlesPerCell,
                           Vec2f vel)
{
    LOG_OUTPUT("Initating the fluid as a sphere at " << vel);
    const float r2 = sqr(radius);
    for (int i = 0; i < solidPhi.nx(); ++i) {
        for (int j = 0; j < solidPhi.ny(); ++j) {
            for (int n = 0; n < particlesPerCell; ++n) {
                const Vec2f offset(random(-0.495, 0.495),random(-0.495, 0.495));
                const Vec2f pos = solidPhi.pos(i,j) + solidPhi.dx() * offset;
                const Vec2f d = pos - center;

                // Inside test
                if (sqr(d.x) + sqr(d.y) - r2 < 0 && solidPhi.bilerp(pos) >= 0) {
                    addParticle(pos, vel);
                }
            }
        }
    }
}
예제 #18
0
command_context_t *setup_command_handler(void)
{
	command_context_t *cmd_ctx;

	global_cmd_ctx = cmd_ctx = command_init();

	register_command(cmd_ctx, NULL, "version", handle_version_command,
					 COMMAND_EXEC, "show OpenOCD version");

	/* register subsystem commands */
	server_register_commands(cmd_ctx);
	telnet_register_commands(cmd_ctx);
	gdb_register_commands(cmd_ctx);
	tcl_register_commands(cmd_ctx); /* tcl server commands */
	log_register_commands(cmd_ctx);
	jtag_register_commands(cmd_ctx);
	xsvf_register_commands(cmd_ctx);
	svf_register_commands(cmd_ctx);
	target_register_commands(cmd_ctx);
	flash_register_commands(cmd_ctx);
	nand_register_commands(cmd_ctx);
	pld_register_commands(cmd_ctx);
	mflash_register_commands(cmd_ctx);

	if (log_init(cmd_ctx) != ERROR_OK)
	{
		exit(-1);
	}
	LOG_DEBUG("log init complete");

	LOG_OUTPUT( OPENOCD_VERSION "\n" );

	register_command(cmd_ctx, NULL, "init", handle_init_command,
					 COMMAND_ANY, "initializes target and servers - nop on subsequent invocations");

	return cmd_ctx;
}
예제 #19
0
파일: sdf.cpp 프로젝트: karlssonper/flip2D
void FluidSDF::reconstructSurface(Particles::Ptr particles, float R, float r)
{
    LOG_OUTPUT("Reconstructing fluid surface.");
    assert(R && r);
    _sum.reset();
    _pAvg.reset();
    
    int nx = _phi.nx();
    int ny = _phi.ny();
    
    for (int p = 0; p < particles->numParticles(); ++p) {
        const int ci = particles->pos(p).x / _phi.dx();
        const int cj = particles->pos(p).y / _phi.dx();
        assert(ci < _phi.nx() && cj < _phi.ny());

        for (int i = std::max(0,ci-2); i < std::min(nx,ci+2); ++i) {
            for (int j = std::max(0,cj-2); j < std::min(ny,cj+2); ++j) {
                const Vec2f xd = particles->pos(p) - _phi.pos(i,j);
                const float k = _kernel(xd.length() / R);
                _sum(i,j) +=  k;
                _pAvg(i,j) += k * particles->pos(p);
            }
        }
    }
    
    for (int i = 0; i < _phi.nx(); ++i) {
        for (int j = 0; j < _phi.ny(); ++j) {
            if (_sum(i,j) > 0) {
                _pAvg(i,j) *= (1.0f / _sum(i,j));
                const Vec2f xd = _phi.pos(i,j) - _pAvg(i,j);
                _phi(i,j) = xd.length() - r;
            } else {
                _phi(i,j) = _phi.dx() * 1e15;
            }
        }
    }
}
예제 #20
0
int rtos_generic_stack_read(struct target *target,
	const struct rtos_register_stacking *stacking,
	int64_t stack_ptr,
	char **hex_reg_list)
{
	int list_size = 0;
	char *tmp_str_ptr;
	int64_t new_stack_ptr;
	int i;
	int retval;

	if (stack_ptr == 0) {
		LOG_ERROR("Error: null stack pointer in thread");
		return -5;
	}
	/* Read the stack */
	uint8_t *stack_data = malloc(stacking->stack_registers_size);
	uint32_t address = stack_ptr;

	if (stacking->stack_growth_direction == 1)
		address -= stacking->stack_registers_size;
	retval = target_read_buffer(target, address, stacking->stack_registers_size, stack_data);
	if (retval != ERROR_OK) {
		free(stack_data);
		LOG_ERROR("Error reading stack frame from thread");
		return retval;
	}
	LOG_DEBUG("RTOS: Read stack frame at 0x%" PRIx32, address);

#if 0
		LOG_OUTPUT("Stack Data :");
		for (i = 0; i < stacking->stack_registers_size; i++)
			LOG_OUTPUT("%02X", stack_data[i]);
		LOG_OUTPUT("\r\n");
#endif
	for (i = 0; i < stacking->num_output_registers; i++)
		list_size += stacking->register_offsets[i].width_bits/8;
	*hex_reg_list = malloc(list_size*2 + 1);
	tmp_str_ptr = *hex_reg_list;
	if (stacking->calculate_process_stack != NULL) {
		new_stack_ptr = stacking->calculate_process_stack(target,
				stack_data, stacking, stack_ptr);
	} else {
		new_stack_ptr = stack_ptr - stacking->stack_growth_direction *
			stacking->stack_registers_size;
	}
	for (i = 0; i < stacking->num_output_registers; i++) {
		int j;
		for (j = 0; j < stacking->register_offsets[i].width_bits/8; j++) {
			if (stacking->register_offsets[i].offset == -1)
				tmp_str_ptr += sprintf(tmp_str_ptr, "%02x", 0);
			else if (stacking->register_offsets[i].offset == -2)
				tmp_str_ptr += sprintf(tmp_str_ptr, "%02x",
						((uint8_t *)&new_stack_ptr)[j]);
			else
				tmp_str_ptr += sprintf(tmp_str_ptr, "%02x",
						stack_data[stacking->register_offsets[i].offset + j]);
		}
	}
	free(stack_data);
/*	LOG_OUTPUT("Output register string: %s\r\n", *hex_reg_list); */
	return ERROR_OK;
}
예제 #21
0
파일: rtos.c 프로젝트: Xplorer001/openocd
int gdb_thread_packet(struct connection *connection, char *packet, int packet_size)
{
	struct target *target = get_target_from_connection(connection);

	if (strstr(packet, "qThreadExtraInfo,"))
	{
		if ((target->rtos != NULL) && (target->rtos->thread_details != NULL) && (target->rtos->thread_count != 0))
		{
			threadid_t threadid = 0;
			int found = -1;
			sscanf(packet, "qThreadExtraInfo,%" SCNx64, &threadid );

			if ((target->rtos != NULL) && (target->rtos->thread_details
					!= NULL)) {
				int thread_num;
				for (thread_num = 0; thread_num
						< target->rtos->thread_count; thread_num++) {
					if (target->rtos->thread_details[thread_num].threadid
							== threadid) {
						if (target->rtos->thread_details[thread_num].exists) {
							found = thread_num;
						}
					}
				}
			}
			if (found == -1) {
				gdb_put_packet(connection, "E01", 3); // thread not found
				return ERROR_OK;
			}

			struct thread_detail* detail = &target->rtos->thread_details[found];

			int str_size = 0;
			if ( detail->display_str != NULL )
			{
				str_size += strlen(detail->display_str);
			}
			if ( detail->thread_name_str != NULL )
			{
				str_size += strlen(detail->thread_name_str);
			}
			if ( detail->extra_info_str != NULL )
			{
				str_size += strlen(detail->extra_info_str);
			}

			char * tmp_str = (char*) malloc( str_size + 7 );
			char*  tmp_str_ptr = tmp_str;

			if ( detail->display_str != NULL )
			{
				tmp_str_ptr += sprintf( tmp_str_ptr, "%s", detail->display_str );
			}
			if ( detail->thread_name_str != NULL )
			{
				if ( tmp_str_ptr != tmp_str )
				{
					tmp_str_ptr += sprintf( tmp_str_ptr, " : " );
				}
				tmp_str_ptr += sprintf( tmp_str_ptr, "%s", detail->thread_name_str );
			}
			if ( detail->extra_info_str != NULL )
			{
				if ( tmp_str_ptr != tmp_str )
				{
					tmp_str_ptr += sprintf( tmp_str_ptr, " : " );
				}
				tmp_str_ptr += sprintf( tmp_str_ptr, " : %s", detail->extra_info_str );
			}

			assert(strlen(tmp_str) ==
				(size_t) (tmp_str_ptr - tmp_str));

			char * hex_str = (char*) malloc( strlen(tmp_str)*2 +1 );
			str_to_hex( hex_str, tmp_str );

			gdb_put_packet(connection, hex_str, strlen(hex_str));
			free(hex_str);
			free(tmp_str);
			return ERROR_OK;

		}
		gdb_put_packet(connection, "", 0);
		return ERROR_OK;
	}
	else if (strstr(packet, "qSymbol"))
	{
		if ( target->rtos != NULL )
		{
			int next_symbol_num = -1;
			if (target->rtos->symbols == NULL)
			{
				target->rtos->type->get_symbol_list_to_lookup( &target->rtos->symbols );
			}
			if (0 == strcmp( "qSymbol::", packet ) )
			{
				// first query -
				next_symbol_num = 0;
			}
			else
			{
				int64_t value = 0;
				char * hex_name_str = malloc( strlen(packet));
				char * name_str;
				int symbol_num;

				char* found = strstr( packet, "qSymbol::" );
				if (0 == found )
				{
					sscanf(packet, "qSymbol:%" SCNx64 ":%s", &value, hex_name_str);
				}
				else
				{
					// No value returned by GDB - symbol was not found
					sscanf(packet, "qSymbol::%s", hex_name_str);
				}
				name_str = (char*) malloc( 1+ strlen(hex_name_str) / 2 );

				hex_to_str( name_str, hex_name_str );


				symbol_num = 0;
				while ( ( target->rtos->symbols[ symbol_num ].symbol_name != NULL ) && ( 0 != strcmp( target->rtos->symbols[ symbol_num ].symbol_name, name_str ) ) )
				{
					symbol_num++;
				}


				if ( target->rtos->symbols[ symbol_num ].symbol_name == NULL )
				{
					LOG_OUTPUT("ERROR: unknown symbol\r\n");
					gdb_put_packet(connection, "OK", 2);
					return ERROR_OK;
				}

				target->rtos->symbols[ symbol_num ].address = value;

				next_symbol_num = symbol_num+1;
				free( hex_name_str );
				free( name_str );

			}

			int symbols_done = 0;
			if ( target->rtos->symbols[ next_symbol_num ].symbol_name == NULL )
			{
				if ( ( target->rtos_auto_detect == false ) ||
					 ( 1 == target->rtos->type->detect_rtos( target ) ) )
				{
					// Found correct RTOS or not autodetecting
					if ( target->rtos_auto_detect == true )
					{
						LOG_OUTPUT( "Auto-detected RTOS: %s\r\n",target->rtos->type->name );
					}
					symbols_done = 1;
				}
				else
				{
					// Auto detecting RTOS and currently not found
					if( 1 != rtos_try_next( target ) )
					{
						// No more RTOS's to try
						symbols_done = 1;
					}
					else
					{
						next_symbol_num = 0;
						target->rtos->type->get_symbol_list_to_lookup( &target->rtos->symbols );
					}

				}
			}


			if ( symbols_done == 1 )
			{
				target->rtos_auto_detect = false;
				target->rtos->type->create( target );
				target->rtos->type->update_threads(target->rtos);
				// No more symbols needed
				gdb_put_packet(connection, "OK", 2);
				return ERROR_OK;

			}
			else
			{
				char* symname = target->rtos->symbols[ next_symbol_num ].symbol_name;
				char qsymstr[] = "qSymbol:";
				char * opstring = (char*)malloc(sizeof(qsymstr)+strlen(symname)*2+1);
				char * posptr = opstring;
				posptr += sprintf( posptr, "%s", qsymstr );
				str_to_hex( posptr, symname );
				gdb_put_packet(connection, opstring, strlen(opstring));
				free(opstring);
				return ERROR_OK;
			}

		}
		gdb_put_packet(connection, "OK", 2);
		return ERROR_OK;
	}
	else if (strstr(packet, "qfThreadInfo"))
	{
		int i;
		if ( ( target->rtos != NULL ) && ( target->rtos->thread_count != 0 ) )
		{

			char* out_str = (char*) malloc(17 * target->rtos->thread_count + 5);
			char* tmp_str = out_str;
			tmp_str += sprintf(tmp_str, "m");
			for (i = 0; i < target->rtos->thread_count; i++) {
				if (i != 0) {
					tmp_str += sprintf(tmp_str, ",");
				}
				tmp_str += sprintf(tmp_str, "%016" PRIx64,
						target->rtos->thread_details[i].threadid);
			}
			tmp_str[0] = 0;
			gdb_put_packet(connection, out_str, strlen(out_str));
		}
		else
		{
			gdb_put_packet(connection, "", 0);
		}

		return ERROR_OK;
	}
	else if (strstr(packet, "qsThreadInfo"))
	{
		gdb_put_packet(connection, "l", 1);
		return ERROR_OK;
	}
	else if (strstr(packet, "qAttached"))
	{
		gdb_put_packet(connection, "1", 1);
		return ERROR_OK;
	}
	else if (strstr(packet, "qOffsets"))
	{
		char offsets[] = "Text=0;Data=0;Bss=0";
		gdb_put_packet(connection, offsets, sizeof(offsets)-1);
		return ERROR_OK;
	}
	else if (strstr(packet, "qC"))
	{
		if( target->rtos!=NULL )
		{
			char buffer[15];
			int size;
			size = snprintf(buffer, 15, "QC%08X", (int)target->rtos->current_thread);
			gdb_put_packet(connection, buffer, size);
		}
		else
		{
			gdb_put_packet(connection, "QC0", 3);
		}
		return ERROR_OK;
	}
	else if ( packet[0] == 'T' ) // Is thread alive?
	{
		threadid_t threadid;
		int found = -1;
		sscanf(packet, "T%" SCNx64, &threadid);
		if ((target->rtos != NULL) && (target->rtos->thread_details
				!= NULL)) {
			int thread_num;
			for (thread_num = 0; thread_num
					< target->rtos->thread_count; thread_num++) {
				if (target->rtos->thread_details[thread_num].threadid
						== threadid) {
					if (target->rtos->thread_details[thread_num].exists) {
						found = thread_num;
					}
				}
			}
		}
		if (found != -1) {
			gdb_put_packet(connection, "OK", 2); // thread alive
		} else {
			gdb_put_packet(connection, "E01", 3); // thread not found
		}
		return ERROR_OK;
	}
	else if ( packet[0] == 'H') // Set current thread ( 'c' for step and continue, 'g' for all other operations )
	{
		if (packet[1] == 'g')
		{
			sscanf(packet, "Hg%16" SCNx64, &current_threadid);
		}
		gdb_put_packet(connection, "OK", 2);
		return ERROR_OK;
	}

	return GDB_THREAD_PACKET_NOT_CONSUMED;
}
예제 #22
0
파일: rtos.c 프로젝트: Xplorer001/openocd
int rtos_generic_stack_read( struct target * target, const struct rtos_register_stacking* stacking, int64_t stack_ptr, char ** hex_reg_list )
{
	int list_size = 0;
	char * tmp_str_ptr;
	int64_t new_stack_ptr;
	int i;
	int retval;

	if ( stack_ptr == 0)
	{
		LOG_OUTPUT("Error: null stack pointer in thread\r\n");
		return -5;
	}
	// Read the stack
	uint8_t * stack_data = (uint8_t*) malloc( stacking->stack_registers_size );
	uint32_t address = stack_ptr;

	if ( stacking->stack_growth_direction == 1 )
	{
		address -=  stacking->stack_registers_size;
	}
	retval = target_read_buffer( target, address, stacking->stack_registers_size, stack_data);
	if ( retval != ERROR_OK )
	{
		LOG_OUTPUT("Error reading stack frame from FreeRTOS thread\r\n");
		return retval;
	}
/*
	LOG_OUTPUT("Stack Data :");
	for(i = 0; i < stacking->stack_registers_size; i++ )
	{
		LOG_OUTPUT("%02X",stack_data[i]);
	}
	LOG_OUTPUT("\r\n");
*/
	for( i = 0; i < stacking->num_output_registers; i++ )
	{
		list_size += stacking->register_offsets[i].width_bits/8;
	}
	*hex_reg_list = (char*)malloc( list_size*2 +1 );
	tmp_str_ptr = *hex_reg_list;
	new_stack_ptr = stack_ptr - stacking->stack_growth_direction * stacking->stack_registers_size;
	if (stacking->stack_alignment != 0) {
		/* Align new stack pointer to x byte boundary */
		new_stack_ptr =
			(new_stack_ptr & (~((int64_t) stacking->stack_alignment - 1))) +
			((stacking->stack_growth_direction == -1) ? stacking->stack_alignment : 0);
	}
	for( i = 0; i < stacking->num_output_registers; i++ )
	{
		int j;
		for ( j = 0; j < stacking->register_offsets[i].width_bits/8; j++ )
		{
			if ( stacking->register_offsets[i].offset == -1 )
			{
				tmp_str_ptr += sprintf( tmp_str_ptr, "%02x", 0 );
			}
			else if ( stacking->register_offsets[i].offset == -2 )
			{
				tmp_str_ptr += sprintf( tmp_str_ptr, "%02x", ((uint8_t*)&new_stack_ptr)[j] );
			}
			else
			{
				tmp_str_ptr += sprintf( tmp_str_ptr,"%02x", stack_data[ stacking->register_offsets[i].offset + j ] );
			}
		}
	}
//	LOG_OUTPUT("Output register string: %s\r\n", *hex_reg_list);
	return ERROR_OK;
}
예제 #23
0
static int embKernel_update_threads(struct rtos *rtos)
{
    /* int i = 0; */
    int retval;
    const struct embKernel_params *param;

    if (rtos == NULL)
        return -1;

    if (rtos->rtos_specific_params == NULL)
        return -3;

    if (rtos->symbols == NULL) {
        LOG_ERROR("No symbols for embKernel");
        return -4;
    }

    if (rtos->symbols[SYMBOL_ID_sCurrentTask].address == 0) {
        LOG_ERROR("Don't have the thread list head");
        return -2;
    }

    /* wipe out previous thread details if any */
    rtos_free_threadlist(rtos);

    param = (const struct embKernel_params *) rtos->rtos_specific_params;

    retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sCurrentTask].address, param->pointer_width,
                                (uint8_t *) &rtos->current_thread);
    if (retval != ERROR_OK) {
        LOG_ERROR("Error reading current thread in embKernel thread list");
        return retval;
    }

    int64_t max_used_priority = 0;
    retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sMaxPriorities].address, param->pointer_width,
                                (uint8_t *) &max_used_priority);
    if (retval != ERROR_OK)
        return retval;

    int thread_list_size = 0;
    retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sCurrentTaskCount].address,
                                param->thread_count_width, (uint8_t *) &thread_list_size);

    if (retval != ERROR_OK) {
        LOG_ERROR("Could not read embKernel thread count from target");
        return retval;
    }

    /* create space for new thread details */
    rtos->thread_details = malloc(sizeof(struct thread_detail) * thread_list_size);
    if (!rtos->thread_details) {
        LOG_ERROR("Error allocating memory for %d threads", thread_list_size);
        return ERROR_FAIL;
    }

    int threadIdx = 0;
    /* Look for ready tasks */
    for (int pri = 0; pri < max_used_priority; pri++) {
        /* Get first item in queue */
        int64_t iterable = 0;
        retval = target_read_buffer(rtos->target,
                                    rtos->symbols[SYMBOL_ID_sListReady].address + (pri * param->rtos_list_size), param->pointer_width,
                                    (uint8_t *) &iterable);
        if (retval != ERROR_OK)
            return retval;
        for (; iterable && threadIdx < thread_list_size; threadIdx++) {
            /* Get info from this iterable item */
            retval = embKernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[threadIdx], "Ready");
            if (retval != ERROR_OK)
                return retval;
            /* Get next iterable item */
            retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width,
                                        (uint8_t *) &iterable);
            if (retval != ERROR_OK)
                return retval;
        }
    }
    /* Look for sleeping tasks */
    int64_t iterable = 0;
    retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sListSleep].address, param->pointer_width,
                                (uint8_t *) &iterable);
    if (retval != ERROR_OK)
        return retval;
    for (; iterable && threadIdx < thread_list_size; threadIdx++) {
        /*Get info from this iterable item */
        retval = embKernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[threadIdx], "Sleeping");
        if (retval != ERROR_OK)
            return retval;
        /*Get next iterable item */
        retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width,
                                    (uint8_t *) &iterable);
        if (retval != ERROR_OK)
            return retval;
    }

    /* Look for suspended tasks  */
    iterable = 0;
    retval = target_read_buffer(rtos->target, rtos->symbols[SYMBOL_ID_sListSuspended].address, param->pointer_width,
                                (uint8_t *) &iterable);
    if (retval != ERROR_OK)
        return retval;
    for (; iterable && threadIdx < thread_list_size; threadIdx++) {
        /* Get info from this iterable item */
        retval = embKernel_get_tasks_details(rtos, iterable, param, &rtos->thread_details[threadIdx], "Suspended");
        if (retval != ERROR_OK)
            return retval;
        /*Get next iterable item */
        retval = target_read_buffer(rtos->target, iterable + param->iterable_next_offset, param->pointer_width,
                                    (uint8_t *) &iterable);
        if (retval != ERROR_OK)
            return retval;
    }

    rtos->thread_count = 0;
    rtos->thread_count = threadIdx;
    LOG_OUTPUT("Found %u tasks\n", (unsigned int)threadIdx);
    return 0;
}
예제 #24
0
파일: options.c 프로젝트: andyturk/openocd
int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[])
{
	int c;
	char command_buffer[128];

	while (1) {
		/* getopt_long stores the option index here. */
		int option_index = 0;

		c = getopt_long(argc, argv, "hvd::l:f:s:c:p", long_options, &option_index);

		/* Detect the end of the options. */
		if (c == -1)
			break;

		switch (c) {
			case 0:
				break;
			case 'h':		/* --help | -h */
				help_flag = 1;
				break;
			case 'v':		/* --version | -v */
				version_flag = 1;
				break;
			case 'f':		/* --file | -f */
			{
				snprintf(command_buffer, 128, "script {%s}", optarg);
				add_config_command(command_buffer);
				break;
			}
			case 's':		/* --search | -s */
				add_script_search_dir(optarg);
				break;
			case 'd':		/* --debug | -d */
				if (optarg)
					snprintf(command_buffer, 128, "debug_level %s", optarg);
				else
					snprintf(command_buffer, 128, "debug_level 3");
				command_run_line(cmd_ctx, command_buffer);
				break;
			case 'l':		/* --log_output | -l */
				if (optarg) {
					snprintf(command_buffer, 128, "log_output %s", optarg);
					command_run_line(cmd_ctx, command_buffer);
				}
				break;
			case 'c':		/* --command | -c */
				if (optarg)
				    add_config_command(optarg);
				break;
			case 'p':
				/* to replicate the old syntax this needs to be synchronous
				 * otherwise the gdb stdin will overflow with the warning message */
				command_run_line(cmd_ctx, "gdb_port pipe; log_output openocd.log");
				LOG_WARNING("deprecated option: -p/--pipe. Use '-c \"gdb_port pipe; "
						"log_output openocd.log\"' instead.");
				break;
		}
	}

	if (help_flag) {
		LOG_OUTPUT("Open On-Chip Debugger\nLicensed under GNU GPL v2\n");
		LOG_OUTPUT("--help       | -h\tdisplay this help\n");
		LOG_OUTPUT("--version    | -v\tdisplay OpenOCD version\n");
		LOG_OUTPUT("--file       | -f\tuse configuration file <name>\n");
		LOG_OUTPUT("--search     | -s\tdir to search for config files and scripts\n");
		LOG_OUTPUT("--debug      | -d\tset debug level <0-3>\n");
		LOG_OUTPUT("--log_output | -l\tredirect log output to file <name>\n");
		LOG_OUTPUT("--command    | -c\trun <command>\n");
		exit(-1);
	}

	if (version_flag) {
		/* Nothing to do, version gets printed automatically. */
		/* It is not an error to request the VERSION number. */
		exit(0);
	}

	/* paths specified on the command line take precedence over these
	 * built-in paths
	 */
	add_default_dirs();

	return ERROR_OK;
}
예제 #25
0
int parse_cmdline_args(struct command_context_s *cmd_ctx, int argc, char *argv[])
{
	int c;
	char command_buffer[128];

	while (1)
	{	
		/* getopt_long stores the option index here. */
		int option_index = 0;
		
		c = getopt_long(argc, argv, "hvd::l:f:s:c:p", long_options, &option_index);
		
		/* Detect the end of the options. */
		if (c == -1)
			break;
		
		switch (c)
		{
			case 0:
				break;
			case 'h':	/* --help | -h */
				help_flag = 1;
				break;
			case 'v':	/* --version | -v */
				version_flag = 1;
				break;
			case 'f':	/* --file | -f */
			{
				snprintf(command_buffer, 128, "script {%s}", optarg);
				add_config_command(command_buffer);
				break;
			}
			case 's':	/* --search | -s */
				add_script_search_dir(optarg);
				break;
			case 'd':	/* --debug | -d */
				if (optarg)
					snprintf(command_buffer, 128, "debug_level %s", optarg);
				else
					snprintf(command_buffer, 128, "debug_level 3");
				command_run_line(cmd_ctx, command_buffer);
				break;
			case 'l':	/* --log_output | -l */
				if (optarg)
				{
					snprintf(command_buffer, 128, "log_output %s", optarg);
					command_run_line(cmd_ctx, command_buffer);
				}	
				break;
			case 'c':	/* --command | -c */
				if (optarg)
				{
					add_config_command(optarg);
				}	
				break;
			case 'p':	/* --pipe | -p */
#if BUILD_ECOSBOARD == 1
				/* pipes unsupported on hosted platforms */
				LOG_WARNING("pipes not supported on this platform");
#else
				server_use_pipes = 1;
#endif
				break;
		}
	}

	if (help_flag)
	{
		LOG_OUTPUT("Open On-Chip Debugger\n(c) 2005-2008 by Dominic Rath\n\n");
		LOG_OUTPUT("--help       | -h\tdisplay this help\n");
		LOG_OUTPUT("--version    | -v\tdisplay OpenOCD version\n");
		LOG_OUTPUT("--file       | -f\tuse configuration file <name>\n");
		LOG_OUTPUT("--search     | -s\tdir to search for config files and scripts\n");
		LOG_OUTPUT("--debug      | -d\tset debug level <0-3>\n");
		LOG_OUTPUT("--log_output | -l\tredirect log output to file <name>\n");
		LOG_OUTPUT("--command    | -c\trun <command>\n");
		LOG_OUTPUT("--pipe       | -p\tuse pipes for gdb communication\n");
		exit(-1);
	}	

	if (version_flag)
	{
		/* Nothing to do, version gets printed automatically. */
		// It is not an error to request the VERSION number.
		exit(0);
	}
	
	return ERROR_OK;
}
예제 #26
0
int main(int argc, char **argv)
{
	void internal_get_counts(uint32_t *, uint32_t *, uint32_t *, uint32_t *);
	void internal_set_dims(int, int, int);
	void internal_set_log(int, FILE*);
	int internal_verify_counts(uint32_t inits, uint32_t deinits, uint32_t cmds, uint32_t dist);
	int internal_verify_data(uint8_t *hash);
	int internal_verify_x(uint16_t x);
	int internal_verify_y(uint16_t y);
	int internal_verify_z(uint16_t z);
	int internal_verify_pos(uint16_t x, uint16_t y, uint16_t z);
	void internal_hw_failure(void);

	int ret = 0;
	char *name = argv[0];
	uint32_t inits, deinits, cmds, dist;

	// Option defaults
	int verbose = 0;
	char *logname = NULL;

	// Parse options
	int opt;
	while ((opt = getopt(argc, argv, "hvo:")) != -1) {
		switch (opt) {
			case 'v':
				verbose = 1;
				break;
			case 'o':
				logname = optarg;
				break;
			case 'h':
			default:
				usage(name);
				return 1;
		}
	}

	// Open log file if any
	FILE *logfile = NULL;
	if (logname) {
		logfile = fopen(logname, "w");
		if (!logfile) {
			perror("opening logfile");
			return 1;
		}
	}
	internal_set_log(verbose, logfile);
	LOG_OUTPUT(fprintf, "Starting Virtual TipTap v" TIPTAP_VERSION "\n");

	// Read first data and sanity-check: dimensions
	uint16_t width, height, depth;
	if (scanf("%hu %hu %hu", &width, &height, &depth) != 3) {
		fprintf(stderr, "Workload input: failed to read dimensions\n");
		return 2;
	} else if (width >= 1024 || height >= 1024 || depth >= 1024) {
		fprintf(stderr, "Workload input: dimensions too large: %dx%dx%d\n",
				width, height, depth);
		return 2;
	}
	internal_set_dims(width, height, depth);
	LOG_OUTPUT(fprintf, "Max print dimensions: %ux%ux%u\n", width, height, depth);

	// This line is the reason we have to distribute simulate.c
	struct tiptap tt;

	// Now read commands
	char cmd[6];
	uint16_t x, y, z, w, h;
	uint8_t *buf;
	uint16_t *ibuf;
	int erv;
	int arv;
	int i;
	while (scanf("%5s", cmd) == 1) {
		if (cmd[4] == '@') {
			// Expected to fail
			erv = 1;
			cmd[4] = '\0';
			LOG_OUTPUT(fprintf, "Command: %s (driver should return error)\n", cmd);
		} else if (cmd[4] == '!') {
			// Test HW failure conditions
			erv = 1;
			internal_hw_failure();
			cmd[4] = '\0';
			LOG_OUTPUT(fprintf, "Command: %s (simulating hw failure)\n",
					cmd);
		} else {
			// Expected to succeed
			erv = 0;
			LOG_OUTPUT(fprintf, "Command: %s\n", cmd);
		}

		// Parse command
		if (!strcmp(cmd, "INIT")) {
			// Initialize driver
			arv = tiptap_init(&tt);
		} else if (!strcmp(cmd, "DEST")) {
			// Clean up driver
			tiptap_destroy(&tt);
			arv = 0;
		} else if (!strcmp(cmd, "MOVE")) {
			// Move to the specified X, Y, Z coordinates
			if (scanf("%hu %hu %hu", &x, &y, &z) != 3) {
				fprintf(stderr, "Workload input: Malformed MOVE command\n");
				ret = 2;
				goto out_destroy;
			}

			arv = tiptap_moveto(&tt, x, y, z);
		} else if (!strcmp(cmd, "GETP")) {
			x = y = z = 65535;
			tiptap_getpos(&tt, &x, &y, &z);
			if (x == 65535 || y == 65535 || z == 65535) {
				LOG_OUTPUT(fprintf, "Did not set all output parameters\n");
				ret = 1;
				goto out_destroy;
			}
			LOG_OUTPUT(fprintf, "Returned position: (%hu, %hu, %hu)\n", x, y, z);
			if (internal_verify_pos(x, y, z)) {
				ret = 1;
				goto out_destroy;
			}
		} else if (!strcmp(cmd, "PRNT")) {
			if (scanf("%hu %hu %hu %hu", &x, &y, &w, &h) != 4) {
				fprintf(stderr, "Workload input: Malformed PRNT command\n");
				ret = 2;
				goto out_destroy;
			}

			// Load voxel data
			buf = calloc(w * h, sizeof(buf[0]));
			for (i = 0; i < w * h; i++) {
				if (scanf("%2hhx", &buf[i]) != 1) {
					fprintf(stderr, "Workload input: Malformed pixel data\n");
					ret = 2;
					goto out_destroy;
				}
			}
			LOG_OUTPUT(fprintf, "Printing %ux%u layer at (%u, %u)\n", w, h, x, y);
			arv = tiptap_printlayer(&tt, x, y, w, h, buf);
			free(buf);
		} else if (!strcmp(cmd, "SCAN")) {
			if (scanf("%hu %hu %hu %hu", &x, &y, &w, &h) != 4) {
				fprintf(stderr, "Workload input: Malformed SCAN command\n");
				ret = 2;
				goto out_destroy;
			}

			// Get height data
			ibuf = calloc(w * h, sizeof(ibuf[0]));
			LOG_OUTPUT(fprintf, "Scanning %ux%u region at (%u, %u)\n", w, h, x, y);
			arv = tiptap_scan(&tt, x, y, w, h, ibuf);
			// XXX verify scan data?
			free(ibuf);
		} else if (!strcmp(cmd, "VDAT")) {
			// Verify functions should return success
			assert(erv == 0);
			arv = 0;

			LOG_OUTPUT(fprintf, "Verifying printed material data\n");

			// Read in target hash from workload
			uint8_t hash[20];
			for (i = 0; i < 20; i++) {
				if (scanf("%2hhx", &hash[i]) != 1) {
					fprintf(stderr, "Workload input: malformed VDAT command\n");
					ret = 2;
					goto out_destroy;
				}
			}

			// Verify actual hash
			if (internal_verify_data(hash)) {
				ret = 1;
				goto out_destroy;
			}
		} else if (!strcmp(cmd, "VPOS")) {
			// Verify functions should return success
			assert(erv == 0);
			arv = 0;

			LOG_OUTPUT(fprintf, "Verifying current nozzle position\n");

			if (scanf("%hu", &x) == 1) {
				arv = internal_verify_x(x) || arv;
			} else if (getchar() != '*') {
				fprintf(stderr, "Workload input: Malformed VPOS command\n");
				ret = 2;
				goto out_destroy;
			}
			if (scanf("%hu", &y) == 1) {
				arv = internal_verify_y(y) || arv;
			} else if (getchar() != '*') {
				fprintf(stderr, "Workload input: Malformed VPOS command\n");
				ret = 2;
				goto out_destroy;
			}
			if (scanf("%hu", &z) == 1) {
				arv = internal_verify_z(z) || arv;
			} else if (getchar() != '*') {
				fprintf(stderr, "Workload input: Malformed VPOS command\n");
				ret = 2;
				goto out_destroy;
			}

			if (arv) {
				ret = 1;
				goto out_destroy;
			}
		} else if (!strcmp(cmd, "VCTR")) {
			// Verify functions should return success
			assert(erv == 0);
			arv = 0;

			LOG_OUTPUT(fprintf, "Verifying poweron/off/cmd/dist counters\n");

			uint32_t ti, tdi, tc, td;
			if (scanf("%u %u %u %u", &ti, &tdi, &tc, &td) != 4) {
				fprintf(stderr, "Workload input: Malformed VCTR command\n");
				ret = 2;
				goto out_destroy;
			}

			// Verify powerons, poweroffs, cmds, and distance
			if (internal_verify_counts(ti, tdi, tc, td)) {
				ret = 1;
				goto out_destroy;
			}
		} else {
			fprintf(stderr, "Workload input: unrecognized command %s\n",
					cmd);
			ret = 2;
			goto out_destroy;
		}

		LOG_OUTPUT(fprintf, "Return value: %s\n", arv ? "error" : "success");
		if (!arv != !erv) {
			LOG_OUTPUT(fprintf, "Expected return value: %s\n", erv ?
					"error" : "success");
			ret = 1;
			goto out_destroy;
		}
	}

out_destroy:
	// Print out totals
	internal_get_counts(&inits, &deinits, &cmds, &dist);

	fprintf(stderr, "\nTotals: poweron=%u, poweroff=%u, cmds=%u, distance=%u\n",
			inits, deinits, cmds, dist);

	if (logfile)
		fclose(logfile);
	if (ret)
		fprintf(stderr, "Test FAILED\n");
	else
		fprintf(stderr, "Test passed\n");
	return ret;
}