public void connect() { byte[] connect_request = new byte[REPORTSIZE]; byte[] response = new byte[REPORTSIZE]; connect_request[2] = (byte)(connect_request[2] | BYTE2_CONNECT_BIT); bool connected = false; while (!connected) { //wait till connect bit is received on a request with connect bit set HIDout.Write(connect_request, 0, REPORTSIZE); Console.WriteLine("Connect request sent"); HIDin.Read(response, 0, REPORTSIZE); byte SEQ = (byte)(response[2] & BITMASK); bool CONNECT_BIT = (response[2] & BYTE2_CONNECT_BIT) != 0; if (CONNECT_BIT) { connect_request[2] = (byte)(connect_request[2] | SEQ); // set ACK to SEQ and infor sender that we are in sync by sending correct ACK HIDout.Write(connect_request, 0, REPORTSIZE); //update the start seq number (this is all this handshake is about) state_last_valid_seq_received = SEQ; connected = true; } else { print_debug(String.Format("SEQ {0} received on connect, but no connect response", SEQ)); } } this.state_connected = true; this.state_invalid_seq_received = false; }
private void HIDOutThreadLoop() { //int PAYLOAD_MAX_INDEX = PAYLOAD_MAX_SIZE - 1; byte BYTE1_RESEND_BIT = 1 << 6; Console.WriteLine("Starting write loop continously sending HID ouput report"); List <byte> current_stream = new List <byte>(); //represents the remainder of the stream (from upper layer), which is currently processed (splitted into chunks, capable of being sent via HID report) List <byte> report_payload; //represents the payload which gets sent in a single report while (true) { bool last_report_of_stream = true; //if this bit is set, this means the report is the last one in a fragemented STREAM //check if there isn't a stream which hasn't been fully sent (remaining chunks in current_stream) if (current_stream.Count == 0) { // no pending data in current stream, check if new full length stream is waiting in out queue if (this.state_report_out_queue.Count > 0) { //dequeue next stream and put it into current_stream current_stream.AddRange(PopOutputStream()); //type casting to byte array needed, as this isn't a generic Queue of type byte[] (synchronization wouldn't be possible) } } //check if stream is small enough to fit into a single report if (current_stream.Count > PAYLOAD_MAX_SIZE) { //no report_payload = current_stream.GetRange(0, PAYLOAD_MAX_SIZE); //fetch MAX_SIZE bytes from the beginning current_stream.RemoveRange(0, PAYLOAD_MAX_SIZE); //remove fetched bytes } else { report_payload = current_stream.GetRange(0, current_stream.Count); //put the rest of the stream into payload current_stream.Clear(); //empty out current_stream } //if remaining data in current stream, set FIN bit to false if (current_stream.Count > 0) { last_report_of_stream = false; } /* * Create the final report which should be send */ //if (report_payload.Count < 62 && report_payload.Count > 0) Console.WriteLine(String.Format("Output report with payload size {0} written", report_payload.Count)); //create LEN_FIN byte byte BYTE1_LEN_FLAGS = (byte)(report_payload.Count & BITMASK); if (last_report_of_stream) { BYTE1_LEN_FLAGS += BYTE1_FIN_BIT; } byte BYTE2_ACK = state_last_valid_seq_received; // set ACK byte to the last valid sequence received //set resend request bit, if last SEQ received was invalid if (state_invalid_seq_received) { BYTE1_LEN_FLAGS += BYTE1_RESEND_BIT; // set RESEND BIT in byte1 BYTE2_ACK += 1; //increase the ACK by one (las valid SEQ + 1 is the next needed SEQ) if (BYTE2_ACK > MAX_SEQ) { BYTE2_ACK -= MAX_SEQ; } } //prepend head to report (first byte is always 0, as it represents the unused HID report ID) report_payload.InsertRange(0, new byte[] { 0, BYTE1_LEN_FLAGS, BYTE2_ACK }); byte[] report = new byte[REPORTSIZE]; report_payload.CopyTo(report); /* * Write report to HID device */ HIDout.Write(report, 0, REPORTSIZE); } }