コード例 #1
0
/*---------------------------------------------------------------------------*/
static void
res_get_handler(void *request, void *response, uint8_t *buffer,
  uint16_t preferred_size, int32_t *offset)
{
  const char *len = NULL;
  char message[40];
  memset(message, 0, 40);
  print_temperature(&message[0]);
  
  int length = strlen(&message[0]);

  /* The query string can be retrieved by rest_get_query(),
   * or parsed for its key-value pairs.
   */
  if(REST.get_query_variable(request, "len", &len)) {
    length = atoi(len);
    if(length < 0) {
      length = 0;
    }
    if(length > REST_MAX_CHUNK_SIZE) {
      length = REST_MAX_CHUNK_SIZE;
    }
    memcpy(buffer, message, length);
  } else {
    memcpy(buffer, message, length);
  }
  REST.set_header_content_type(response, REST.type.TEXT_PLAIN);
  REST.set_header_etag(response, (uint8_t *)&length, 1);
  REST.set_response_payload(response, buffer, length);
}
コード例 #2
0
ファイル: main.c プロジェクト: Biolunar/dstatus
int main(void)
{
	Display* display = 0;
	struct temperature* temperature = 0;
	int ret = EXIT_FAILURE;

	signal(SIGINT, &signal_handler);
	signal(SIGTERM, &signal_handler);
	setlocale(LC_ALL, u8"");

	display = XOpenDisplay(0);
	if (!display)
	{
		fprintf(stderr, u8"Could not open X11 display.\n");
		goto cleanup;
	}

	temperature = temperature_init();
	if (!temperature)
	{
		fprintf(stderr, u8"Could not initialize temperature.\n");
		goto cleanup;
	}

	while (running)
	{
		char buffer[1024];
		char* cur = buffer;
		size_t size = sizeof buffer;
		size_t check = 0;

		check = print_temperature(cur, size, temperature);
		size -= check;
		cur += check;

		check = print_time(cur, size);
		size -= check;
		cur += check;

		XStoreName(display, DefaultRootWindow(display), buffer);
		XSync(display, False);
		sleep(1);
	}

	ret = EXIT_SUCCESS;

cleanup:
	temperature_cleanup(temperature);
	if (display)
		XCloseDisplay(display);

	return ret;
}
コード例 #3
0
ファイル: garmin_txt.c プロジェクト: alexbirkett/GPSBabel
static void
track_disp_wpt_cb(const waypoint *wpt)
{
    waypoint *prev = cur_info->prev_wpt;
    time_t delta;
    double dist, depth;

    gbfprintf(fout, "Trackpoint\t");

    print_position(wpt);
    print_date_and_time(wpt->creation_time, 0);
    if IS_VALID_ALT(wpt->altitude)
        print_distance(wpt->altitude, 1, 0, 0);

    gbfprintf(fout, "\t");
    depth = WAYPT_GET(wpt, depth, unknown_alt);
    if (depth != unknown_alt)
        print_distance(depth, 1, 0, 1);

    if (prev != NULL) {
        float temp;
        gbfprintf(fout, "\t");
        delta = wpt->creation_time - prev->creation_time;
        temp = WAYPT_GET(wpt, temperature, -999);
        if (temp != -999)
            print_temperature(temp);
        gbfprintf(fout, "\t");
        dist = waypt_distance_ex(prev, wpt);
        print_distance(dist, 0, 1, 0);
        print_date_and_time(delta, 1);
        print_speed(&dist, &delta);
        print_course(prev, wpt);
    }
    gbfprintf(fout, "\r\n");

    cur_info->prev_wpt = (waypoint *)wpt;
}
コード例 #4
0
ファイル: weather.cpp プロジェクト: 0x90sled/Cataclysm-DDA
/**
 * Generate textual weather forecast for the specified radio tower.
 */
