bool robotInfraredDetectorHasObstacle(enum InfraredDetectorGroupType type) {
    OutputStream* outputStream = getDriverRequestOutputStream();
    InputStream* inputStream = getDriverResponseInputStream();

    append(outputStream, ROBOT_INFRARED_DETECTOR_DEVICE_HEADER);
    append(outputStream, COMMAND_INFRARED_DETECTOR_DETECTION);
    appendHex2(outputStream, type);
    bool result = transmitFromDriverRequestBuffer();
    if (result) {
        int result = readHex2(inputStream);
        return result == 0x01;
    }
    return false;
}
bool clientDistributor2018CleanNext(int direction) {
    OutputStream* outputStream = getDriverRequestOutputStream();
    InputStream* inputStream = getDriverResponseInputStream();

    append(outputStream, LAUNCHER_2018_DEVICE_HEADER);
    append(outputStream, DISTRIBUTOR_LOAD_NEXT_BALL_COMMAND);
    appendHex2(outputStream, direction);

    bool result = transmitFromDriverRequestBuffer();

    // Read the distance of detection, but we don't care about
    readHex2(inputStream);

    return result;
}
BOOL sendStrategyNextStep() {
	appendString(getOutputStreamLogger(INFO), "sendStrategyNextStep\n");

    OutputStream* outputStream = getDriverRequestOutputStream();
    InputStream* inputStream = getDriverResponseInputStream();

    append(outputStream, COMMAND_STRATEGY_NEXT_STEP);

    BOOL result = transmitFromDriverRequestBuffer();
    if (result) {
        int result = readHex2(inputStream);
		return result;
    }
    return FALSE;
}
bool transmitFromDriverRequestBuffer() {
    // Handle redirection
    if (redirectFunction != NULL) {
        bool result = redirectFunction();
        return result;
    }
    // We do exactly as if the data was written by a end-user
    // requestBuffer must be filled before calling this method
    Buffer* requestBuffer = getDriverRequestBuffer();
    Buffer* responseBuffer = getDriverResponseBuffer();

    InputStream* inputStream = getDriverResponseInputStream();
    if (inputStream == NULL) {
        writeError(DRIVER_INPUT_STREAM_NULL);
        return false;
    }

    // The first char is the device header
    unsigned dataDispacherLength = 0;
    unsigned char deviceHeader = bufferGetCharAtIndex(requestBuffer, DEVICE_HEADER_INDEX);

    if (deviceHeader == DISPATCHER_COMMAND_HEADER) {
        dataDispacherLength = DISPATCHER_COMMAND_AND_INDEX_HEADER_LENGTH;
        // Reload the real Device Header
        deviceHeader = bufferGetCharAtIndex(requestBuffer, dataDispacherLength + DEVICE_HEADER_INDEX);
    }

    // The second char is the command header
    unsigned char commandHeader = bufferGetCharAtIndex(requestBuffer, dataDispacherLength + COMMAND_HEADER_INDEX);

    bool result = handleStreamInstruction(
            requestBuffer,
            responseBuffer,
            // Don't copy to an outputStream, because, we
            // want to read the content of responseBuffer
            NULL,
            // TODO : Check why we don't provide any NotificationOutputStream
            NULL,
            // No Input Filter
            NULL,
            // No Output Filter
            NULL);

    // We need ack
    result = checkIsAck(inputStream);
    if (!result) {
        // The buffer is corrupted, but we would like to avoid further problem
        clearInputStream(inputStream);
        return false;
    }
    // Device header answer with the same header as the request
    checkIsChar(inputStream, deviceHeader);
    if (!result) {
        // The buffer is corrupted, but we would like to avoid further problem
        clearInputStream(inputStream);
        return false;
    }
    // Command header answer with the same header as the request
    checkIsChar(inputStream, commandHeader);
    if (!result) {
        // The buffer is corrupted, but we would like to avoid further problem
        clearInputStream(inputStream);
        return false;
    }

    return result;
}