brother_mfp: added query block and error conditions

Now detects cover open and paper jam.
Also formalised the query packet which occurs during initialization.
Hopefully, we will be able to decode this for useful information.
brother_mfp_backend
Ralph Little 2022-10-26 12:58:45 -07:00
rodzic 9bbf24cf97
commit a8a9e895b9
4 zmienionych plików z 416 dodań i 74 usunięć

Wyświetl plik

@ -585,44 +585,66 @@ SANE_Status BrotherUSBDriver::Init ()
}
/*
* First prep parameter block.
*
* TODO: Move this block construction to common code.
* Execute Query request.
*
*/
(void) memcpy (small_buffer, "\x1b" "\x51" "\x0a" "\x80", 4);
size_t buf_size = 4;
size_t packet_len = 0;
DecodeStatus dec_ret = encoder->EncodeQueryBlock (small_buffer,
sizeof(small_buffer),
&packet_len);
if (dec_ret != DECODE_STATUS_GOOD)
{
DBG (DBG_SERIOUS,
"BrotherUSBDriver::Init: failed to generate query block: %d\n",
dec_ret);
(void) CancelScan ();
return SANE_STATUS_INVAL;
}
size_t buf_size = packet_len;
res = sanei_usb_write_bulk (fd, small_buffer, &buf_size);
if (res != SANE_STATUS_GOOD)
{
DBG (DBG_SERIOUS,
"BrotherUSBDriver::Init: failed to send first prep block: %d\n",
"BrotherUSBDriver::Init: failed to send query block: %d\n",
res);
(void) CancelScan ();
return res;
}
if (buf_size != 4)
if (buf_size != packet_len)
{
DBG (DBG_SERIOUS, "BrotherUSBDriver::Init: failed to write init block\n");
DBG (DBG_SERIOUS, "BrotherUSBDriver::Init: failed to write query block\n");
(void) CancelScan ();
return SANE_STATUS_IO_ERROR;
}
/*
* Try to read the response.
*
* TODO: Check response.
*
*/
buf_size = sizeof(small_buffer);
useconds_t timeout = TIMEOUT_SECS(8);
res = PollForRead (small_buffer, &buf_size, &timeout);
if (res != SANE_STATUS_GOOD)
{
DBG (
DBG_SERIOUS,
"BrotherUSBDriver::Init: failed to read query block response: %d\n", res);
(void) CancelScan ();
return res;
}
BrotherQueryResponse query_resp;
dec_ret = encoder->DecodeQueryBlockResp (small_buffer, buf_size, query_resp);
if (dec_ret != DECODE_STATUS_GOOD)
{
DBG (DBG_SERIOUS,
"BrotherUSBDriver::Init: failed to receive first prep block response: %d\n",
res);
"BrotherUSBDriver::Init: failed to read query block response: %d\n",
dec_ret);
(void) CancelScan ();
return res;
}
@ -842,6 +864,12 @@ SANE_Status BrotherUSBDriver::StartScan ()
/*
* Construct the "ADF" block.
*
* This is a query to see if the ADF contains documents.
* TBH I don't really know why we would do this because the source
* (flatbed/ADF) selection seems to be automatic. Perhaps there is a way
* to select the source that we haven't seen to override that behaviour?
* I add it here for completeness though.
*
*/
packet_len = 0;
dec_ret = encoder->EncodeADFBlock (small_buffer, sizeof(small_buffer), &packet_len);
@ -898,17 +926,12 @@ SANE_Status BrotherUSBDriver::StartScan ()
"BrotherUSBDriver::StartScan: ADF block response block invalid: %d\n",
dec_ret);
(void) CancelScan ();
return res;
return encoder->DecodeStatusToSaneStatus(dec_ret);
}
if (adf_resp.resp_code != 0xc2)
{
DBG (DBG_SERIOUS,
"BrotherUSBDriver::StartScan: ADF block response invalid: %u\n",
(unsigned int) adf_resp.resp_code);
(void) CancelScan ();
return SANE_STATUS_IO_ERROR;
}
DBG (DBG_DETAIL,
"BrotherUSBDriver::StartScan: ADF reports readiness?: %s\n",
adf_resp.adf_ready? "Yes": "No");
}
/*

Wyświetl plik

@ -48,18 +48,38 @@
/*
* Block header identifiers.
*
* Scan data codes.
*
*/
#define BROTHER_DATA_BLOCK_SCAN_FINISHED 0x80
#define BROTHER_DATA_BLOCK_END_OF_FRAME_MORE 0x81
#define BROTHER_DATA_BLOCK_END_OF_FRAME_NO_MORE 0x82
#define BROTHER_DATA_BLOCK_CANCEL 0x86
#define BROTHER_DATA_BLOCK_JPEG 0x64
#define BROTHER_DATA_BLOCK_GRAY_RAW 0x40
#define BROTHER_DATA_BLOCK_GRAY_RLENGTH 0x42
#define BROTHER_DATA_BLOCK_RED_RAW 0x44
#define BROTHER_DATA_BLOCK_GREEN_RAW 0x48
#define BROTHER_DATA_BLOCK_BLUE_RAW 0x4c
#define BROTHER_DATA_BLOCK_JPEG 0x64
/*
* Termination codes.
*/
#define BROTHER_DATA_BLOCK_SCAN_FINISHED 0x80
#define BROTHER_DATA_BLOCK_END_OF_FRAME_MORE 0x81
#define BROTHER_DATA_BLOCK_END_OF_FRAME_NO_MORE 0x82
#define BROTHER_DATA_BLOCK_CANCEL 0x86
/*
* Error condition codes.
*
*/
#define BROTHER_DATA_QUERY_RESPONSE 0xc1
// Seen references to this code elsewhere but I have not seen it from a device.
#define BROTHER_DATA_BLOCK_NO_DOCS 0xc2
#define BROTHER_DATA_BLOCK_PAPER_JAM 0xc3
#define BROTHER_DATA_BLOCK_COVER_OPEN 0xc4
// unsure as to the meaning of this or how to get it again.
#define BROTHER_DATA_BLOCK_CLEARING_PAPER 0xc5
const char* BrotherEncoder::ScanModeToText (BrotherScanMode scan_mode)
{
static const char *scan_mode_text[] =
@ -68,7 +88,6 @@ const char* BrotherEncoder::ScanModeToText (BrotherScanMode scan_mode)
return scan_mode_text[scan_mode];
}
DecodeStatus BrotherEncoder::SetScanMode (BrotherScanMode scan_mode)
{
@ -149,6 +168,102 @@ DecodeStatus BrotherEncoder::SetScanDimensions (SANE_Int pixel_x_offset, SANE_In
* --------------------------------------------
*
*/
DecodeStatus BrotherEncoderFamily2::EncodeQueryBlock (SANE_Byte *data, size_t data_len,
size_t *length)
{
*length = snprintf ((char*) data, data_len, "\x1b" "\x51" "\x0a" "\x80");
if (*length > data_len)
{
DBG (DBG_SERIOUS,
"BrotherEncoderFamily2::EncodeBasicParameterBlock: query block too long for buffer: %zu\n",
*length);
return DECODE_STATUS_INVAL;
}
return DECODE_STATUS_GOOD;
}
DecodeStatus BrotherEncoderFamily2::DecodeQueryBlockResp (const SANE_Byte *data, size_t data_len,
BrotherQueryResponse &response)
{
/*
* Formatting and content checks.
*
*/
if ((data_len != 16) || (data[0] != BROTHER_DATA_QUERY_RESPONSE))
{
DBG (DBG_SERIOUS,
"BrotherEncoderFamily2::DecodeSessionResp: invalid query response block: len = %zu\n",
data_len);
return DECODE_STATUS_ERROR;
}
/*
* TODO: decode the response block to fill in the details.
*
*/
response.dummy = 0;
return DECODE_STATUS_GOOD;
}
DecodeStatus BrotherEncoderFamily2::EncodeADFBlock (SANE_Byte *data, size_t data_len, size_t *length)
{
*length = snprintf ((char*) data, data_len, "\x1b" "D\nADF\n" "\x80");
if (*length > data_len)
{
DBG (DBG_SERIOUS,
"BrotherEncoderFamily2::EncodeBasicParameterBlock: ADF block too long for buffer: %zu\n",
*length);
return DECODE_STATUS_INVAL;
}
return DECODE_STATUS_GOOD;
}
DecodeStatus BrotherEncoderFamily2::DecodeADFBlockResp (const SANE_Byte *data, size_t data_len,
BrotherADFResponse &response)
{
if (data_len != 1)
{
DBG (DBG_SERIOUS,
"BrotherEncoderFamily2::DecodeADFBlockResp: ADF block response invalid: %zu\n",
data_len);
return DECODE_STATUS_ERROR;
}
/*
* We can get error condition codes from this block.
*
*/
switch (data[0])
{
case BROTHER_DATA_BLOCK_PAPER_JAM:
return DECODE_STATUS_PAPER_JAM;
case BROTHER_DATA_BLOCK_COVER_OPEN:
return DECODE_STATUS_COVER_OPEN;
case BROTHER_DATA_BLOCK_NO_DOCS:
response.adf_ready = SANE_FALSE;
return DECODE_STATUS_GOOD;
case BROTHER_DATA_BLOCK_SCAN_FINISHED:
response.adf_ready = SANE_TRUE;
return DECODE_STATUS_GOOD;
default:
return DECODE_STATUS_ERROR;
}
}
DecodeStatus BrotherEncoderFamily2::DecodeSessionResp (const SANE_Byte *data, size_t data_len,
BrotherSessionResponse &response)
{
@ -585,6 +700,19 @@ DecodeStatus BrotherEncoderFamily2::DecodeScanDataHeader (const SANE_Byte *src_d
return DECODE_STATUS_CANCEL;
}
if ((header.block_type == BROTHER_DATA_BLOCK_PAPER_JAM)
|| (header.block_type == BROTHER_DATA_BLOCK_CLEARING_PAPER))
{
*src_data_consumed = 1;
return DECODE_STATUS_PAPER_JAM;
}
if (header.block_type == BROTHER_DATA_BLOCK_COVER_OPEN)
{
*src_data_consumed = 1;
return DECODE_STATUS_COVER_OPEN;
}
/*
* Other data-carrying packets.
*
@ -634,6 +762,100 @@ DecodeStatus BrotherEncoderFamily2::DecodeButtonStateResp (const SANE_Byte *data
* --------------------------------------------
*
*/
DecodeStatus BrotherEncoderFamily3::EncodeQueryBlock (SANE_Byte *data, size_t data_len,
size_t *length)
{
*length = snprintf ((char*) data, data_len, "\x1b" "\x51" "\x0a" "\x80");
if (*length > data_len)
{
DBG (DBG_SERIOUS,
"BrotherEncoderFamily2::EncodeBasicParameterBlock: query block too long for buffer: %zu\n",
*length);
return DECODE_STATUS_INVAL;
}
return DECODE_STATUS_GOOD;
}
DecodeStatus BrotherEncoderFamily3::DecodeQueryBlockResp (const SANE_Byte *data, size_t data_len,
BrotherQueryResponse &response)
{
/*
* Formatting and content checks.
*
*/
if ((data_len != 20) || (data[0] != BROTHER_DATA_QUERY_RESPONSE))
{
DBG (DBG_SERIOUS,
"BrotherEncoderFamily3::DecodeSessionResp: invalid query response block: len = %zu\n",
data_len);
return DECODE_STATUS_ERROR;
}
/*
* TODO: decode the response block to fill in the details.
*
*/
response.dummy = 0;
return DECODE_STATUS_GOOD;
}
DecodeStatus BrotherEncoderFamily3::EncodeADFBlock (SANE_Byte *data, size_t data_len, size_t *length)
{
*length = snprintf ((char*) data, data_len, "\x1b" "D\nADF\n" "\x80");
if (*length > data_len)
{
DBG (DBG_SERIOUS,
"BrotherEncoderFamily3::EncodeBasicParameterBlock: ADF block too long for buffer: %zu\n",
*length);
return DECODE_STATUS_INVAL;
}
return DECODE_STATUS_GOOD;
}
DecodeStatus BrotherEncoderFamily3::DecodeADFBlockResp (const SANE_Byte *data, size_t data_len,
BrotherADFResponse &response)
{
if (data_len != 1)
{
DBG (DBG_SERIOUS,
"BrotherEncoderFamily2::DecodeADFBlockResp: ADF block response invalid: %zu\n",
data_len);
return DECODE_STATUS_ERROR;
}
/*
* We can get error condition codes from this block.
*
*/
switch (data[0])
{
case BROTHER_DATA_BLOCK_PAPER_JAM:
return DECODE_STATUS_PAPER_JAM;
case BROTHER_DATA_BLOCK_COVER_OPEN:
return DECODE_STATUS_COVER_OPEN;
case BROTHER_DATA_BLOCK_NO_DOCS:
response.adf_ready = SANE_FALSE;
return DECODE_STATUS_GOOD;
case BROTHER_DATA_BLOCK_SCAN_FINISHED:
response.adf_ready = SANE_TRUE;
return DECODE_STATUS_GOOD;
default:
return DECODE_STATUS_ERROR;
}
}
DecodeStatus BrotherEncoderFamily3::DecodeSessionResp (const SANE_Byte *data, size_t data_len,
BrotherSessionResponse &response)
@ -1081,6 +1303,19 @@ DecodeStatus BrotherEncoderFamily3::DecodeScanDataHeader (const SANE_Byte *src_d
return DECODE_STATUS_CANCEL;
}
if ((header.block_type == BROTHER_DATA_BLOCK_PAPER_JAM)
|| (header.block_type == BROTHER_DATA_BLOCK_CLEARING_PAPER))
{
*src_data_consumed = 1;
return DECODE_STATUS_PAPER_JAM;
}
if (header.block_type == BROTHER_DATA_BLOCK_COVER_OPEN)
{
*src_data_consumed = 1;
return DECODE_STATUS_COVER_OPEN;
}
if (header.block_type == BROTHER_DATA_BLOCK_END_OF_FRAME_NO_MORE)
{
if (src_data_len < 10)
@ -1140,6 +1375,50 @@ DecodeStatus BrotherEncoderFamily3::DecodeButtonStateResp (const SANE_Byte *data
* --------------------------------------------
*
*/
DecodeStatus BrotherEncoderFamily4::EncodeQueryBlock (SANE_Byte *data, size_t data_len,
size_t *length)
{
*length = snprintf ((char*) data, data_len, "\x1b" "\x51" "\x0a" "\x80");
if (*length > data_len)
{
DBG (DBG_SERIOUS,
"BrotherEncoderFamily4::EncodeBasicParameterBlock: query block too long for buffer: %zu\n",
*length);
return DECODE_STATUS_INVAL;
}
return DECODE_STATUS_GOOD;
}
DecodeStatus BrotherEncoderFamily4::DecodeQueryBlockResp (const SANE_Byte *data, size_t data_len,
BrotherQueryResponse &response)
{
/*
* Formatting and content checks.
*
*/
if ((data_len != 72) || (data[0] != BROTHER_DATA_QUERY_RESPONSE))
{
DBG (DBG_SERIOUS,
"BrotherEncoderFamily4::DecodeSessionResp: invalid query response block: len = %zu\n",
data_len);
return DECODE_STATUS_ERROR;
}
/*
* TODO: decode the response block to fill in the details.
*
*/
response.dummy = 0;
return DECODE_STATUS_GOOD;
}
DecodeStatus BrotherEncoderFamily4::DecodeSessionResp (const SANE_Byte *data, size_t data_len,
BrotherSessionResponse &response)
{
@ -1241,7 +1520,7 @@ DecodeStatus BrotherEncoderFamily4::EncodeADFBlock (SANE_Byte *data, size_t data
if (*length > data_len)
{
DBG (DBG_SERIOUS,
"BrotherEncoderFamily4::EncodeBasicParameterBlock: parameter block too long for buffer: %zu\n",
"BrotherEncoderFamily4::EncodeBasicParameterBlock: ADF block too long for buffer: %zu\n",
*length);
return DECODE_STATUS_INVAL;
}
@ -1252,14 +1531,37 @@ DecodeStatus BrotherEncoderFamily4::EncodeADFBlock (SANE_Byte *data, size_t data
DecodeStatus BrotherEncoderFamily4::DecodeADFBlockResp (const SANE_Byte *data, size_t data_len,
BrotherADFResponse &response)
{
if ((data_len != 1))
if (data_len != 1)
{
DBG (DBG_SERIOUS,
"BrotherEncoderFamily2::DecodeADFBlockResp: ADF block response invalid: %zu\n",
data_len);
return DECODE_STATUS_ERROR;
}
response.resp_code = data[0];
/*
* We can get error condition codes from this block.
*
*/
switch (data[0])
{
case BROTHER_DATA_BLOCK_PAPER_JAM:
return DECODE_STATUS_PAPER_JAM;
return DECODE_STATUS_GOOD;
case BROTHER_DATA_BLOCK_COVER_OPEN:
return DECODE_STATUS_COVER_OPEN;
case BROTHER_DATA_BLOCK_NO_DOCS:
response.adf_ready = SANE_FALSE;
return DECODE_STATUS_GOOD;
case BROTHER_DATA_BLOCK_SCAN_FINISHED:
response.adf_ready = SANE_TRUE;
return DECODE_STATUS_GOOD;
default:
return DECODE_STATUS_ERROR;
}
}
DecodeStatus BrotherEncoderFamily4::EncodeParameterBlockBlank (SANE_Byte *data, size_t data_len,
@ -1591,6 +1893,19 @@ DecodeStatus BrotherEncoderFamily4::DecodeScanDataHeader (const SANE_Byte *src_d
return DECODE_STATUS_CANCEL;
}
if ((header.block_type == BROTHER_DATA_BLOCK_PAPER_JAM)
|| (header.block_type == BROTHER_DATA_BLOCK_CLEARING_PAPER))
{
*src_data_consumed = 1;
return DECODE_STATUS_PAPER_JAM;
}
if (header.block_type == BROTHER_DATA_BLOCK_COVER_OPEN)
{
*src_data_consumed = 1;
return DECODE_STATUS_COVER_OPEN;
}
if (header.block_type == BROTHER_DATA_BLOCK_END_OF_FRAME_NO_MORE)
{
if (src_data_len < 10)

Wyświetl plik

@ -142,9 +142,15 @@ struct BrotherBasicParamResponse
// fill me
};
struct BrotherQueryResponse
{
int dummy;
// fill me
};
struct BrotherADFResponse
{
SANE_Byte resp_code;
SANE_Bool adf_ready;
};
@ -152,11 +158,6 @@ struct BrotherADFResponse
/*
* DecodeStatus
*
* DECODE_STATUS_GOOD - decode finished. Nothing more to do.
* DECODE_STATUS_TRUNCATED - starved of input. Need more src data.
* DECODE_STATUS_MORE - starved of output. Have more output available.
* DECODE_STATUS_ERROR - format of the data is incorrect.
*
*/
enum DecodeStatus
{
@ -169,7 +170,9 @@ enum DecodeStatus
DECODE_STATUS_ERROR,
DECODE_STATUS_MEMORY,
DECODE_STATUS_INVAL,
DECODE_STATUS_UNSUPPORTED
DECODE_STATUS_UNSUPPORTED,
DECODE_STATUS_PAPER_JAM,
DECODE_STATUS_COVER_OPEN,
};
struct ScanDataHeader
@ -218,7 +221,9 @@ public:
SANE_STATUS_IO_ERROR,
SANE_STATUS_NO_MEM,
SANE_STATUS_INVAL,
SANE_STATUS_UNSUPPORTED
SANE_STATUS_UNSUPPORTED,
SANE_STATUS_JAMMED,
SANE_STATUS_COVER_OPEN,
};
return status_lookup[dec_ret];
@ -227,6 +232,7 @@ public:
static const char* ScanModeToText (BrotherScanMode scan_mode);
// Buttons.
virtual DecodeStatus DecodeSessionResp (const SANE_Byte *data, size_t data_len,
BrotherSessionResponse &response) = 0;
@ -236,6 +242,12 @@ public:
virtual DecodeStatus DecodeButtonStateResp (const SANE_Byte *data, size_t data_len,
BrotherButtonStateResponse &response) = 0;
// Requests and responses.
virtual DecodeStatus EncodeQueryBlock (SANE_Byte *data, size_t data_len, size_t *length) = 0;
virtual DecodeStatus DecodeQueryBlockResp (const SANE_Byte *data, size_t data_len,
BrotherQueryResponse &response) = 0;
virtual DecodeStatus EncodeBasicParameterBlock (SANE_Byte *data, size_t data_len,
size_t *length) = 0;
@ -252,6 +264,7 @@ public:
virtual DecodeStatus EncodeParameterBlockBlank (SANE_Byte *data, size_t data_len,
size_t *length) = 0;
// Scan data decoding.
virtual DecodeStatus DecodeScanData (const SANE_Byte *src_data, size_t src_data_len,
size_t *src_data_consumed, SANE_Byte *dst_data,
size_t dest_data_len, size_t *dest_data_written) = 0;
@ -441,6 +454,11 @@ public:
colour_decoder.NewPage (scan_params);
}
DecodeStatus EncodeQueryBlock (SANE_Byte *data, size_t data_len, size_t *length) override;
DecodeStatus DecodeQueryBlockResp (const SANE_Byte *data, size_t data_len,
BrotherQueryResponse &response) override;
DecodeStatus DecodeSessionResp (const SANE_Byte *data, size_t data_len,
BrotherSessionResponse &response) override;
@ -450,23 +468,10 @@ public:
DecodeStatus DecodeBasicParameterBlockResp (const SANE_Byte *data, size_t data_len,
BrotherBasicParamResponse &response) override;
DecodeStatus EncodeADFBlock (SANE_Byte *data, size_t data_len, size_t *length) override
{
(void) data;
(void) data_len;
(void) length;
return DECODE_STATUS_UNSUPPORTED;
}
DecodeStatus EncodeADFBlock (SANE_Byte *data, size_t data_len, size_t *length) override;
DecodeStatus DecodeADFBlockResp (const SANE_Byte *data, size_t data_len,
BrotherADFResponse &response) override
{
(void) data;
(void) data_len;
(void) response;
return DECODE_STATUS_UNSUPPORTED;
}
BrotherADFResponse &response) override;
DecodeStatus EncodeParameterBlock (SANE_Byte *data, size_t data_len, size_t *length) override;
@ -517,6 +522,11 @@ public:
jfif_decoder.NewPage(scan_params);
}
DecodeStatus EncodeQueryBlock (SANE_Byte *data, size_t data_len, size_t *length) override;
DecodeStatus DecodeQueryBlockResp (const SANE_Byte *data, size_t data_len,
BrotherQueryResponse &response) override;
DecodeStatus DecodeSessionResp (const SANE_Byte *data, size_t data_len,
BrotherSessionResponse &response) override;
@ -526,24 +536,10 @@ public:
DecodeStatus DecodeBasicParameterBlockResp (const SANE_Byte *data, size_t data_len,
BrotherBasicParamResponse &response) override;
DecodeStatus EncodeADFBlock (SANE_Byte *data, size_t data_len, size_t *length) override
{
(void) data;
(void) data_len;
(void) length;
return DECODE_STATUS_UNSUPPORTED;
}
DecodeStatus EncodeADFBlock (SANE_Byte *data, size_t data_len, size_t *length) override;
DecodeStatus DecodeADFBlockResp (const SANE_Byte *data, size_t data_len,
BrotherADFResponse &response) override
{
(void) data;
(void) data_len;
(void) response;
return DECODE_STATUS_UNSUPPORTED;
}
BrotherADFResponse &response) override;
DecodeStatus EncodeParameterBlock (SANE_Byte *data, size_t data_len, size_t *length) override;
DecodeStatus EncodeParameterBlockBlank (SANE_Byte *data, size_t data_len, size_t *length)
@ -592,6 +588,11 @@ public:
gray_raw_decoder.NewPage (scan_params);
}
DecodeStatus EncodeQueryBlock (SANE_Byte *data, size_t data_len, size_t *length) override;
DecodeStatus DecodeQueryBlockResp (const SANE_Byte *data, size_t data_len,
BrotherQueryResponse &response) override;
DecodeStatus DecodeSessionResp (const SANE_Byte *data, size_t data_len,
BrotherSessionResponse &response) override;

Wyświetl plik

@ -107,20 +107,23 @@ static void test_family4_decode_adf_resp()
// SUCCESS status
const SANE_Byte *data = (const SANE_Byte *)"\xc2";
decode_resp = encoder.DecodeADFBlockResp (data, 1, adf_resp);
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
ASSERT_EQ(adf_resp.resp_code, (SANE_Byte)0xc2);
ASSERT_FALSE(adf_resp.adf_ready);
data = (const SANE_Byte *)"\x80";
decode_resp = encoder.DecodeADFBlockResp (data, 1, adf_resp);
ASSERT_EQ(decode_resp, DECODE_STATUS_GOOD);
ASSERT_TRUE(adf_resp.adf_ready);
// Wrong length.
decode_resp = encoder.DecodeADFBlockResp (data, 0, adf_resp);
ASSERT_EQ(decode_resp, DECODE_STATUS_ERROR);
ASSERT_EQ(adf_resp.resp_code, (SANE_Byte)0xc2);
decode_resp = encoder.DecodeADFBlockResp (data, 20, adf_resp);
ASSERT_EQ(decode_resp, DECODE_STATUS_ERROR);
ASSERT_EQ(adf_resp.resp_code, (SANE_Byte)0xc2);
}
/*