/** * Sends the three bytes comprising a read command to the 14CUX. * @param addr 16-bit address at which to read * @param len Number of bytes to read * @param lastByteOnly Send only the last byte of the read command; this will * work only if the coarse address was previously set. * @return True when the read command is successfully sent; false otherwise */ bool c14cux_sendReadCmd(c14cux_info* info, uint16_t addr, uint16_t len, bool lastByteOnly) { bool success = 0; uint8_t cmdByte = 0; // do the command-agnostic coarse address setup // (req'd for both reads and writes) if (lastByteOnly || c14cux_setReadCoarseAddr(info, addr, len)) { // if we actually did send the command bytes to set a new coarse // address, then remember what it was if (!lastByteOnly) { info->lastReadCoarseAddress = addr; } // build and send the byte for the Read command cmdByte = ((addr & 0x003F) | 0xC0); dprintf_info("14CUX(info): Sending Read command byte: 0x%02X... (no echo)\n", cmdByte); if (c14cux_writeSerialBytes(info, &cmdByte, 1) == 1) { // The 14CUX doesn't echo the Read command byte; // it simply starts sending the requested data. // Because of this, we can consider the command // successfully sent without checking for an echo // of the last byte. success = true; } else { dprintf_err("14CUX(error): Faled to write byte!\n"); } } return success; }
/** * Reads the specified number of bytes from memory at the specified address. * @param info State information for the active connection. * @param addr Address at which memory should be read. * @param len Number of bytes to read. * @param buffer Pointer to a buffer of at least len bytes * @return 1 when the operation was successful; 0 otherwise */ bool c14cux_readMem(c14cux_info* info, uint16_t addr, uint16_t len, uint8_t* buffer) { #if defined(WIN32) if (WaitForSingleObject(info->mutex, INFINITE) != WAIT_OBJECT_0) { return 0; } #else pthread_mutex_lock(&info->mutex); #endif uint16_t totalBytesRead = 0; uint16_t singleReqQuantity = 0; uint16_t singleReqBytesRead = 0; bool readSuccess = false; int16_t readCallBytesRead = 1; bool sendLastByteOnly = false; info->cancelRead = 0; if (c14cux_isConnected(info)) { // loop until we've read all the bytes, or we experienced a read error while ((totalBytesRead < len) && (readCallBytesRead > 0) && (info->cancelRead == 0)) { // read the maximum number of bytes as is reasonable singleReqQuantity = c14cux_getByteCountForNextRead(len, totalBytesRead); // if the next address to read is within the 64-byte window // created by the last coarse address that was set, then we // can just send the final byte of the read command sendLastByteOnly = ((singleReqQuantity == info->lastReadQuantity) && ((addr + totalBytesRead) < (info->lastReadCoarseAddress + 64)) && (info->lastReadCoarseAddress <= (addr + totalBytesRead))); dprintf_info("14CUX(info): Sending cmd to read %d bytes at 0x%04X...\n", singleReqQuantity, addr + totalBytesRead); // if sending the read command is successful... if (c14cux_sendReadCmd(info, addr + totalBytesRead, singleReqQuantity, sendLastByteOnly)) { dprintf_info("14CUX(info): Successfully sent read command.\n"); // reset the number of bytes read during this single read operation singleReqBytesRead = 0; // loop until we've read all the bytes for this single read operation, // or until we time out do { readCallBytesRead = c14cux_readSerialBytes(info, buffer + totalBytesRead + singleReqBytesRead, singleReqQuantity - singleReqBytesRead); singleReqBytesRead += readCallBytesRead; } while ((readCallBytesRead > 0) && (singleReqBytesRead < singleReqQuantity)); // if all the reads were successful, add the total bytes // read from this request to the overall total if (readCallBytesRead > 0) { dprintf_info("14CUX(info): Successfully read %d bytes.\n", singleReqBytesRead); totalBytesRead += singleReqBytesRead; // remember the number of bytes read on this pass, in case we // want to issue an abbreviated command next time (which will // send the same number of bytes) info->lastReadQuantity = singleReqQuantity; } } else { // if we were unable to even send the read command, // stop with failure dprintf_err("14CUX(error): Failed to send read command\n"); readCallBytesRead = -1; } } } // if we read as many bytes as were requested, indicate success if (totalBytesRead == len) { dprintf_info("14CUX(info): Successfully read all requested bytes.\n"); readSuccess = true; } else { info->lastReadCoarseAddress = 0; info->lastReadQuantity = 0; } #if defined(WIN32) ReleaseMutex(info->mutex); #else pthread_mutex_unlock(&info->mutex); #endif return readSuccess; }
/** * Sends command bytes to the 14CUX to set the coarse address for either a * read or write operation. If the command is ultimately a write operation, * the 14CUX will ignore the length. * @param addr Memory address at which the read or write will occur. * @param len Number of bytes to retrieve when the read operation is executed. * @return True when the command bytes were sent and echoed properly; false otherwise */ bool c14cux_setCoarseAddr(c14cux_info* info, uint16_t addr, uint16_t len) { uint8_t firstByte = 0x00; uint8_t secondByte = 0x00; uint8_t readByte = 0x00; bool retVal = false; dprintf_info("14CUX(info): Sending command to set coarse address...\n"); if (len == 0) { // if zero was passed for the length, we assume that this address // selection is being done for a write operation (which does not // require a quantity) firstByte = 0; } else if (len <= C14CUX_ReadCount0) { // if we're reading between 1 and 16 bytes, set the byte value // to (len - 1), which is interpreted by the 14CUX as (len) firstByte = len - 1; } else { // otherwise, we check to ensure that len is one of the allowed // preset values; if it isn't, return failure if (len == C14CUX_ReadCount1) { firstByte = C14CUX_ReadCount1Value; } else if (len == C14CUX_ReadCount2) { firstByte = C14CUX_ReadCount2Value; } else if (len == C14CUX_ReadCount3) { firstByte = C14CUX_ReadCount3Value; } else if (len == C14CUX_ReadCount4) { firstByte = C14CUX_ReadCount4Value; } else { dprintf_err("14CUX(error): Invalid length.\n"); return 0; } } // bit 7 is fixed low; bits 6:2 are the read quantity, // and bits 1:0 are the top two bits (15:14) of the address firstByte <<= 2; firstByte |= (addr >> 14); dprintf_info("14CUX(info): Sending byte: 0x%02X...\n", firstByte); if ((c14cux_writeSerialBytes(info, &firstByte, 1) == 1) && (c14cux_readSerialBytes(info, &readByte, 1) == 1) && (readByte == firstByte)) { // bits 13:6 of the address secondByte = ((addr >> 6) & 0x00ff); dprintf_info("14CUX(info): Sending byte: 0x%02X...\n", secondByte); if ((c14cux_writeSerialBytes(info, &secondByte, 1) == 1) && (c14cux_readSerialBytes(info, &readByte, 1) == 1) && (readByte == secondByte)) { retVal = true; } }