private CrtpResponse Send(CrtpMessage outMessage) { var content = outMessage.Message; // Adds 1bit counter to CRTP header to guarantee that no ack(downlink) // payload are lost and no uplink packet are duplicated. // The caller should resend packet if not acked(ie.same as with a // direct call to crazyradio.send_packet) if (_safeLink) { content[0] &= 0xF3; content[0] |= (byte)(_curr_up << 3 | _curr_down << 2); } var result = new CrtpResponse(_crazyradioDriver.SendData(content)); if (_safeLink) { if (result.Ack && ((result.Content.Header & 0x04) == (_curr_down << 2))) { _curr_down = (byte)(1 - _curr_down); } if (result.Ack) { _curr_up = (byte)(1 - _curr_up); } } return(result); }
private void TrackLinkQuality(CrtpResponse response) { var retry = 10 - response.Retry; _retries.Enqueue(retry); _retry_sum += retry; while (_retries.Count > 100) { var oldest = _retries.Dequeue(); _retry_sum -= oldest; } var linkQuality = ((float)_retry_sum / _retries.Count) * 10; LinkQuality?.Invoke(this, new LinkQualityEventArgs(linkQuality)); }
private void CommunicationLoop() { _retryBeforeDisconnect = NumberOfRetries; _emptyCounter = 0; _waitTime = 0; var emptyMessage = new CrtpMessage(0xff, new byte[0]); var outMessage = emptyMessage; // Try up to 10 times to enable the safelink mode TryEnableSafeLink(); _comStarted.Set(); _log.Info("Communication with crazyfly started."); while (_isRunning) { CrtpResponse response = null; try { response = Send(outMessage); } catch (Exception ex) { _log.Error("error sending message", ex); LinkError?.Invoke(this, new LinkErrorEventArgs("failed to send: " + ex)); } // Analyse the in data packet ... if (response == null) { _log.Info("Dongle reported ACK status == None"); continue; } TrackLinkQuality(response); if (!response.Ack) { UpdateRetryCount(); if (_retryBeforeDisconnect > 0) { continue; } // else try a next packet to send. } _retryBeforeDisconnect = NumberOfRetries; // after we managed to send the message, set the next one to the ping message again. outMessage = emptyMessage; if (response.HasContent) { _waitTime = 0; _emptyCounter = 0; lock (_lock) { _log.Debug($"incoming queue count: {_incoming.Count}; enqueue for {response.Content.Port} / {response.Content.Channel}"); _incoming.Enqueue(response.Content); while (_incoming.Count > _maxInqueue) { // dequue old messages which are not processed and therefore stale. var old = _incoming.Dequeue(); _log.Warn($"Too many old message not processed, drop for port: {old.Port}."); } _waitForInqueue.Set(); } } else { _emptyCounter += 1; if (_emptyCounter > 10) { _emptyCounter = 10; // Relaxation time if the last 10 packet where empty _waitTime = 10; } else { // send more ack messages to get more responses and don't wait for // user out messages; start waiting only after 10 empty messages received. _waitTime = 0; } } _waitForOutqueue.Wait(_waitTime); lock (_lock) { if (_outgoing.Count > 0) { outMessage = _outgoing.Dequeue(); } if (_outgoing.Count == 0) { _waitForOutqueue.Reset(); } } } _log.Debug("send loop ended"); }