Пример #1
0
int
rr_dev_resend (rr_dev dev, unsigned long lineno, const char *reply, size_t nbytes)
{
  int resent = 0;
  blocknode *node;

  /* sent cache slot 0 is most recent */
  while (1) {
    if (!(node = rr_dev_pop_from_queue (dev, RR_PRIO_SENTCACHE)))
      break;
    rr_dev_log (dev, RR_DEBUG_HIGH, "pop sent node line %d '%s' (%d bytes)\n",
		(int)node->line, node->block, node->blocksize);
    if (node->line >= lineno) {
      rr_dev_prepend_to_queue (dev, RR_PRIO_RESEND, node);
      resent++;
    } else { /* put it back and look elsewhere */
      rr_dev_prepend_to_queue (dev, RR_PRIO_SENTCACHE, node);
      break;
    }
  }

  if (resent == 0) {
    /* Perhaps line is in the resend queue, and we got an:
     *     rs: 3
     *     rs: 6
     * type sequence so try peel forward the resend queue.
     */

    while (1) {
      if (!(node = rr_dev_pop_from_queue (dev, RR_PRIO_RESEND)))
	break;
      rr_dev_log (dev, RR_DEBUG_HIGH,
		  "pop resend node line %d '%s' (%d bytes)\n",
	  (int)node->line, node->block, node->blocksize);
      if (node->line < lineno) {
	rr_dev_prepend_to_queue (dev, RR_PRIO_SENTCACHE, node);
	resent++;
      } else { /* put it back and give up */
	rr_dev_prepend_to_queue (dev, RR_PRIO_RESEND, node);
	break;
      }
    }

    if (resent == 0) {
      rr_dev_log (dev, RR_DEBUG_ALWAYS,
		  "re-send request for unknown (too old) line %ld from cache size %d\n",
		  lineno, dev->sendsize[RR_PRIO_SENTCACHE]);
      rr_dev_emit_error (dev, RR_E_UNCACHED_RESEND, reply, nbytes);
    }
  }

  dev->send_next = 1;
  dev->wait_wr_cb (dev, 1, dev->wait_wr_cl);

  return 0;
}
Пример #2
0
void
rr_dev_reset (rr_dev dev)
{
  empty_buffers (dev);
  rr_dev_log (dev, RR_DEBUG_MEDIUM, "reset dev size to zero\n");
  rr_dev_reset_lineno (dev);
  dev->recvbuf_fill = 0;
}
Пример #3
0
static void
debug_log_block (rr_dev dev, const char *block, int nbytes)
{
  char buffer[4096], *p;
  int num = nbytes >= 4096 ? 4095 : nbytes;
  strncpy (buffer, block, num);
  buffer[num] = '\0';
  if ((p = strchr (buffer, '\n')))
    *p = '\0';
  if ((p = strchr (buffer, '\r')))
    *p = '\0';
  rr_dev_log (dev, RR_DEBUG_MEDIUM, "API enqueue of '%s' queue size %d\n",
	      buffer, rr_dev_buffered_lines (dev));
}
Пример #4
0
int
rr_dev_open (rr_dev dev, const char *port, long speed)
{
  char *error = NULL;
  dev->fd = serial_open (port, speed, &error);
  if (SERIAL_INVALID_CHECK(dev->fd) < 0)
  {
      rr_dev_log (dev, RR_DEBUG_ALWAYS, "Failed to open device %s", error ? error : "<no error>");
      fprintf (stderr, "%s\n", error ? error : "<null>");
      return -1;
  }
  else
    return 0;
}
Пример #5
0
void
rr_dev_handle_ok (rr_dev dev)
{
  int buffered = rr_dev_buffered_lines (dev);

  /* Send as many commands as we get ok's */
  if (dev->init_send_count > 0)
    dev->init_send_count--;
  dev->send_next = 1;

  if (buffered < dev->dev_cmdqueue_size) {
    rr_dev_log (dev, RR_DEBUG_MEDIUM,
		"request more %d < %d\n", buffered, dev->dev_cmdqueue_size);
    dev->more_cb (dev, dev->more_cl);
  }
  dev->wait_wr_cb (dev, 1, dev->wait_wr_cl);

  if (dev->debug_output > RR_DEBUG_ALWAYS)
    { /* Check the sendsize accounts add up */
      int i = 0;
      for (i = 0; i < RR_PRIO_COUNT; ++i) {
	blocknode *p;
	int count = 0;
	for (p = dev->sendhead[i]; p; p = p->next) {
	  if (!p->next && dev->sendtail[i] != p)
	    rr_dev_log (dev, RR_DEBUG_MEDIUM,
			"Error: queue (%d) broken tail pointer %p vs %p\n",
			i, p, dev->sendtail[i]);
	  count++;
	}
	if (count != dev->sendsize[i])
	  rr_dev_log (dev, RR_DEBUG_MEDIUM,
		      "Error: queue (%d) size mismatch: %d vs %d\n",
		      i, count, dev->sendsize[i]);
      }
    }
}
Пример #6
0
int
fived_handle_reply (rr_dev dev, const char *reply, size_t nbytes)
{
  if (!strncasecmp ("ok", reply, 2)) {
    rr_dev_handle_ok (dev);

    /* Parse values */
    char *i;
    for (i = (char*)reply + 2; i < reply + nbytes; ++i) {
      if (isspace (*i))
	continue;
      switch (toupper (*i)) {
      case 'T':
	float_reply (dev, &i, RR_NOZZLE_TEMP);
	break;
      case 'B':
	float_reply (dev, &i, RR_BED_TEMP);
	break;
      case 'C':
	break;
      case 'X':
	float_reply (dev, &i, RR_X_POS);
	break;
      case 'Y':
	float_reply (dev, &i, RR_Y_POS);
	break;
      case 'Z':
	float_reply (dev, &i, RR_Z_POS);
	break;
      case 'E':
	float_reply (dev, &i, RR_E_POS);
	break;
      default:
	break;
	  //return rr_dev_emit_error (dev, RR_E_UNKNOWN_REPLY, reply, nbytes);
      }
    }
    return 0;

  } else if (!strncasecmp ("rs", reply, 2) ||
	     !strncasecmp ("resend", reply, 6)) {
    /* check where the line number starts */
    size_t n_start = strcspn (reply, "123456789");
    if (n_start) {
      long long lineno = strtoll (reply + n_start, NULL, 10);

      if (dev->sendsize[RR_PRIO_SENTCACHE] +
	  dev->sendsize[RR_PRIO_RESEND] <= 1) {
	/*
	 * oh dear - most likely we re-connected to a device that
	 * had problems mid-flow, now we need to re-send the
	 * line-number reset as if it was this line-no it is asking
	 * for a re-send of, or there will be no peace
	 */
	rr_dev_log (dev, RR_DEBUG_ALWAYS,
		    "resetting confused firmware with synthetic resend of line %d\n",
		    lineno);
	rr_dev_enqueue_internal (dev, RR_PRIO_HIGH, "M110", 4, lineno);
	/* re-start the print */
	rr_dev_resend (dev, 0, "synthetic restart", 16);
	return rr_dev_emit_error (dev, RR_E_UNSENT_RESEND, reply, nbytes);
      }
      return rr_dev_resend (dev, lineno, reply, nbytes);
    } else
      return rr_dev_emit_error (dev, RR_E_MALFORMED_RESEND_REQUEST, reply, nbytes);

  } else if (!strncmp("!!", reply, 2)) {
    return rr_dev_emit_error (dev, RR_E_HARDWARE_FAULT, reply, nbytes);

  } else if (!strncasecmp ("start", reply, 5)) {
    return rr_dev_handle_start (dev);

  } else
    return rr_dev_emit_error (dev, RR_E_UNKNOWN_REPLY, reply, nbytes);
}
Пример #7
0
int
rr_dev_handle_writable (rr_dev dev)
{
  ssize_t result;

  if (dev->sendbuf_fill == 0) {
    if (dev->init_send_count <= 0 && !dev->send_next) {
      rr_dev_log (dev, RR_DEBUG_MEDIUM,
		  "writeable - init count is %d, no send_next queue %d resend %d\n",
		  dev->init_send_count, dev->dev_cmdqueue_size,
		  dev->sendsize[RR_PRIO_RESEND]);
      /* wait until there is space in the device buffer and/or an ok */
      dev->wait_wr_cb (dev, 0, dev->wait_wr_cl);
      return 0;
    }

    /* Last block is gone; prepare to send a new block */
    int prio;
    blocknode *node = NULL;
    for (prio = RR_PRIO_COUNT - 1; prio >= 0; --prio) {

      if (dev->paused[prio])
	continue;

      node = dev->sendhead[prio];
      if (node) {
        /* We have a block to send! Get it ready. */
        dev->bytes_sent = 0;
        result = fmtblock (dev, node);
        if (result < 0) {
          /* FIXME: This will confuse code expecting errno to be set */
          return result;
        }
	if (result == 0)
	  rr_dev_log (dev, RR_DEBUG_ALWAYS,
		      "unusual error - nothing in block to write\n");

	dev->send_next = 0;
        dev->sendbuf_fill = result;
        dev->sending_prio = prio;
        break;
      }
    }
    if (!node) {
      /* No data to write */
      dev->wait_wr_cb (dev, 0, dev->wait_wr_cl);
      return 0;
    }
  }

  /* Perform write */
  do {
    result = write (dev->fd, dev->sendbuf + dev->bytes_sent, dev->sendbuf_fill - dev->bytes_sent);
  } while (result < 0 && errno == EINTR);

  if (result < 0)
    return result;

  if (dev->opt_log_cb)
    dev->opt_log_cb (dev, RR_LOG_SEND, dev->sendbuf + dev->bytes_sent,
		     dev->sendbuf_fill - dev->bytes_sent,
		     dev->opt_log_cl);

  dev->bytes_sent += result;

  if (dev->bytes_sent == dev->sendbuf_fill) {
    /* We've sent the complete block. */
    blocknode *node = rr_dev_pop_from_queue (dev, dev->sending_prio);

    if (node->line < 0) {
      node->line = dev->lineno;
      ++(dev->lineno);
    }

    /* Update sent cache */
    assert (node->block != NULL);
    rr_dev_prepend_to_queue (dev, RR_PRIO_SENTCACHE, node);
    if (dev->sendsize[RR_PRIO_SENTCACHE] > (dev->sentcachesize * 3 / 2))
      shrink_sentcache (dev);

    /* Indicate that we're ready for the next. */
    dev->sendbuf_fill = 0;
  }

  return result;
}
Пример #8
0
int
rr_dev_handle_readable (rr_dev dev)
{
  int i;

  /* Grow receive buffer if it's full */
  if (dev->recvbuf_fill >= dev->recvbufsize) {
    dev->recvbufsize *= 2;
    dev->recvbuf = realloc (dev->recvbuf, dev->recvbufsize + 1);
  }

  ssize_t result;

  do {
    result = read (dev->fd, dev->recvbuf + dev->recvbuf_fill, dev->recvbufsize - dev->recvbuf_fill);
  } while (result < 0 && errno == EINTR);

  if (result < 0)
    return result;

  dev->recvbuf_fill += result;

  /* string terminate */
  dev->recvbuf[dev->recvbuf_fill] = '\0';

  /* validate the stream is ascii and of the correct length */
  for (i = 0; i < dev->recvbuf_fill; i++) {
    if (dev->recvbuf[i] == '\0' || !isascii (dev->recvbuf[i])) {
      rr_dev_log (dev, RR_DEBUG_ALWAYS,
		  "invalid char in recvbuf at char %d (0x%2x) full "
		  "msg: '%s', truncating here", i, dev->recvbuf[i],
		  dev->recvbuf);
      dev->recvbuf_fill = i;
      dev->recvbuf[dev->recvbuf_fill] = '\0';
      break;
    }
  }

  /* spot control characters */
  if (dev->recvbuf[0] == 1) {
    rr_dev_log (dev, RR_DEBUG_ALWAYS,
		"unusual - control character 0x%2x 0x%2x\n",
		dev->recvbuf[0], dev->recvbuf[1]);
    memmove (dev->recvbuf, dev->recvbuf + 2, dev->recvbuf_fill - 2);
    dev->recvbuf_fill -= 2;
  }

  /* Scan the buffer and shift it down if we detect a full command */
  size_t reply_span, term_span;
  while (1) {
    /* How many non terminator chars and how many terminator chars after them */
    reply_span = strcspn (dev->recvbuf, REPLY_TERMINATOR);
    term_span = strspn (dev->recvbuf + reply_span, REPLY_TERMINATOR);

    if (term_span > 0) {
      if (reply_span > 0)
	handle_reply (dev, dev->recvbuf, reply_span, term_span);
      /* else - perhaps a prepended \n having sent in reaction to \r previously */

      size_t len = reply_span + term_span;
      assert (dev->recvbuf_fill >= len);
      dev->recvbuf_fill -= len;
      memmove (dev->recvbuf, dev->recvbuf + len, dev->recvbuf_fill + 1);
      continue;
    }
    break;
  }

  return 0;
}
Пример #9
0
rr_dev
rr_dev_create (rr_proto      proto,
	       /* how many commands can we push */
	       size_t        dev_cmdqueue_size,
	       /* callbacks cf. above */
	       rr_reply_fn   reply_cb,   void *reply_cl,
	       rr_more_fn    more_cb,    void *more_cl,
	       rr_error_fn   error_cb,   void *error_cl,
	       /* notify when socket is writeable */
	       rr_wait_wr_fn wait_wr_cb, void *wait_wr_cl,
	       /* optional (or NULL, NULL) */
	       rr_log_fn     opt_log_cb, void *opt_log_cl)
{
  unsigned int i;
  rr_dev dev;

  /* Required callbacks */
  if (!reply_cb || !more_cb || !error_cb || !wait_wr_cb)
    return NULL;

  dev = malloc (sizeof(struct rr_dev_t));
  if (!dev)
    return NULL;

  dev->proto = proto;
  dev->dev_cmdqueue_size = dev_cmdqueue_size;
  dev->reply_cb = reply_cb;
  dev->reply_cl = reply_cl;
  dev->more_cb = more_cb;
  dev->more_cl = more_cl;
  dev->error_cb = error_cb;
  dev->error_cl = error_cl;
  dev->wait_wr_cb = wait_wr_cb;
  dev->wait_wr_cl = wait_wr_cl;
  dev->opt_log_cb = opt_log_cb;
  dev->opt_log_cl = opt_log_cl;

  dev->lineno = 0;
  dev->fd = SERIAL_INVALID_INIT;
  dev->send_next = 0;
  dev->init_send_count = dev->dev_cmdqueue_size;
  dev->debug_output = 0;
  if (getenv("RR_DEBUG"))
    dev->debug_output = atoi (getenv("RR_DEBUG"));

  dev->sentcachesize = dev_cmdqueue_size * 4 + 64;

  for (i = 0; i < RR_PRIO_ALL_QUEUES; ++i) {
    dev->sendsize[i] = 0;
    dev->sendhead[i] = NULL;
    dev->sendtail[i] = NULL;
    dev->paused[i] = 0;
  }
  dev->sendbuf_fill = 0;
  dev->bytes_sent = 0;
  dev->recvbufsize = INITIAL_RECVBUFSIZE;
  dev->recvbuf = calloc (dev->recvbufsize + 1, sizeof (char));
  dev->recvbuf_fill = 0;

  rr_dev_log (dev, RR_DEBUG_ALWAYS, "Connecting with libreprap\n");

  return dev;
}