Update repo
This commit is contained in:
1 parent
ef5f9a563e
commit
dfe8ec02bd
12 files changed
+723
-341
No files matched your search
@@ -0,0 +1,504 @@
|
||||
#include "at24cm02.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include "driverlib.h"
|
||||
#include "device.h"
|
||||
#include "semphr.h"
|
||||
#include "task.h"
|
||||
|
||||
#define EEPROM_I2C_BASE I2CA_BASE
|
||||
#define EEPROM_I2C_BIT_RATE 400000UL
|
||||
#define EEPROM_SDA_PIN 91U
|
||||
#define EEPROM_SCL_PIN 92U
|
||||
#define EEPROM_STATUS_ERROR_MASK (I2C_STS_NO_ACK | I2C_STS_ARB_LOST)
|
||||
#define EEPROM_CLEARABLE_STATUS_MASK (I2C_STS_NO_ACK | I2C_STS_ARB_LOST | \
|
||||
I2C_STS_REG_ACCESS_RDY | \
|
||||
I2C_STS_STOP_CONDITION)
|
||||
// The AT24CM02 tWR maximum is 10 ms. Use 11 RTOS ticks at a 1-kHz tick rate
|
||||
// so the actual delay cannot be shortened below 10 ms by tick quantization.
|
||||
#define EEPROM_WRITE_CYCLE_MS 11U
|
||||
|
||||
static SemaphoreHandle_t eepromMutex = NULL;
|
||||
static bool eepromInitialized = false;
|
||||
|
||||
static bool EEPROM_hasTimedOut(TickType_t start, TickType_t timeoutTicks)
|
||||
{
|
||||
if(timeoutTicks == portMAX_DELAY)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return ((TickType_t)(xTaskGetTickCount() - start) >= timeoutTicks);
|
||||
}
|
||||
|
||||
static void EEPROM_yield(void)
|
||||
{
|
||||
if(xTaskGetSchedulerState() == taskSCHEDULER_RUNNING)
|
||||
{
|
||||
taskYIELD();
|
||||
}
|
||||
}
|
||||
|
||||
static EEPROM_Status EEPROM_statusToError(uint16_t i2cStatus)
|
||||
{
|
||||
if((i2cStatus & I2C_STS_ARB_LOST) != 0U)
|
||||
{
|
||||
return EEPROM_STATUS_ARBITRATION_LOST;
|
||||
}
|
||||
|
||||
if((i2cStatus & I2C_STS_NO_ACK) != 0U)
|
||||
{
|
||||
return EEPROM_STATUS_NO_ACK;
|
||||
}
|
||||
|
||||
return EEPROM_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void EEPROM_abortTransaction(void)
|
||||
{
|
||||
I2C_sendStopCondition(EEPROM_I2C_BASE);
|
||||
I2C_clearStatus(EEPROM_I2C_BASE, EEPROM_CLEARABLE_STATUS_MASK);
|
||||
}
|
||||
|
||||
static EEPROM_Status EEPROM_waitForStatus(uint16_t requestedStatus,
|
||||
TickType_t start,
|
||||
TickType_t timeoutTicks)
|
||||
{
|
||||
uint16_t status;
|
||||
EEPROM_Status error;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
status = I2C_getStatus(EEPROM_I2C_BASE);
|
||||
error = EEPROM_statusToError(status);
|
||||
if(error != EEPROM_STATUS_SUCCESS)
|
||||
{
|
||||
return error;
|
||||
}
|
||||
|
||||
if((status & requestedStatus) != 0U)
|
||||
{
|
||||
return EEPROM_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if(EEPROM_hasTimedOut(start, timeoutTicks))
|
||||
{
|
||||
return EEPROM_STATUS_TIMEOUT;
|
||||
}
|
||||
|
||||
EEPROM_yield();
|
||||
}
|
||||
}
|
||||
|
||||
static EEPROM_Status EEPROM_waitForBusIdle(TickType_t start,
|
||||
TickType_t timeoutTicks)
|
||||
{
|
||||
while(I2C_getStopConditionStatus(EEPROM_I2C_BASE) ||
|
||||
I2C_isBusBusy(EEPROM_I2C_BASE))
|
||||
{
|
||||
if(EEPROM_hasTimedOut(start, timeoutTicks))
|
||||
{
|
||||
return EEPROM_STATUS_BUS_BUSY;
|
||||
}
|
||||
|
||||
EEPROM_yield();
|
||||
}
|
||||
|
||||
return EEPROM_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static uint16_t EEPROM_targetAddress(uint16_t deviceAddress,
|
||||
uint32_t memoryAddress)
|
||||
{
|
||||
return (uint16_t)(deviceAddress | ((memoryAddress >> 16U) & 0x3U));
|
||||
}
|
||||
|
||||
static bool EEPROM_deviceAddressIsValid(uint16_t deviceAddress)
|
||||
{
|
||||
// Bits A17:A16 are supplied by the memory address for this device.
|
||||
return ((deviceAddress <= 0x7CU) && ((deviceAddress & 0x3U) == 0U));
|
||||
}
|
||||
|
||||
static EEPROM_Status EEPROM_writeChunk(const uint16_t *data,
|
||||
uint32_t address,
|
||||
uint16_t deviceAddress,
|
||||
uint16_t byteCount,
|
||||
TickType_t timeoutTicks)
|
||||
{
|
||||
uint16_t i;
|
||||
TickType_t start = xTaskGetTickCount();
|
||||
EEPROM_Status status;
|
||||
|
||||
status = EEPROM_waitForBusIdle(start, timeoutTicks);
|
||||
if(status != EEPROM_STATUS_SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
I2C_clearStatus(EEPROM_I2C_BASE, EEPROM_CLEARABLE_STATUS_MASK);
|
||||
I2C_setTargetAddress(EEPROM_I2C_BASE,
|
||||
EEPROM_targetAddress(deviceAddress, address));
|
||||
I2C_setDataCount(EEPROM_I2C_BASE, (uint16_t)(byteCount + 2U));
|
||||
I2C_setConfig(EEPROM_I2C_BASE, I2C_CONTROLLER_SEND_MODE);
|
||||
I2C_sendStartCondition(EEPROM_I2C_BASE);
|
||||
I2C_sendStopCondition(EEPROM_I2C_BASE);
|
||||
|
||||
status = EEPROM_waitForStatus(I2C_STS_TX_DATA_RDY, start, timeoutTicks);
|
||||
if(status == EEPROM_STATUS_SUCCESS)
|
||||
{
|
||||
I2C_putData(EEPROM_I2C_BASE, (uint16_t)((address >> 8U) & 0xFFU));
|
||||
}
|
||||
|
||||
if(status == EEPROM_STATUS_SUCCESS)
|
||||
{
|
||||
status = EEPROM_waitForStatus(I2C_STS_TX_DATA_RDY, start,
|
||||
timeoutTicks);
|
||||
}
|
||||
if(status == EEPROM_STATUS_SUCCESS)
|
||||
{
|
||||
I2C_putData(EEPROM_I2C_BASE, (uint16_t)(address & 0xFFU));
|
||||
}
|
||||
|
||||
for(i = 0U; (i < byteCount) && (status == EEPROM_STATUS_SUCCESS); i++)
|
||||
{
|
||||
status = EEPROM_waitForStatus(I2C_STS_TX_DATA_RDY, start,
|
||||
timeoutTicks);
|
||||
if(status == EEPROM_STATUS_SUCCESS)
|
||||
{
|
||||
I2C_putData(EEPROM_I2C_BASE, data[i] & 0xFFU);
|
||||
}
|
||||
}
|
||||
|
||||
if(status == EEPROM_STATUS_SUCCESS)
|
||||
{
|
||||
status = EEPROM_waitForStatus(I2C_STS_STOP_CONDITION, start,
|
||||
timeoutTicks);
|
||||
}
|
||||
|
||||
if(status != EEPROM_STATUS_SUCCESS)
|
||||
{
|
||||
EEPROM_abortTransaction();
|
||||
return status;
|
||||
}
|
||||
|
||||
I2C_clearStatus(EEPROM_I2C_BASE, I2C_STS_STOP_CONDITION);
|
||||
return EEPROM_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static EEPROM_Status EEPROM_readChunk(uint16_t *data, uint32_t address,
|
||||
uint16_t deviceAddress,
|
||||
uint16_t byteCount,
|
||||
TickType_t timeoutTicks)
|
||||
{
|
||||
uint16_t i;
|
||||
TickType_t start = xTaskGetTickCount();
|
||||
EEPROM_Status status;
|
||||
|
||||
status = EEPROM_waitForBusIdle(start, timeoutTicks);
|
||||
if(status != EEPROM_STATUS_SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
I2C_clearStatus(EEPROM_I2C_BASE, EEPROM_CLEARABLE_STATUS_MASK);
|
||||
I2C_setTargetAddress(EEPROM_I2C_BASE,
|
||||
EEPROM_targetAddress(deviceAddress, address));
|
||||
I2C_setDataCount(EEPROM_I2C_BASE, 2U);
|
||||
I2C_setConfig(EEPROM_I2C_BASE, I2C_CONTROLLER_SEND_MODE);
|
||||
I2C_sendStartCondition(EEPROM_I2C_BASE);
|
||||
|
||||
status = EEPROM_waitForStatus(I2C_STS_TX_DATA_RDY, start, timeoutTicks);
|
||||
if(status == EEPROM_STATUS_SUCCESS)
|
||||
{
|
||||
I2C_putData(EEPROM_I2C_BASE, (uint16_t)((address >> 8U) & 0xFFU));
|
||||
}
|
||||
|
||||
if(status == EEPROM_STATUS_SUCCESS)
|
||||
{
|
||||
status = EEPROM_waitForStatus(I2C_STS_TX_DATA_RDY, start,
|
||||
timeoutTicks);
|
||||
}
|
||||
if(status == EEPROM_STATUS_SUCCESS)
|
||||
{
|
||||
I2C_putData(EEPROM_I2C_BASE, (uint16_t)(address & 0xFFU));
|
||||
}
|
||||
|
||||
if(status == EEPROM_STATUS_SUCCESS)
|
||||
{
|
||||
status = EEPROM_waitForStatus(I2C_STS_REG_ACCESS_RDY, start,
|
||||
timeoutTicks);
|
||||
}
|
||||
|
||||
if(status == EEPROM_STATUS_SUCCESS)
|
||||
{
|
||||
I2C_clearStatus(EEPROM_I2C_BASE, I2C_STS_REG_ACCESS_RDY);
|
||||
I2C_setDataCount(EEPROM_I2C_BASE, byteCount);
|
||||
I2C_setConfig(EEPROM_I2C_BASE, I2C_CONTROLLER_RECEIVE_MODE);
|
||||
I2C_sendStartCondition(EEPROM_I2C_BASE);
|
||||
I2C_sendStopCondition(EEPROM_I2C_BASE);
|
||||
}
|
||||
|
||||
for(i = 0U; (i < byteCount) && (status == EEPROM_STATUS_SUCCESS); i++)
|
||||
{
|
||||
status = EEPROM_waitForStatus(I2C_STS_RX_DATA_RDY, start,
|
||||
timeoutTicks);
|
||||
if(status == EEPROM_STATUS_SUCCESS)
|
||||
{
|
||||
data[i] = I2C_getData(EEPROM_I2C_BASE) & 0xFFU;
|
||||
}
|
||||
}
|
||||
|
||||
if(status == EEPROM_STATUS_SUCCESS)
|
||||
{
|
||||
status = EEPROM_waitForStatus(I2C_STS_STOP_CONDITION, start,
|
||||
timeoutTicks);
|
||||
}
|
||||
|
||||
if(status != EEPROM_STATUS_SUCCESS)
|
||||
{
|
||||
EEPROM_abortTransaction();
|
||||
return status;
|
||||
}
|
||||
|
||||
I2C_clearStatus(EEPROM_I2C_BASE, I2C_STS_STOP_CONDITION);
|
||||
return EEPROM_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
EEPROM_Status EEPROM_init(void)
|
||||
{
|
||||
if(eepromMutex == NULL)
|
||||
{
|
||||
eepromMutex = xSemaphoreCreateMutex();
|
||||
if(eepromMutex == NULL)
|
||||
{
|
||||
return EEPROM_STATUS_NO_MEMORY;
|
||||
}
|
||||
}
|
||||
|
||||
GPIO_setMasterCore(EEPROM_SDA_PIN, GPIO_CORE_CPU1);
|
||||
GPIO_setPinConfig(GPIO_91_SDAA);
|
||||
GPIO_setDirectionMode(EEPROM_SDA_PIN, GPIO_DIR_MODE_IN);
|
||||
GPIO_setPadConfig(EEPROM_SDA_PIN, GPIO_PIN_TYPE_PULLUP);
|
||||
GPIO_setQualificationMode(EEPROM_SDA_PIN, GPIO_QUAL_ASYNC);
|
||||
|
||||
GPIO_setMasterCore(EEPROM_SCL_PIN, GPIO_CORE_CPU1);
|
||||
GPIO_setPinConfig(GPIO_92_SCLA);
|
||||
GPIO_setDirectionMode(EEPROM_SCL_PIN, GPIO_DIR_MODE_IN);
|
||||
GPIO_setPadConfig(EEPROM_SCL_PIN, GPIO_PIN_TYPE_PULLUP);
|
||||
GPIO_setQualificationMode(EEPROM_SCL_PIN, GPIO_QUAL_ASYNC);
|
||||
|
||||
I2C_disableModule(EEPROM_I2C_BASE);
|
||||
I2C_initController(EEPROM_I2C_BASE, DEVICE_SYSCLK_FREQ,
|
||||
EEPROM_I2C_BIT_RATE, I2C_DUTYCYCLE_33);
|
||||
I2C_setBitCount(EEPROM_I2C_BASE, I2C_BITCOUNT_8);
|
||||
I2C_setAddressMode(EEPROM_I2C_BASE, I2C_ADDR_MODE_7BITS);
|
||||
I2C_setEmulationMode(EEPROM_I2C_BASE, I2C_EMULATION_FREE_RUN);
|
||||
I2C_disableFIFO(EEPROM_I2C_BASE);
|
||||
I2C_disableInterrupt(EEPROM_I2C_BASE, I2C_INT_ARB_LOST |
|
||||
I2C_INT_NO_ACK | I2C_INT_REG_ACCESS_RDY |
|
||||
I2C_INT_RX_DATA_RDY | I2C_INT_TX_DATA_RDY |
|
||||
I2C_INT_STOP_CONDITION | I2C_INT_ADDR_TARGET |
|
||||
I2C_INT_RXFF | I2C_INT_TXFF);
|
||||
I2C_clearStatus(EEPROM_I2C_BASE, EEPROM_CLEARABLE_STATUS_MASK);
|
||||
I2C_enableModule(EEPROM_I2C_BASE);
|
||||
|
||||
eepromInitialized = true;
|
||||
return EEPROM_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
EEPROM_Status EEPROM_read(uint16_t *data, uint32_t address,
|
||||
uint16_t deviceAddress, uint32_t byteCount,
|
||||
TickType_t timeoutTicks)
|
||||
{
|
||||
EEPROM_Status status;
|
||||
uint32_t chunkSize;
|
||||
|
||||
if(!eepromInitialized)
|
||||
{
|
||||
return EEPROM_STATUS_NOT_INITIALIZED;
|
||||
}
|
||||
if((data == NULL) || (byteCount == 0UL) ||
|
||||
!EEPROM_deviceAddressIsValid(deviceAddress))
|
||||
{
|
||||
return EEPROM_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if((address >= AT24CM02_CAPACITY_BYTES) ||
|
||||
(byteCount > (AT24CM02_CAPACITY_BYTES - address)))
|
||||
{
|
||||
return EEPROM_STATUS_OUT_OF_RANGE;
|
||||
}
|
||||
if(xSemaphoreTake(eepromMutex, timeoutTicks) != pdTRUE)
|
||||
{
|
||||
return EEPROM_STATUS_MUTEX_TIMEOUT;
|
||||
}
|
||||
|
||||
status = EEPROM_STATUS_SUCCESS;
|
||||
while((byteCount != 0UL) && (status == EEPROM_STATUS_SUCCESS))
|
||||
{
|
||||
// I2CCNT is 16-bit; keep chunks moderate and avoid a block-address
|
||||
// change in the middle of an I2C transaction.
|
||||
chunkSize = 0x10000UL - (address & 0xFFFFUL);
|
||||
if(chunkSize > byteCount)
|
||||
{
|
||||
chunkSize = byteCount;
|
||||
}
|
||||
if(chunkSize > 0xFFFFUL)
|
||||
{
|
||||
chunkSize = 0xFFFFUL;
|
||||
}
|
||||
|
||||
status = EEPROM_readChunk(data, address, deviceAddress,
|
||||
(uint16_t)chunkSize, timeoutTicks);
|
||||
address += chunkSize;
|
||||
data += chunkSize;
|
||||
byteCount -= chunkSize;
|
||||
}
|
||||
|
||||
xSemaphoreGive(eepromMutex);
|
||||
return status;
|
||||
}
|
||||
|
||||
EEPROM_Status EEPROM_write(const uint16_t *data, uint32_t address,
|
||||
uint16_t deviceAddress, uint32_t byteCount,
|
||||
TickType_t timeoutTicks)
|
||||
{
|
||||
EEPROM_Status status;
|
||||
uint32_t chunkSize;
|
||||
|
||||
if(!eepromInitialized)
|
||||
{
|
||||
return EEPROM_STATUS_NOT_INITIALIZED;
|
||||
}
|
||||
if((data == NULL) || (byteCount == 0UL) ||
|
||||
!EEPROM_deviceAddressIsValid(deviceAddress))
|
||||
{
|
||||
return EEPROM_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if((address >= AT24CM02_CAPACITY_BYTES) ||
|
||||
(byteCount > (AT24CM02_CAPACITY_BYTES - address)))
|
||||
{
|
||||
return EEPROM_STATUS_OUT_OF_RANGE;
|
||||
}
|
||||
if(xSemaphoreTake(eepromMutex, timeoutTicks) != pdTRUE)
|
||||
{
|
||||
return EEPROM_STATUS_MUTEX_TIMEOUT;
|
||||
}
|
||||
|
||||
status = EEPROM_STATUS_SUCCESS;
|
||||
while((byteCount != 0UL) && (status == EEPROM_STATUS_SUCCESS))
|
||||
{
|
||||
chunkSize = AT24CM02_PAGE_SIZE_BYTES -
|
||||
(address & (AT24CM02_PAGE_SIZE_BYTES - 1U));
|
||||
if(chunkSize > byteCount)
|
||||
{
|
||||
chunkSize = byteCount;
|
||||
}
|
||||
|
||||
status = EEPROM_writeChunk(data, address, deviceAddress,
|
||||
(uint16_t)chunkSize, timeoutTicks);
|
||||
if(status == EEPROM_STATUS_SUCCESS)
|
||||
{
|
||||
if(xTaskGetSchedulerState() == taskSCHEDULER_RUNNING)
|
||||
{
|
||||
vTaskDelay(pdMS_TO_TICKS(EEPROM_WRITE_CYCLE_MS));
|
||||
}
|
||||
else
|
||||
{
|
||||
DEVICE_DELAY_US((uint32_t)EEPROM_WRITE_CYCLE_MS * 1000UL);
|
||||
}
|
||||
}
|
||||
|
||||
address += chunkSize;
|
||||
data += chunkSize;
|
||||
byteCount -= chunkSize;
|
||||
}
|
||||
|
||||
xSemaphoreGive(eepromMutex);
|
||||
return status;
|
||||
}
|
||||
|
||||
EEPROM_Status EEPROM_pageNumberToAddress(uint16_t pageNumber,
|
||||
uint32_t *pageAddress)
|
||||
{
|
||||
if(pageAddress == NULL)
|
||||
{
|
||||
return EEPROM_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
if((pageNumber == 0U) || (pageNumber > AT24CM02_PAGE_COUNT))
|
||||
{
|
||||
return EEPROM_STATUS_OUT_OF_RANGE;
|
||||
}
|
||||
|
||||
*pageAddress = ((uint32_t)pageNumber - 1UL) *
|
||||
AT24CM02_PAGE_SIZE_BYTES;
|
||||
return EEPROM_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
EEPROM_Status EEPROM_readPage(uint16_t *data, uint16_t deviceAddress,
|
||||
uint16_t pageNumber, uint16_t byteCount,
|
||||
TickType_t timeoutTicks)
|
||||
{
|
||||
uint32_t address;
|
||||
EEPROM_Status status;
|
||||
|
||||
if((byteCount == 0U) || (byteCount > AT24CM02_PAGE_SIZE_BYTES))
|
||||
{
|
||||
return EEPROM_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
status = EEPROM_pageNumberToAddress(pageNumber, &address);
|
||||
if(status != EEPROM_STATUS_SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
return EEPROM_read(data, address, deviceAddress, byteCount, timeoutTicks);
|
||||
}
|
||||
|
||||
EEPROM_Status EEPROM_writePage(const uint16_t *data, uint16_t deviceAddress,
|
||||
uint16_t pageNumber, uint16_t byteCount,
|
||||
TickType_t timeoutTicks)
|
||||
{
|
||||
uint32_t address;
|
||||
EEPROM_Status status;
|
||||
|
||||
if((byteCount == 0U) || (byteCount > AT24CM02_PAGE_SIZE_BYTES))
|
||||
{
|
||||
return EEPROM_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
status = EEPROM_pageNumberToAddress(pageNumber, &address);
|
||||
if(status != EEPROM_STATUS_SUCCESS)
|
||||
{
|
||||
return status;
|
||||
}
|
||||
|
||||
return EEPROM_write(data, address, deviceAddress, byteCount, timeoutTicks);
|
||||
}
|
||||
|
||||
const char *EEPROM_statusString(EEPROM_Status status)
|
||||
{
|
||||
static const char *const descriptions[] =
|
||||
{
|
||||
"success",
|
||||
"not initialized",
|
||||
"invalid argument",
|
||||
"address out of range",
|
||||
"FreeRTOS heap exhausted",
|
||||
"mutex timeout",
|
||||
"I2C bus busy",
|
||||
"I2C timeout",
|
||||
"I2C no acknowledgement",
|
||||
"I2C arbitration lost"
|
||||
};
|
||||
|
||||
if((uint16_t)status >=
|
||||
(uint16_t)(sizeof(descriptions) / sizeof(descriptions[0])))
|
||||
{
|
||||
return "unknown status";
|
||||
}
|
||||
|
||||
return descriptions[(uint16_t)status];
|
||||
}
|
||||
@@ -0,0 +1,327 @@
|
||||
/*****************************************************************************/
|
||||
//
|
||||
// Copyright 2001, 2002 Georges Menie (www.menie.org)
|
||||
// stdarg version contributed by Christian Ettinger
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
/*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
// putchar is the only external dependency for this file,
|
||||
// if you have a working putchar, leave it commented out.
|
||||
// If not, uncomment the define below and
|
||||
// replace outbyte(c) by your own function call.
|
||||
/*****************************************************************************/
|
||||
|
||||
#define TEST_PRINTF
|
||||
#include "sci.h"
|
||||
#define putchar(c) UartPutChar(c)
|
||||
extern void UartPutChar(uint16_t charToWrite);
|
||||
#include <stdarg.h>
|
||||
|
||||
static int tiny_print(char **out, const char *format, va_list args, unsigned int buflen);
|
||||
|
||||
static void printchar(char **str, int c, char *buflimit)
|
||||
{
|
||||
//extern int putchar(int c);
|
||||
|
||||
if (str)
|
||||
{
|
||||
if( buflimit == ( char * ) 0 )
|
||||
{
|
||||
// Limit of buffer not known, write charater to buffer
|
||||
**str = (char)c;
|
||||
++(*str);
|
||||
}
|
||||
else if( ( ( unsigned long ) *str ) < ( ( unsigned long ) buflimit ) )
|
||||
{
|
||||
// With known limit of buffer, write character
|
||||
**str = (char)c;
|
||||
++(*str);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)putchar(c);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define PAD_RIGHT 1
|
||||
#define PAD_ZERO 2
|
||||
|
||||
static int prints(char **out, const char *string, int width, int pad, char *buflimit)
|
||||
{
|
||||
register int pc = 0, padchar = ' ';
|
||||
|
||||
if (width > 0)
|
||||
{
|
||||
register int len = 0;
|
||||
register const char *ptr;
|
||||
for (ptr = string; *ptr; ++ptr) ++len;
|
||||
if (len >= width) width = 0;
|
||||
else width -= len;
|
||||
if (pad & PAD_ZERO) padchar = '0';
|
||||
}
|
||||
|
||||
if (!(pad & PAD_RIGHT))
|
||||
{
|
||||
for ( ; width > 0; --width)
|
||||
{
|
||||
printchar (out, padchar, buflimit);
|
||||
++pc;
|
||||
}
|
||||
}
|
||||
|
||||
for ( ; *string ; ++string)
|
||||
{
|
||||
printchar (out, *string, buflimit);
|
||||
++pc;
|
||||
}
|
||||
|
||||
for ( ; width > 0; --width)
|
||||
{
|
||||
printchar (out, padchar, buflimit);
|
||||
++pc;
|
||||
}
|
||||
|
||||
return pc;
|
||||
|
||||
}
|
||||
|
||||
// The following should be enough for 32 bit int
|
||||
#define PRINT_BUF_LEN 12
|
||||
|
||||
static int printi(char **out, int i, int b, int sg, int width, int pad, int letbase, char *buflimit)
|
||||
{
|
||||
char print_buf[PRINT_BUF_LEN];
|
||||
register char *s;
|
||||
register int t, neg = 0, pc = 0;
|
||||
register unsigned int u = (unsigned int)i;
|
||||
|
||||
if (i == 0) {
|
||||
print_buf[0] = '0';
|
||||
print_buf[1] = '\0';
|
||||
return prints (out, print_buf, width, pad, buflimit);
|
||||
}
|
||||
|
||||
if (sg && b == 10 && i < 0) {
|
||||
neg = 1;
|
||||
u = (unsigned int)-i;
|
||||
}
|
||||
|
||||
s = print_buf + PRINT_BUF_LEN-1;
|
||||
*s = '\0';
|
||||
|
||||
while (u) {
|
||||
t = (unsigned int)u % b;
|
||||
if( t >= 10 )
|
||||
t += letbase - '0' - 10;
|
||||
*--s = (char)(t + '0');
|
||||
u /= b;
|
||||
}
|
||||
|
||||
if (neg) {
|
||||
if( width && (pad & PAD_ZERO) ) {
|
||||
printchar (out, '-', buflimit);
|
||||
++pc;
|
||||
--width;
|
||||
}
|
||||
else {
|
||||
*--s = '-';
|
||||
}
|
||||
}
|
||||
|
||||
return pc + prints (out, s, width, pad, buflimit);
|
||||
}
|
||||
|
||||
static int tiny_print(char **out, const char *format, va_list args, unsigned int buflen)
|
||||
{
|
||||
register int width, pad;
|
||||
register int pc = 0;
|
||||
char scr[2], *buflimit;
|
||||
|
||||
if( buflen == 0 )
|
||||
{
|
||||
buflimit = (char *) 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Calculate the last valid buffer space, leaving space for the NULL
|
||||
terminator. */
|
||||
buflimit = (*out) + (buflen - 1);
|
||||
}
|
||||
|
||||
for (; *format != 0; ++format) {
|
||||
if (*format == '%') {
|
||||
++format;
|
||||
width = pad = 0;
|
||||
if (*format == '\0') break;
|
||||
if (*format == '%') goto out;
|
||||
if (*format == '-') {
|
||||
++format;
|
||||
pad = PAD_RIGHT;
|
||||
}
|
||||
while (*format == '0') {
|
||||
++format;
|
||||
pad |= PAD_ZERO;
|
||||
}
|
||||
for ( ; *format >= '0' && *format <= '9'; ++format) {
|
||||
width *= 10;
|
||||
width += *format - '0';
|
||||
}
|
||||
if( *format == 's' ) {
|
||||
register char *s = (char *)va_arg( args, int32_t );
|
||||
pc += prints (out, s?s:"(null)", width, pad, buflimit);
|
||||
continue;
|
||||
}
|
||||
if( *format == 'd' ) {
|
||||
pc += printi (out, va_arg( args, int ), 10, 1, width, pad, 'a', buflimit);
|
||||
continue;
|
||||
}
|
||||
if( *format == 'x' ) {
|
||||
pc += printi (out, va_arg( args, int ), 16, 0, width, pad, 'a', buflimit);
|
||||
continue;
|
||||
}
|
||||
if( *format == 'X' ) {
|
||||
pc += printi (out, va_arg( args, int ), 16, 0, width, pad, 'A', buflimit);
|
||||
continue;
|
||||
}
|
||||
if( *format == 'u' ) {
|
||||
pc += printi (out, va_arg( args, int ), 10, 0, width, pad, 'a', buflimit);
|
||||
continue;
|
||||
}
|
||||
if( *format == 'c' ) {
|
||||
/* char are converted to int then pushed on the stack */
|
||||
scr[0] = (char)va_arg( args, int );
|
||||
scr[1] = '\0';
|
||||
pc += prints (out, scr, width, pad, buflimit);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
out:
|
||||
printchar (out, *format, buflimit);
|
||||
++pc;
|
||||
}
|
||||
}
|
||||
if (out) **out = '\0';
|
||||
va_end( args );
|
||||
return pc;
|
||||
}
|
||||
|
||||
int printf(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
return tiny_print(0, format, args, 0);
|
||||
}
|
||||
|
||||
int sprintf(char *out, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
return tiny_print(&out, format, args, 0);
|
||||
}
|
||||
|
||||
|
||||
int snprintf( char *buf, unsigned int count, const char *format, ... )
|
||||
{
|
||||
va_list args;
|
||||
(void) count;
|
||||
va_start(args, format);
|
||||
return tiny_print(&buf, format, args, count);
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST_PRINTF
|
||||
|
||||
int checkPrintf(void)
|
||||
{
|
||||
char *ptr = "Hello world!";
|
||||
char *np = 0;
|
||||
int i = 5;
|
||||
unsigned int bs = sizeof(int)*8;
|
||||
int mi;
|
||||
char buf[80];
|
||||
|
||||
mi = (1 << (bs-1)) + 1;
|
||||
printf("Ptr string = %s \r\n", ptr);
|
||||
printf("printf test\r\n");
|
||||
printf("%s is null pointer\r\n", np);
|
||||
printf("%d = 5\r\n", i);
|
||||
printf("%d = - max int\r\n", mi);
|
||||
printf("char %c = 'a'\r\n", 'a');
|
||||
printf("hex %x = ff\r\n", 0xff);
|
||||
printf("hex %02x = 00\r\n", 0);
|
||||
printf("signed %d = unsigned %u = hex %x\r\n", -3, -3, -3);
|
||||
printf("%d %s(s)%", 0, "message");
|
||||
printf("\r\n");
|
||||
printf("%d %s(s) with %%\r\n", 0, "message");
|
||||
sprintf(buf, "justif: \"%-10s\"\r\n", "left"); printf("%s", buf);
|
||||
sprintf(buf, "justif: \"%10s\"\r\n", "right"); printf("%s", buf);
|
||||
sprintf(buf, " 3: %04d zero padded\r\n", 3); printf("%s", buf);
|
||||
sprintf(buf, " 3: %-4d left justif.\r\n", 3); printf("%s", buf);
|
||||
sprintf(buf, " 3: %4d right justif.\r\n", 3); printf("%s", buf);
|
||||
sprintf(buf, "-3: %04d zero padded\r\n", -3); printf("%s", buf);
|
||||
sprintf(buf, "-3: %-4d left justif.\r\n", -3); printf("%s", buf);
|
||||
sprintf(buf, "-3: %4d right justif.\r\n", -3); printf("%s", buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* if you compile this file with
|
||||
* gcc -Wall $(YOUR_C_OPTIONS) -DTEST_PRINTF -c printf.c
|
||||
* you will get a normal warning:
|
||||
* printf.c:214: warning: spurious trailing `%' in format
|
||||
* this line is testing an invalid % at the end of the format string.
|
||||
*
|
||||
* this should display (on 32bit int machine) :
|
||||
*
|
||||
* Hello world!
|
||||
* printf test
|
||||
* (null) is null pointer
|
||||
* 5 = 5
|
||||
* -2147483647 = - max int
|
||||
* char a = 'a'
|
||||
* hex ff = ff
|
||||
* hex 00 = 00
|
||||
* signed -3 = unsigned 4294967293 = hex fffffffd
|
||||
* 0 message(s)
|
||||
* 0 message(s) with %
|
||||
* justif: "left "
|
||||
* justif: " right"
|
||||
* 3: 0003 zero padded
|
||||
* 3: 3 left justif.
|
||||
* 3: 3 right justif.
|
||||
* -3: -003 zero padded
|
||||
* -3: -3 left justif.
|
||||
* -3: -3 right justif.
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* To keep linker happy. */
|
||||
int write(int i, char* c, int n)
|
||||
{
|
||||
(void)i;
|
||||
(void)n;
|
||||
(void)c;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
/*****************************************************************************/
|
||||
/* UART_LOWLEV.C - Example user-defined device. */
|
||||
/*****************************************************************************/
|
||||
#include <file.h>
|
||||
#include "uart_drv.h"
|
||||
//#include "uart.h"
|
||||
|
||||
extern void UartSetup();
|
||||
extern void UartPutChar(int charToWrite);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* This is a sample implementation of a user-defined device. The device */
|
||||
/* must define the seven basic functions (open, close, read, write, lseek, */
|
||||
/* unlink, rename). These are expected to behave just like the Unix */
|
||||
/* functions of these names. Some devices might not have a reasonable */
|
||||
/* action to take for some functions; a UART or TTY device might not be */
|
||||
/* lseek-able, but can still be opened and written to. A device is added */
|
||||
/* using the add_device() RTS function call (q.v.). */
|
||||
/*****************************************************************************/
|
||||
/* The low-level interface is based on file names and file descriptors. */
|
||||
/* The file names don't need to be valid Unix file names, but must mean */
|
||||
/* something to the device. The device must keep track of its own file */
|
||||
/* descriptors, which will be used by the calling functions to read and */
|
||||
/* write to the device. If there can only be one instance of a "file" on a */
|
||||
/* device, the file descriptor doesn't matter much, so just pass a */
|
||||
/* non-negative integer such as zero. */
|
||||
/*****************************************************************************/
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* UART_open() */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
int UART_open(const char *path, unsigned flags, int llv_fd)
|
||||
{
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Only one UART device exists (_SSA). For an _SSA device, file names */
|
||||
/* are not meaningful, so ignore the file name. */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Don't allow attempts to open the UART device that aren't O_WRONLY. */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
if (!(flags & O_WRONLY)) return -1;
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Set up the UART */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
UartSetup();
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Arbitrarily give it file descriptor 1. File descriptors are */
|
||||
/* device-specific; this file descriptor 1 is not the same as HOST file */
|
||||
/* descriptor 1 (stdout). */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* UART_close() */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
int UART_close(int dev_fd)
|
||||
{
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Only one UART device exists, so we don't do anything upon close. */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* UART_read() reads *at most* count bytes. */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
int UART_read(int dev_fd, char *buf, unsigned count)
|
||||
{
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Only one UART device exists, and it is write-only, so return error */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* UART_write() */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
int UART_write(int dev_fd, const char *buf, unsigned count)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Output character-by-character */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
for (i=0; i < count; i++)
|
||||
UartPutChar(buf[i]);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* UART_lseek() */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
off_t UART_lseek(int dev_fd, off_t offset, int origin)
|
||||
{
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* lseek is not possible on UART. */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* UART_unlink() */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
int UART_unlink(const char *path)
|
||||
{
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* unlink is not possible on UART */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* */
|
||||
/* UART_rename() */
|
||||
/* */
|
||||
/*****************************************************************************/
|
||||
/* rename is unusual among the low-level functions in that it is also */
|
||||
/* specified in the ISO C standard. It has the same prototype and */
|
||||
/* semantics, so it's not really an issue. */
|
||||
/*****************************************************************************/
|
||||
int UART_rename(const char *old_name, const char *new_name)
|
||||
{
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* rename is not possible on UART */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
return -1;
|
||||
}
|
||||
Reference in new issue
Block a user