/** * Prints command queue - convenience and bugfixing. */ void ClientSonyVISCAoverIP::printCommandQueue(uint8_t cam) { for (uint8_t a = 1; a < SONYVISCAIP_comBufSize; a++) { // Start from the next non-sent command Serial << a << ": idx:" << ((_applicationCommandBufferCurrentIndex[cam - 1] + a) % SONYVISCAIP_comBufSize) << ": "; for (uint8_t b = 0; b < 15; b++) { Serial << _HEXPADL(_applicationCommandBuffer[cam - 1][(_applicationCommandBufferCurrentIndex[cam - 1] + a) % SONYVISCAIP_comBufSize][b], 2, "0") << " "; } Serial << "\n"; if ((_applicationCommandBufferCurrentIndex[cam - 1] + a) % SONYVISCAIP_comBufSize == _applicationCommandBufferLastPositionAdded[cam - 1]) { break; } } }
bool ClientAJAKumoTCP::receiveData() { _inputPos = 0; memset(_inputBuffer, 0, ClientAJAKumoTCP_INPUTBUFFER_SIZE); while(_client.available() && _inputPos < ClientAJAKumoTCP_INPUTBUFFER_SIZE) { char c = _client.read(); _inputBuffer[_inputPos++] = c; if(_serialOutput > 1) Serial << _HEXPADL(c, 2, "0") << ":"; if(c == 0x04) { if(_serialOutput > 1) { Serial << " : " << (char*)_inputBuffer << "\n"; } parseIncoming(_inputBuffer, _inputPos); _inputPos = 0; return true; } } return false; }
void ClientAJAKumoTCP::transmitPacket(char* data) { uint8_t len = strlen(data); uint8_t *_buffer = (uint8_t*)malloc(6 + len); // Prepare packet _buffer[0] = 0x01; // SOH _buffer[1] = 'N'; // Protocol ID _buffer[2] = toASCII(_sessionID & 0xF); for(uint8_t i = 0; i < len; i++) { if(data[i] == ',') { _buffer[3+i] = 0x09; // HT } else { _buffer[3+i] = data[i]; } } uint16_t checksum = calculateChecksum(_buffer, 3+len); _buffer[3+len] = checksum >> 8; _buffer[4+len] = checksum & 0xFF; _buffer[5+len] = 0x04; // EOT if(_client.connected()) { if(_serialOutput > 1) { for(uint8_t j=0; j<6+len; j++) { Serial << _HEXPADL(_buffer[j], 2, "0") << ":"; } Serial << "\n"; } _client.write(_buffer, 6 + len); } free(_buffer); }
/** * Keeps connection to the cameras alive: Reads UDP incoming and empties/processes the outgoing command queue * Therefore: Call this in the loop() function and make sure it gets called multiple times a second, including after sending commands. */ void ClientSonyVISCAoverIP::runLoop(uint16_t delayTime) { unsigned long enterTime = millis(); do { // Reading incoming UDP data on port: while (true) { // Iterate until UDP buffer is empty uint16_t packetSize = _Udp.parsePacket(); if (_Udp.available()) { IPAddress remote = _Udp.remoteIP(); uint8_t cam = remote[3] - forthByteBase; // Select the cam from the IP address. if (camNumOK(cam)) { // valid range for VISCA _Udp.read(_packetBuffer, 8); // Read header uint16_t payloadType = word(_packetBuffer[0], _packetBuffer[1]); uint16_t packetLength = word(_packetBuffer[2], _packetBuffer[3]); uint16_t sequenceNumber = word(_packetBuffer[6], _packetBuffer[7]); // Actually, this is probably a 32 bit unsigned long... if (packetSize == packetLength + 8) { // Just to make sure these are equal, they should be! if (_serialOutput & 0x80) { Serial << "Incoming Packet from cam #" << cam << " (" << packetLength << " bytes): 0x" << _HEXPADL(payloadType, 4, "0") << ": "; for (uint8_t a = 4; a < 8; a++) { Serial << _HEXPADL(_packetBuffer[a], 2, "0") << " "; } Serial << " / "; } // Read the VISCA packet itself: _Udp.read(_packetBuffer, SONYVISCAIP_packetBufferLength); if (_serialOutput & 0x80) { for (uint8_t a = 0; a < packetLength; a++) { Serial << _HEXPADL(_packetBuffer[a], 2, "0") << " "; } Serial << ": "; } if (!_isConnected[cam - 1]) { // If not connected, look for reply to reset counter package if (payloadType == 0x0201 && packetLength == 1 && _packetBuffer[0] == 0x01) { // Response to sequence number "RESET" connect package _isConnected[cam - 1] = true; if (_serialOutput & 0x80) { Serial << F("Connected to VISCA camera #") << cam << "\n"; } } } else { _lastContact[cam - 1] = millis(); _pushedStateUpdate[cam - 1] = false; if (_camLastTX[cam - 1] > 0) { // Waiting for response // if (_localPacketIdCounter[cam - 1] == sequenceNumber) { // the returned sequence number is a reference to the sequence number we sent to the camera - but notice that an ack and complete package will refer to the same number. At the moment I see no need to track the package number - we just look for acks and ignores "completes" if (payloadType == 0x0111 && _packetBuffer[0] == 0x90) { if (_applicationCommandBuffer[cam - 1][_applicationCommandBufferCurrentIndex[cam - 1]][0] == 0x01 && packetLength == 3 && (_packetBuffer[1] & 0xF0) == 0x40) { // an ack for a command if (_serialOutput & 0x80) { Serial << "ACK in " << (millis() - _camLastTX[cam - 1]) << "ms\n"; } _camLastTX[cam - 1] = 0; } if (_applicationCommandBuffer[cam - 1][_applicationCommandBufferCurrentIndex[cam - 1]][0] == 0x01 && packetLength == 4 && (_packetBuffer[1] & 0xF0) == 0x60) { // an error for a command if (_serialOutput) { Serial << "ERROR in " << (millis() - _camLastTX[cam - 1]) << "ms\n"; } _camLastTX[cam - 1] = 0; } if (_applicationCommandBuffer[cam - 1][_applicationCommandBufferCurrentIndex[cam - 1]][0] == 0x09 && (_packetBuffer[1] & 0xF0) == 0x50) { // a inquery answer if (_serialOutput & 0x80) { Serial << "INQUERY ANS in " << (millis() - _camLastTX[cam - 1]) << "ms\n"; } _camLastTX[cam - 1] = 0; parsePacketBufferInqueryData(cam); } } } } if (_serialOutput & 0x80) { Serial << "\n"; } } else { //#if SONYVISCAIP_debug if (_serialOutput & 0x80) { Serial.print(F("ERROR: Packet size mismatch: ")); Serial.print(packetSize, DEC); Serial.print(F(" != ")); Serial.println(packetLength, DEC); } //#endif // Flushing larger packets while (_Udp.available()) { _Udp.read(_packetBuffer, SONYVISCAIP_packetBufferLength); } } } else { Serial << "ERROR: Cam number " << cam << " out of range!\n"; } } else break; } // Send a command from buffer to cameras: for (uint8_t cam = 1; cam <= SONYVISCAIP_cams; cam++) { sendCommand(cam); } // If connection is gone anyway, try to reconnect: for (uint8_t cam = 1; cam <= SONYVISCAIP_cams; cam++) { if (_camOnline[cam - 1]) { if (hasTimedOut(_lastContact[cam - 1], 400) && _applicationCommandBufferLastPositionAdded[cam - 1] == _applicationCommandBufferCurrentIndex[cam - 1]) { // Send a "get state update" when nothing else happens (output buffer is empty) // if (_serialOutput) // Serial.println(F("pushNextStateUpdate()")); pushNextStateUpdate(cam); } else if (hasTimedOut(_lastContact[cam - 1], 1000 + 2000)) { // Allow a get state update 2000 ms to register if (_serialOutput) Serial.println(F("Connection to Camera has timed out - reconnecting!")); connect(cam); } } } } while (delayTime > 0 && !hasTimedOut(enterTime, delayTime)); }