# Code reading exercise <style> .ui-infobar, #doc.markdown-body { max-width: 1000px; } </style> The code is taken from https://github.com/u-blox/ubxlib/blob/master/gnss/src/u_gnss_util.c # Code ```c= /* * Copyright 2020 u-blox * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* Only #includes of u_* and the C standard library are allowed here, * no platform stuff and no OS stuff. Anything required from * the platform/OS must be brought in through u_port* to maintain * portability. */ /** @file * @brief This header file defines the utility functions of the GNSS API. */ #ifdef U_CFG_OVERRIDE # include "u_cfg_override.h" // For a customer's configuration override #endif #include "stdlib.h" // malloc()/free() #include "stddef.h" // NULL, size_t etc. #include "stdint.h" // int32_t etc. #include "stdbool.h" #include "u_cfg_sw.h" #include "u_error_common.h" #include "u_port.h" #include "u_port_os.h" // Required by u_gnss_private.h #include "u_port_debug.h" #include "u_port_uart.h" #include "u_at_client.h" #include "u_hex_bin_convert.h" #include "u_gnss_module_type.h" #include "u_gnss_type.h" #include "u_gnss.h" #include "u_gnss_private.h" #include "u_gnss_util.h" /* ---------------------------------------------------------------- * COMPILE-TIME MACROS * -------------------------------------------------------------- */ #ifndef U_GNSS_UTIL_TRANSPARENT_RECEIVE_DELAY_MS /** The amount of time to wait between lines received * from the GNSS chip to ensure we don't lose any * of a transparent message. */ # define U_GNSS_UTIL_TRANSPARENT_RECEIVE_DELAY_MS 500 #endif /* ---------------------------------------------------------------- * TYPES * -------------------------------------------------------------- */ /* ---------------------------------------------------------------- * STATIC VARIABLES * -------------------------------------------------------------- */ /* ---------------------------------------------------------------- * STATIC FUNCTIONS * -------------------------------------------------------------- */ /* ---------------------------------------------------------------- * PUBLIC FUNCTIONS * -------------------------------------------------------------- */ // Transparently send a command to the GNSS chip. int32_t uGnssUtilUbxTransparentSendReceive(int32_t gnssHandle, const char *pCommand, size_t commandLengthBytes, char *pResponse, size_t maxResponseLengthBytes) { int32_t errorCodeOrResponseLength = (int32_t) U_ERROR_COMMON_INVALID_PARAMETER; uGnssPrivateInstance_t *pInstance; int64_t startTime; int32_t x = 0; int32_t bytesRead = 0; char *pBuffer; size_t bufferLengthBytes; uAtClientHandle_t atHandle; if (gUGnssPrivateMutex != NULL) { U_PORT_MUTEX_LOCK(gUGnssPrivateMutex); pInstance = pUGnssPrivateGetInstance(gnssHandle); if ((pInstance != NULL) && (((pCommand == NULL) && (commandLengthBytes == 0)) || (commandLengthBytes > 0)) && (((pResponse == NULL) && (maxResponseLengthBytes == 0)) || (maxResponseLengthBytes > 0))) { errorCodeOrResponseLength = (int32_t) U_GNSS_ERROR_TRANSPORT; U_PORT_MUTEX_LOCK(pInstance->transportMutex); switch (pInstance->transportType) { case U_GNSS_TRANSPORT_UBX_UART: //lint -fallthrough case U_GNSS_TRANSPORT_NMEA_UART: errorCodeOrResponseLength = uPortUartWrite(pInstance->transportHandle.uart, pCommand, commandLengthBytes); if (errorCodeOrResponseLength == commandLengthBytes) { if (pInstance->printUbxMessages) { uPortLog("U_GNSS: sent command"); uGnssPrivatePrintBuffer(pCommand, commandLengthBytes); uPortLog(".\n"); } errorCodeOrResponseLength = (int32_t) U_ERROR_COMMON_SUCCESS; if (pResponse != NULL) { errorCodeOrResponseLength = (int32_t) U_GNSS_ERROR_TRANSPORT; startTime = uPortGetTickTimeMs(); // Wait for something to start coming back while (((x = uPortUartGetReceiveSize(pInstance->transportHandle.uart)) <= 0) && (uPortGetTickTimeMs() < startTime + pInstance->timeoutMs)) { // Relax a little uPortTaskBlock(U_GNSS_UTIL_TRANSPARENT_RECEIVE_DELAY_MS); } if (x > 0) { // Got something; continue receiving until nothing arrives for // U_GNSS_UTIL_TRANSPARENT_RECEIVE_DELAY_MS while (((x = uPortUartGetReceiveSize(pInstance->transportHandle.uart)) > 0) && (uPortGetTickTimeMs() < startTime + pInstance->timeoutMs)) { if (x > 0) { // Read the response into pResponse x = uPortUartRead(pInstance->transportHandle.uart, pResponse + bytesRead, maxResponseLengthBytes - bytesRead); if (x > 0) { bytesRead += x; } } else { // Relax a little uPortTaskBlock(U_GNSS_UTIL_TRANSPARENT_RECEIVE_DELAY_MS); } } if (bytesRead > 0) { errorCodeOrResponseLength = bytesRead; } } if (pInstance->printUbxMessages && (errorCodeOrResponseLength >= 0)) { uPortLog("U_GNSS: received response"); uGnssPrivatePrintBuffer(pResponse, errorCodeOrResponseLength); uPortLog(".\n"); } } } break; case U_GNSS_TRANSPORT_UBX_AT: char *pTmp = NULL; errorCodeOrResponseLength = (int32_t) U_ERROR_COMMON_NO_MEMORY; atHandle = pInstance->transportHandle.pAt; // Need a buffer to hex encode the message into // and receive the hex-encoded response into bufferLengthBytes = (commandLengthBytes << 1) + 1; // +1 for terminator if (bufferLengthBytes < (maxResponseLengthBytes * 2) + 1) { bufferLengthBytes = (maxResponseLengthBytes * 2) + 1; } pBuffer = (char *) malloc(bufferLengthBytes); if (pBuffer != NULL) { errorCodeOrResponseLength = (int32_t) U_GNSS_ERROR_TRANSPORT; if (pCommand != NULL) { x = (int32_t) uBinToHex(pCommand, commandLengthBytes, pBuffer); } // Add terminator *(pBuffer + x) = 0; uAtClientLock(atHandle); uAtClientTimeoutSet(atHandle, pInstance->timeoutMs); // Send the command uAtClientCommandStart(atHandle, "AT+UGUBX="); uAtClientWriteString(atHandle, pBuffer, true); uAtClientCommandStop(atHandle); // Read the hex-coded response back into pTmp, // which may be NULL to throw the response away uAtClientResponseStart(atHandle, "+UGUBX:"); if (pResponse != NULL) { pTmp = pBuffer; } bytesRead = uAtClientReadString(atHandle, pTmp, bufferLengthBytes, false); uAtClientResponseStop(atHandle); if ((uAtClientUnlock(atHandle) == 0) && (bytesRead >= 0)) { if (bytesRead > (int32_t) maxResponseLengthBytes) { bytesRead = (int32_t) maxResponseLengthBytes; } errorCodeOrResponseLength = 0; if (pTmp != NULL) { // Decode the hex into pResponse errorCodeOrResponseLength = (int32_t) uHexToBin(pTmp, bytesRead, pResponse); if (pInstance->printUbxMessages) { uPortLog("U_GNSS: received response"); uGnssPrivatePrintBuffer(pResponse, errorCodeOrResponseLength); uPortLog(".\n"); } } } // Free memory free(pBuffer); } break; default: break; } U_PORT_MUTEX_UNLOCK(pInstance->transportMutex); } U_PORT_MUTEX_UNLOCK(gUGnssPrivateMutex); } return errorCodeOrResponseLength; } // End of file ```