std::string weather_forecast( point const &abs_sm_pos )
{
    std::ostringstream weather_report;
    // Local conditions
    const auto cref = overmap_buffer.closest_city( tripoint( abs_sm_pos, 0 ) );
    const std::string city_name = cref ? cref.city->name : std::string( _( "middle of nowhere" ) );
    // Current time
    weather_report << string_format(
                       _("The current time is %s Eastern Standard Time.  At %s in %s, it was %s. The temperature was %s. "),
                       calendar::turn.print_time().c_str(), calendar::turn.print_time(true).c_str(),
                       city_name.c_str(),
                       weather_data(g->weather).name.c_str(), print_temperature(g->temperature).c_str()
                   );

    //weather_report << ", the dewpoint ???, and the relative humidity ???.  ";
    //weather_report << "The wind was <direction> at ? mi/km an hour.  ";
    //weather_report << "The pressure was ??? in/mm and steady/rising/falling.";

    // Regional conditions (simulated by choosing a random range containing the current conditions).
    // Adjusted for weather volatility based on how many weather changes are coming up.
    //weather_report << "Across <region>, skies ranged from <cloudiest> to <clearest>.  ";
    // TODO: Add fake reports for nearby cities

    // TODO: weather forecast
    // forecasting periods are divided into 12-hour periods, day (6-18) and night (19-5)
    // Accumulate percentages for each period of various weather statistics, and report that
    // (with fuzz) as the weather chances.
    // int weather_proportions[NUM_WEATHER_TYPES] = {0};
    double high = -100.0;
    double low = 100.0;
    point const abs_ms_pos = overmapbuffer::sm_to_ms_copy( abs_sm_pos );
    // TODO wind direction and speed
    int last_hour = calendar::turn - ( calendar::turn % HOURS(1) );
    for(int d = 0; d < 6; d++) {
        weather_type forecast = WEATHER_NULL;
        for(calendar i(last_hour + 7200 * d); i < last_hour + 7200 * (d + 1); i += 600) {
            w_point w = g->weather_gen->get_weather( abs_ms_pos, i );
            forecast = std::max(forecast, g->weather_gen->get_weather_conditions(w));
            high = std::max(high, w.temperature);
            low = std::min(low, w.temperature);
        }
        std::string day;
        bool started_at_night;
        calendar c(last_hour + 7200 * d);
        if(d == 0 && c.is_night()) {
            day = _("Tonight");
            started_at_night = true;
        } else {
            day = _("Today");
            started_at_night = false;
        }
        if(d > 0 && ((started_at_night && !(d % 2)) || (!started_at_night && d % 2))) {
            day = rmp_format(_("<Mon Night>%s Night"), c.day_of_week().c_str());
        } else {
            day = c.day_of_week();
        }
        weather_report << string_format(
                           _("%s... %s. Highs of %s. Lows of %s. "),
                           day.c_str(), weather_data(forecast).name.c_str(),
                           print_temperature(high).c_str(), print_temperature(low).c_str()
                       );
    }
    return weather_report.str();
}
コード例 #5
0
ファイル: weather.cpp プロジェクト: Abalieno/Cataclysm-DDA
std::string weather_forecast(game *g, radio_tower tower)
{
    std::stringstream weather_report;

    // Current time
    weather_report << "The current time is " << g->turn.print_time() << " Eastern Standard Time.  ";

    // Local conditions
    weather_report << "At " << g->turn.print_time(true);

    city *closest_city = &g->cur_om->cities[g->cur_om->closest_city(point(tower.x, tower.y))];
    if (closest_city)
    {
        weather_report << " in " << closest_city->name;
    }
    weather_report << ", it was " << weather_data[g->weather].name << ".  ";
    weather_report << "The temperature was " << print_temperature(g->temperature);

    //weather_report << ", the dewpoint ???, and the relative humidity ???.  ";
    //weather_report << "The wind was <direction> at ? mi/km an hour.  ";
    //weather_report << "The pressure was ??? in/mm and steady/rising/falling.";

    // Regional conditions (simulated by chosing a random range containing the current conditions).
    // Adjusted for weather volatility based on how many weather changes are coming up.
    //weather_report << "Across <region>, skies ranged from <cloudiest> to <clearest>.  ";
    // TODO: Add fake reports for nearby cities

    // TODO: weather forecast
    // forecasting periods are divided into 12-hour periods, day (6-18) and night (19-5)
    // Accumulate percentages for each period of various weather statistics, and report that
    // (with fuzz) as the weather chances.
    int weather_proportions[NUM_WEATHER_TYPES] = {0};
    signed char high = 0;
    signed char low = 0;
    calendar start_time = g->turn;
    int period_start = g->turn.hours();
    // TODO wind direction and speed
    for( std::list<weather_segment>::iterator period = g->future_weather.begin();
         period != g->future_weather.end(); period++ )
    {
        int period_deadline = period->deadline.hours();
        signed char period_temperature = period->temperature;
        weather_type period_weather = period->weather;
        bool start_day = period_start >= 6 && period_start <= 18;
        bool end_day = period_deadline >= 6 && period_deadline <= 18;

        high = std::max(high, period_temperature);
        low = std::min(low, period_temperature);

        if(start_day != end_day) // Assume a period doesn't last over 12 hrs?
        {
            weather_proportions[period_weather] += end_day ? 6 : 18 - period_start;
            int weather_duration = 0;
            int predominant_weather;
            std::string day;
            if( g->turn.days() == period->deadline.days() )
            {
                if( start_day )
                {
                    day = "Today";
                }
                else
                {
                    day = "Tonight";
                }
            }
            else
            {
                day = start_time.day_of_week();
                if( !start_day )
                {
                    day += " Night";
                }
            }
            for( int i = WEATHER_CLEAR; i < NUM_WEATHER_TYPES; i++)
            {
                if( weather_proportions[i] > weather_duration)
                {
                    weather_duration = weather_proportions[i];
                    predominant_weather = i;
                }
            }
            // Print forecast
            weather_report << day << "..." << weather_data[predominant_weather].name << ".  ";
            weather_report << "Highs of " << print_temperature(high) << ".  Lows of " << print_temperature(low) << ".  ";

            low = period_temperature;
            high = period_temperature;
            weather_proportions[period_weather] += end_day ? 6 : 18 - period_start;
        } else {
            weather_proportions[period_weather] += period_deadline - period_start;
        }
        start_time = period->deadline;
        period_start = period_deadline;
    }
    return weather_report.str();
}
コード例 #6
0
ファイル: weather.cpp プロジェクト: Liberthas/Cataclysm-DDA
std::string weather_forecast(radio_tower tower)
{
    std::stringstream weather_report;
    // Local conditions
    city *closest_city = &g->cur_om->cities[g->cur_om->closest_city(point(tower.x, tower.y))];
    // Current time
    weather_report << string_format(
        _("The current time is %s Eastern Standard Time.  At %s in %s, it was %s. The temperature was %s"),
        g->turn.print_time().c_str(), g->turn.print_time(true).c_str(), closest_city->name.c_str(),
        weather_data[g->weather].name.c_str(), print_temperature(g->temperature).c_str()
    );

    //weather_report << ", the dewpoint ???, and the relative humidity ???.  ";
    //weather_report << "The wind was <direction> at ? mi/km an hour.  ";
    //weather_report << "The pressure was ??? in/mm and steady/rising/falling.";

    // Regional conditions (simulated by chosing a random range containing the current conditions).
    // Adjusted for weather volatility based on how many weather changes are coming up.
    //weather_report << "Across <region>, skies ranged from <cloudiest> to <clearest>.  ";
    // TODO: Add fake reports for nearby cities

    // TODO: weather forecast
    // forecasting periods are divided into 12-hour periods, day (6-18) and night (19-5)
    // Accumulate percentages for each period of various weather statistics, and report that
    // (with fuzz) as the weather chances.
    int weather_proportions[NUM_WEATHER_TYPES] = {0};
    signed char high = 0;
    signed char low = 0;
    calendar start_time = g->turn;
    int period_start = g->turn.hours();
    // TODO wind direction and speed
    for(std::map<int, weather_segment>::iterator it = g->weather_log.lower_bound( int(g->turn) ); it != g->weather_log.end(); ++it ) {
        weather_segment * period = &(it->second);
        int period_deadline = period->deadline.hours();
        signed char period_temperature = period->temperature;
        weather_type period_weather = period->weather;
        bool start_day = period_start >= 6 && period_start <= 18;
        bool end_day = period_deadline >= 6 && period_deadline <= 18;

        high = std::max(high, period_temperature);
        low = std::min(low, period_temperature);

        if(start_day != end_day) // Assume a period doesn't last over 12 hrs?
        {
            weather_proportions[period_weather] += end_day ? 6 : 18 - period_start;
            int weather_duration = 0;
            int predominant_weather = 0;
            std::string day;
            if( g->turn.days() == period->deadline.days() )
            {
                if( start_day )
                {
                    day = _("Today");
                }
                else
                {
                    day = _("Tonight");
                }
            }
            else
            {
                std::string dayofweak = start_time.day_of_week();
                if( !start_day )
                {
                    day = rmp_format(_("<Mon Night>%s Night"), dayofweak.c_str());
                }
                else
                {
                    day = dayofweak;
                }
            }
            for( int i = WEATHER_CLEAR; i < NUM_WEATHER_TYPES; i++)
            {
                if( weather_proportions[i] > weather_duration)
                {
                    weather_duration = weather_proportions[i];
                    predominant_weather = i;
                }
            }
            // Print forecast
            weather_report << string_format(
                _("%s...%s. Highs of %s. Lows of %s. "),
                day.c_str(), weather_data[predominant_weather].name.c_str(),
                print_temperature(high).c_str(), print_temperature(low).c_str()
            );
            low = period_temperature;
            high = period_temperature;
            weather_proportions[period_weather] += end_day ? 6 : 18 - period_start;
        } else {
            weather_proportions[period_weather] += period_deadline - period_start;
        }
        start_time = period->deadline;
        period_start = period_deadline;
    }
    return weather_report.str();
}
コード例 #7
0
ファイル: garmin_txt.c プロジェクト: alexbirkett/GPSBabel
static void
write_waypt(const waypoint *wpt)
{
    unsigned char wpt_class;
    garmin_fs_p gmsd;
    char *wpt_type;
    char *dspl_mode;
    const char *country;
    double x;
    int i, icon, dynamic;
    char *icon_descr;

    gmsd = GMSD_FIND(wpt);

    i = GMSD_GET(display, 0);
    if (i > GT_DISPLAY_MODE_MAX) i = 0;
    dspl_mode = gt_display_mode_names[i];

    wpt_class = GMSD_GET(wpt_class, 0);
    if (wpt_class <= gt_waypt_class_map_line)
        wpt_type = gt_waypt_class_names[wpt_class];
    else
        wpt_type = gt_waypt_class_names[0];

    gbfprintf(fout, "Waypoint\t%s\t", (wpt->shortname) ? wpt->shortname : "");
    if (wpt_class <= gt_waypt_class_airport_ndb) {
        char *temp = wpt->notes;
        if (temp == NULL) {
            if (wpt->description && (strcmp(wpt->description, wpt->shortname) != 0))
                temp = wpt->description;
            else
                temp = "";
        }
        print_string("%s\t", temp);
    }
    else
        gbfprintf(fout, "\t");
    gbfprintf(fout, "%s\t", wpt_type);

    print_position(wpt);

    if IS_VALID_ALT(wpt->altitude)
        print_distance(wpt->altitude, 1, 0, 0);
    gbfprintf(fout, "\t");

    x = WAYPT_GET(wpt, depth, unknown_alt);
    if (x != unknown_alt)
        print_distance(x, 1, 0, 1);
    gbfprintf(fout, "\t");

    x = WAYPT_GET(wpt, proximity, unknown_alt);
    if (x != unknown_alt)
        print_distance(x, 0, 0, 0);
    gbfprintf(fout, "\t");

    x = WAYPT_GET(wpt, temperature, -999);
    if (x != -999)
        print_temperature(x);
    gbfprintf(fout, "\t%s\t", dspl_mode);

    gbfprintf(fout, "Unknown\t"); 				/* Color is fixed: Unknown */

    icon = GMSD_GET(icon, -1);
    if (icon == -1) {
        icon = gt_find_icon_number_from_desc(wpt->icon_descr, GDB);
    }
    icon_descr = gt_find_desc_from_icon_number(icon, GDB, &dynamic);
    print_string("%s\t", icon_descr);
    if (dynamic) xfree(icon_descr);

    print_string("%s\t", GMSD_GET(facility, ""));
    print_string("%s\t", GMSD_GET(city, ""));
    print_string("%s\t", GMSD_GET(state, ""));
    country = gt_get_icao_country(GMSD_GET(cc, ""));
    print_string("%s\t", (country != NULL) ? country : "");
    print_date_and_time(wpt->creation_time, 0);
    print_string("%s\t", wpt->url ? wpt->url : "");
    print_categories(GMSD_GET(category, 0));

    gbfprintf(fout, "\r\n");
}
コード例 #8
0
int main(int argc, char* argv[]) {
	int nbytes;
	int status;
	unsigned int previous, ch;
	unsigned int temp_extruder = 0, temp_bed = 0;
	// rename TODO
	unsigned int key_mask=0;

	unsigned int jog_distance = DEFAULT_JOG_DISTANCE;
	unsigned int jog_speed = DEFAULT_JOG_SPEED;
	unsigned int temp_target = DEFAULT_TEMP_TARGET;
	unsigned int feedrate = DEFAULT_FEEDRATE;
	// Explain?
	float delta_e = 0.001666669999999968 * (float)feedrate;;

	// TODO heater on/off keys

	// TODO consider a struct to hold state, then we can declare it once
	// and pass a single pointer around to various functions!!!

	// TODO float? need to?
	int posX=0, posY=0, posZ=0;
	float posE=0.0;
	int extruding=0;

	time_t last_temp = time(NULL);
	time_t last_extrude = time(NULL);

	int pipe_gcode = 0, pipe_feedback = 0;
	//stream_gcode = fdopen(pipe_gcode[1], "w");

	FILE *stream_gcode = NULL, *stream_feedback = NULL;

	// User options
	char *serial_port = NULL;

	char *cmd = NULL;	// Command string to execute austerus-core

	//size_t line_feedback_len = PIPE_LINE_BUFFER_LEN;
	//char *line_feedback = NULL;
	char line_feedback[LINE_FEEDBACK_LEN];

	// Allocate inital size of input line buffer
	//pipe_buffer = (char *) malloc (pipe_buffer_len + 1);

	// Read command line options
	int option_index = 0, opt=0;
	static struct option loptions[] = {
		{"help", no_argument, 0, 'h'},
		{"port", required_argument, 0, 'p'},
		{"baud", required_argument, 0, 'b'},
		{"verbose", no_argument, 0, 'v'}
	};

	// Generate the command line for austerus-core
	asprintf(&cmd, "/usr/bin/env AG_ACKCOUNT=1 PATH=$PWD:$PATH");

	while(opt >= 0) {
		opt = getopt_long(argc, argv, "hp:b:v", loptions,
			&option_index);

		switch (opt) {
			case 'h':
				usage();
				return EXIT_SUCCESS;
			case 'p':
				serial_port = optarg;
				asprintf(&cmd, "%s AG_SERIALPORT=%s", cmd,
					optarg);
				break;
			case 'b':
				asprintf(&cmd, "%s AG_BAUDRATE=%ld", cmd,
					strtol(optarg, NULL, 10));
				break;
			case 'v':
				asprintf(&cmd, "%s AG_VERBOSE=1", cmd);
				break;
		}
	}

	if (!serial_port & !getenv("AG_SERIALPORT")) {
		fprintf(stderr, "A serial port must be specified\n");
		return EXIT_FAILURE;
	}

	asprintf(&cmd, "%s austerus-core", cmd);

	// Open the gcode output stream to austerus-core
	popen2(cmd, &pipe_gcode, &pipe_feedback);
	free(cmd);

	// Make feedback pipe non-blocking
	fcntl(pipe_feedback, F_SETFL, O_NONBLOCK);

	stream_gcode = fdopen(pipe_gcode, "w");
	stream_feedback = fdopen(pipe_feedback, "r");

	if (!stream_gcode) {
		fprintf(stderr, "unable to open output stream\n");
		return EXIT_FAILURE;
	}

	if (!stream_feedback) {
		fprintf(stderr, "unable to open feedback stream\n");
		return EXIT_FAILURE;
	}

	// Start curses mode
	initscr();
	// Line buffering disabled
	raw();
	//  We get F1, F2 etc
	keypad(stdscr, TRUE);
	// Don't echo() while we do getch
	noecho();
	// Hide cursor
	curs_set(0);

	// Timeout so we can run extruder and check for feedback
	timeout(CURSES_TIMEOUT);

	// draw initial screen
	mvprintw(0, 0, "austerusG %s", VERSION);
	mvprintw(0, 30, "- +");

	print_fkeys(PANEL_POS_NUMBERS_X, PANEL_POS_NUMBERS_Y);
	print_extruder_keys(key_mask);
	print_keys(PANEL_POS_KEYS_X, PANEL_POS_KEYS_Y, key_mask);

	print_temperature(temp_extruder, temp_target);
	print_feedrate(feedrate);
	print_jog_distance(jog_distance);
	print_jog_speed(jog_speed);
	print_fan(0);

	mvprintw(LINES - 1, 0, "Status: Idle");

	refresh();

	// start of print reset
	fprintf(stream_gcode, "M110\n");
	// set absolute positioning
	fprintf(stream_gcode, "G90\n");
	// set to mm
	fprintf(stream_gcode, "G21\n");
	// reset coordinates to zero
	fprintf(stream_gcode, "G92 X0 Y0 Z0 E0\n");
	fflush(stream_gcode);

	while (1) {
		// Wait for user input
		ch = getch();

		// Handle any two key sequences
		switch (previous) {
			case KEY_HOME:
				if (home_axis(stream_gcode, ch)) {
					key_mask = key_mask & !BIT_H;
					print_keys(PANEL_POS_KEYS_X, PANEL_POS_KEYS_Y, key_mask);
				}
				break;
			case KEY_END:
				if (end_axis(stream_gcode, ch)) {
					key_mask = key_mask & !BIT_END;
					print_keys(PANEL_POS_KEYS_X, PANEL_POS_KEYS_Y, key_mask);
				}
				break;
		}

		// Handle single key press
		switch (ch) {
			case '1':
				// Decrease target temperature
				if (temp_target > 0) {
					temp_target = temp_target - 1;

					fprintf(stream_gcode, "M104 S%d\n", temp_target);
					fflush(stream_gcode);

					print_temperature(temp_extruder, temp_target);
				}
				break;

			case '2':
				// Increase target temperature
				temp_target = temp_target + 1;

				fprintf(stream_gcode, "M104 S%d\n", temp_target);
				fflush(stream_gcode);

				print_temperature(temp_extruder, temp_target);
				break;

			case '3':
				// Decrease feedrate
				if (feedrate >= 1) {
					feedrate -= 1;
					delta_e = 0.001666669999999968 * (float)feedrate;
					print_feedrate(feedrate);
				}
				break;

			case '4':
				// Increase feedrate
				feedrate += 1;
				delta_e = 0.001666669999999968 * (float)feedrate;
				print_feedrate(feedrate);
				break;

			case '5':
				// Decrease jog distance
				if (jog_distance > 10) {
					fprintf(stream_gcode, "M104 %d\n", temp_target);
					fflush(stream_gcode);
					jog_distance = jog_distance - 10;
					print_jog_distance(jog_distance);
				}
				break;

			case '6':
				// Increase jog distance
				jog_distance = jog_distance + 10;
				print_jog_distance(jog_distance);
				break;

			case '7':
				// Decrease jog speed
				if (jog_speed > 10) {
					jog_speed = jog_speed - 100;
					print_jog_speed(jog_speed);
				}
				break;

			case '8':
				// Increase jog speed
				jog_speed = jog_speed + 100;
				print_jog_speed(jog_speed);
				break;

			case 'e':
				extruding = 1;
				key_mask = (key_mask | BIT_E) & ~(BIT_D | BIT_R);
				print_extruder_keys(key_mask);
				break;

			case 'd':
				extruding = 0;
				key_mask = (key_mask | BIT_D) & ~(BIT_E | BIT_R);
				print_extruder_keys(key_mask);
				break;

			case 'r':
				extruding = -1;
				key_mask = (key_mask | BIT_R) & ~(BIT_D | BIT_E);
				print_extruder_keys(key_mask);
				break;

			case KEY_LEFT:
				// Jog X axis minus
				// TODO merits of G0 or G1 moves?
				posX -= jog_distance;
				fprintf(
					stream_gcode, "G1 X%d Y%d Z%d F%d\n",
					posX, posY, posZ, jog_speed
				);
				fflush(stream_gcode);
				key_mask = key_mask | BIT_MX;
				print_keys(PANEL_POS_KEYS_X, PANEL_POS_KEYS_Y, key_mask);
				break;

			case KEY_RIGHT:
				// Jog X axis plus
				posX += jog_distance;
				fprintf(
					stream_gcode, "G1 X%d Y%d Z%d F%d\n",
					posX, posY, posZ, jog_speed
				);
				fflush(stream_gcode);
				key_mask = key_mask | BIT_PX;
				print_keys(PANEL_POS_KEYS_X, PANEL_POS_KEYS_Y, key_mask);
				break;

			case KEY_UP:
				// Jog Y axis plus
				posY += jog_distance;
				fprintf(
					stream_gcode, "G1 X%d Y%d Z%d F%d\n",
					posX, posY, posZ, jog_speed
				);
				fflush(stream_gcode);
				key_mask = key_mask | BIT_PY;
				print_keys(PANEL_POS_KEYS_X, PANEL_POS_KEYS_Y, key_mask);
				break;

			case KEY_DOWN:
				// Jog Y axis minus
				posY -= jog_distance;
				fprintf(
					stream_gcode, "G1 X%d Y%d Z%d F%d\n",
					posX, posY, posZ, jog_speed
				);
				fflush(stream_gcode);
				key_mask = key_mask | BIT_MY;
				print_keys(PANEL_POS_KEYS_X, PANEL_POS_KEYS_Y, key_mask);
				break;

			case KEY_PPAGE:
				// Jog Z axis up
				posZ += jog_distance;
				fprintf(
					stream_gcode, "G1 X%d Y%d Z%d F%d\n",
					posX, posY, posZ, jog_speed
				);
				fflush(stream_gcode);
				key_mask = key_mask | BIT_PZ;
				print_keys(PANEL_POS_KEYS_X, PANEL_POS_KEYS_Y, key_mask);
				break;

			case KEY_NPAGE:
				// Jog Z axis down
				posZ -= jog_distance;
				fprintf(
					stream_gcode, "G1 X%d Y%d Z%d F%d\n",
					posX, posY, posZ, jog_speed
				);
				fflush(stream_gcode);
				key_mask = key_mask | BIT_MZ;
				print_keys(PANEL_POS_KEYS_X, PANEL_POS_KEYS_Y, key_mask);
				break;

			case KEY_HOME:
				// Start of two key move to home command
				key_mask = key_mask | BIT_H;
				print_keys(PANEL_POS_KEYS_X, PANEL_POS_KEYS_Y, key_mask);
				previous = ch;
				break;

			case KEY_END:
				// Start of two key move to end command
				key_mask = key_mask | BIT_END;
				print_keys(PANEL_POS_KEYS_X, PANEL_POS_KEYS_Y, key_mask);
				previous = ch;
				break;

			case 'f':
			case 'F':
				// Fan on
				fprintf(stream_gcode, "M106\n");
				fflush(stream_gcode);
				print_fan(1);

				break;

			case 'g':
			case 'G':
				// Fan off
				fprintf(stream_gcode, "M107\n");
				fflush(stream_gcode);
				print_fan(0);

				break;

			case 'q':
			case KEY_ESC:
				// Shutdown printer
				fprintf(stream_gcode, "M112\n");
				// Exit core
				fprintf(stream_gcode, "#ag:exit\n\n");
				fflush(stream_gcode);

				endwin();

				pclose(stream_gcode);
				pclose(stream_feedback);

				close(pipe_gcode);
				close(pipe_feedback);

				//if (line_feedback)
				//	free(line_feedback);

				wait(&status);
				printf("core exit = %d\n", status);

				return EXIT_SUCCESS;
		}

		// TODO check core alive?

		if (time(NULL) - last_temp > TEMP_PERIOD)
		{
			do {
				nbytes = nonblock_getline(line_feedback, stream_feedback);
				
				//nbytes = getline(&line_feedback, &line_feedback_len, stream_feedback);

				//fprintf(stream_gcode, "NB %d %s\n", nbytes);
				//fflush(stream_gcode);

				if (nbytes > 0) {

					mvprintw(LINES - 3, 0, "nb %d", nbytes);
					sscanf(line_feedback, "ok T:%d B:%d", &temp_extruder, &temp_bed);

					//
					if (nbytes > 66) {
						line_feedback[63] = '.';
						line_feedback[64] = '.';
						line_feedback[65] = '.';
						line_feedback[66] = '\0';
					}

					mvprintw(LINES - 2, 0, "Response: %s", line_feedback);
					print_temperature(temp_extruder, temp_target);
				}

			} while (nbytes != -1);


			last_temp = time(NULL);

			fprintf(stream_gcode, "M105\n");
			fflush(stream_gcode);

			// tODO this needs it's own clock too!
			// tODO arrow keys etc
			if (key_mask |  BIT_D) {
				key_mask = key_mask & ~BIT_D;
				print_extruder_keys(key_mask);
			}

			// We can make one mask #def? from all keys we want cleared
			// and use it for check andf clear!


		}


		if (time(NULL) - last_extrude > EXTRUDE_PERIOD)
		{
			last_extrude = time(NULL);

			// This needs to be on an indepentent time check so it can be controlled!! TODO
			if (extruding > 0) {
				posE += delta_e;
				fprintf(stream_gcode, "G1 E%.2f F%d\n", posE, feedrate);
				fflush(stream_gcode);
			} else if (extruding < 0) {
				posE -= delta_e;
				fprintf(stream_gcode, "G1 E%.2f F%d\n", posE, feedrate);
				fflush(stream_gcode);
			}

			// tODO arrow keys etc
			if (key_mask |  BIT_D) {
				key_mask = key_mask & ~BIT_D;
				print_extruder_keys(key_mask);
			}

			// We can make one mask #def? from all keys we want cleared
			// and use it for check andf clear!
		}
		refresh();


		// TODO check core is still alive

	}
}