From 0f3f8f68f87233bf59c3fa68c3dfe1f492a1a478 Mon Sep 17 00:00:00 2001 From: inmarket Date: Wed, 20 Aug 2014 17:42:53 +1000 Subject: Rename lots of files to help prevent compile time name conflicts. --- src/gadc/gadc_gadc.c | 362 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 362 insertions(+) create mode 100644 src/gadc/gadc_gadc.c (limited to 'src/gadc/gadc_gadc.c') diff --git a/src/gadc/gadc_gadc.c b/src/gadc/gadc_gadc.c new file mode 100644 index 00000000..5ac8e53c --- /dev/null +++ b/src/gadc/gadc_gadc.c @@ -0,0 +1,362 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file src/gadc/gadc_gadc.c + * @brief GADC sub-system code. + * + * @addtogroup GADC + * @{ + */ +#include "gfx.h" + +#if GFX_USE_GADC + +/* Include the driver defines */ +#include "driver.h" + +#if GADC_MAX_HIGH_SPEED_SAMPLERATE > GADC_MAX_SAMPLE_FREQUENCY/2 + #error "GADC: GADC_MAX_HIGH_SPEED_SAMPLERATE has been set too high. It must be less than half the maximum CPU rate" +#endif + +#define GADC_HSADC_GTIMER 0x8000 +#define GADC_ADC_RUNNING 0x4000 +#define GADC_HSADC_CONVERTION 0x2000 + +typedef struct NonTimerData_t { + gfxQueueGSyncItem next; + GADCCallbackFunction callback; + union { + void *param; + gfxSem sigdone; + }; + GadcNonTimerJob job; + } NonTimerData; + +static volatile uint16_t hsFlags; +static size_t hsBytesPerConv; +static GadcTimerJob hsJob; +static GDataBuffer *hsData; +static gfxQueueGSync hsListDone; +static GADCISRCallbackFunction hsISRcallback; +#if GFX_USE_GEVENT + static GTimer hsGTimer; +#endif + +static GTimer lsGTimer; +static gfxQueueGSync lsListToDo; +static gfxQueueGSync lsListDone; +static NonTimerData *lsData; + +void gadcGotDataI(size_t n) { + if ((hsFlags & GADC_HSADC_CONVERTION)) { + + // A set of timer conversions is done - add them + hsJob.done += n; + + // Are we finished yet? (or driver signalled complete now) + if (n && hsJob.done < hsJob.todo) + return; + + // Clear event flags we might set + hsFlags &= ~(GADC_HSADC_GOTBUFFER|GADC_HSADC_STALL); + + // Is there any data in it + if (!hsJob.done) { + + // Oops - no data in this buffer. Just return it to the free-list + gfxBufferReleaseI(hsData); + goto starttimerjob; // Restart the timer job + } + + // Save the buffer on the hsListDone list + hsData->len = hsJob.done * hsBytesPerConv; + gfxQueueGSyncPutI(&hsListDone, (gfxQueueGSyncItem *)hsData); + hsFlags |= GADC_HSADC_GOTBUFFER; + + /* Signal a buffer completion */ + if (hsISRcallback) + hsISRcallback(); + #if GFX_USE_GEVENT + if (hsFlags & GADC_HSADC_GTIMER) + gtimerJabI(&hsGTimer); + #endif + + // Stop if we have been told to + if (!(hsFlags & GADC_HSADC_RUNNING)) { + gadc_lld_stop_timerI(); + + // Get the next free buffer + } else if (!(hsData = gfxBufferGetI())) { + + // Oops - no free buffers. Stall + hsFlags &= ~GADC_HSADC_RUNNING; + hsFlags |= GADC_HSADC_STALL; + gadc_lld_stop_timerI(); + + // Prepare the next job + } else { + + // Return this new job + #if GFX_USE_OS_CHIBIOS + // ChibiOS api bug - samples must be even + hsJob.todo = (hsData->size / hsBytesPerConv) & ~1; + #else + hsJob.todo = hsData->size / hsBytesPerConv; + #endif + hsJob.done = 0; + hsJob.buffer = (adcsample_t *)(hsData+1); + } + + // Start a job preferring a non-timer job + if ((lsData = (NonTimerData *)gfxQueueGSyncGetI(&lsListToDo))) { + hsFlags &= ~GADC_HSADC_CONVERTION; + gadc_lld_nontimerjobI(&lsData->job); + } else if ((hsFlags & GADC_HSADC_RUNNING)) { + hsFlags |= GADC_HSADC_CONVERTION; + gadc_lld_timerjobI(&hsJob); + } else + hsFlags &= ~GADC_ADC_RUNNING; + + } else { + + // Did it fail + if (!n) { + // Push it back on the head of the queue - it didn't actually get done + gfxQueueGSyncPushI(&lsListToDo, (gfxQueueGSyncItem *)lsData); + lsData = 0; + goto starttimerjob; + } + + // A non-timer job completed - signal + if (lsData->callback) { + // Put it on the completed list and signal the timer to do the call-backs + gfxQueueGSyncPutI(&lsListDone, (gfxQueueGSyncItem *)lsData); + gtimerJabI(&lsGTimer); + } else { + // Signal the thread directly + gfxSemSignalI(&lsData->sigdone); + } + lsData = 0; + + // Start a job preferring a timer job +starttimerjob: + if ((hsFlags & GADC_HSADC_RUNNING)) { + hsFlags |= GADC_HSADC_CONVERTION; + gadc_lld_timerjobI(&hsJob); + } else if ((lsData = (NonTimerData *)gfxQueueGSyncGetI(&lsListToDo))) { + hsFlags &= ~GADC_HSADC_CONVERTION; + gadc_lld_nontimerjobI(&lsData->job); + } else + hsFlags &= ~GADC_ADC_RUNNING; + } +} + +/* Our module initialiser */ +void _gadcInit(void) +{ + gadc_lld_init(); + + gfxQueueGSyncInit(&hsListDone); + #if GFX_USE_GEVENT + gtimerInit(&hsGTimer); + #endif + gtimerInit(&lsGTimer); + gfxQueueGSyncInit(&lsListToDo); + gfxQueueGSyncInit(&lsListDone); +} + +void _gadcDeinit(void) +{ + /* commented stuff is ToDo */ + + // gadc_lld_deinit(); + gfxQueueGSyncDeinit(&hsListDone); + #if GFX_USE_GEVENT + gtimerDeinit(&hsGTimer); + #endif + gtimerDeinit(&lsGTimer); + gfxQueueGSyncDeinit(&lsListToDo); + gfxQueueGSyncDeinit(&lsListDone); +} + +#if GFX_USE_GEVENT + static void HighSpeedGTimerCallback(void *param) { + (void) param; + GSourceListener *psl; + GEventADC *pe; + + psl = 0; + while ((psl = geventGetSourceListener((GSourceHandle)(&hsGTimer), psl))) { + if (!(pe = (GEventADC *)geventGetEventBuffer(psl))) { + // This listener is missing - save this. + psl->srcflags |= GADC_HSADC_LOSTEVENT; + continue; + } + + pe->type = GEVENT_ADC; + pe->flags = (hsFlags & (GADC_HSADC_RUNNING|GADC_HSADC_GOTBUFFER|GADC_HSADC_STALL)) | psl->srcflags; + psl->srcflags = 0; + geventSendEvent(psl); + } + } +#endif + +void gadcHighSpeedInit(uint32_t physdev, uint32_t frequency) +{ + if ((hsFlags & GADC_HSADC_RUNNING)) + gadcHighSpeedStop(); + + /* Just save the details and reset everything for now */ + hsJob.physdev = physdev; + hsJob.frequency = frequency; + hsISRcallback = 0; + hsBytesPerConv = gadc_lld_samplesperconversion(physdev) * sizeof(adcsample_t); +} + +#if GFX_USE_GEVENT + GSourceHandle gadcHighSpeedGetSource(void) { + if (!gtimerIsActive(&hsGTimer)) + gtimerStart(&hsGTimer, HighSpeedGTimerCallback, 0, TRUE, TIME_INFINITE); + hsFlags |= GADC_HSADC_GTIMER; + return (GSourceHandle)&hsGTimer; + } +#endif + +void gadcHighSpeedSetISRCallback(GADCISRCallbackFunction isrfn) { + hsISRcallback = isrfn; +} + +GDataBuffer *gadcHighSpeedGetData(delaytime_t ms) { + return (GDataBuffer *)gfxQueueGSyncGet(&hsListDone, ms); +} + +GDataBuffer *gadcHighSpeedGetDataI(void) { + return (GDataBuffer *)gfxQueueGSyncGetI(&hsListDone); +} + +void gadcHighSpeedStart(void) { + // Safety first + if (!hsJob.frequency || !hsBytesPerConv) + return; + + gfxSystemLock(); + if (!(hsFlags & GADC_HSADC_RUNNING)) { + if (!(hsData = gfxBufferGetI())) { + // Oops - no free buffers. Stall + hsFlags |= GADC_HSADC_STALL; + #if GFX_USE_GEVENT + if (hsFlags & GADC_HSADC_GTIMER) + gtimerJabI(&hsGTimer); + #endif + + // Prepare the next job + } else { + + #if GFX_USE_OS_CHIBIOS + // ChibiOS api bug - samples must be even + hsJob.todo = (hsData->size / hsBytesPerConv) & ~1; + #else + hsJob.todo = hsData->size / hsBytesPerConv; + #endif + hsJob.done = 0; + hsJob.buffer = (adcsample_t *)(hsData+1); + hsFlags |= GADC_HSADC_RUNNING; + + // Start the timer + gadc_lld_start_timerI(hsJob.frequency); + + // If nothing is running start the job + if (!(hsFlags & GADC_ADC_RUNNING)) { + hsFlags |= (GADC_HSADC_CONVERTION|GADC_ADC_RUNNING); + gadc_lld_timerjobI(&hsJob); + } + } + } + gfxSystemUnlock(); +} + +void gadcHighSpeedStop(void) { + // Stop it and wait for completion + hsFlags &= ~GADC_HSADC_RUNNING; + while ((hsFlags & GADC_HSADC_CONVERTION)) + gfxYield(); +} + +static void LowSpeedGTimerCallback(void *param) { + (void) param; + NonTimerData *pdata; + + // Look for completed non-timer jobs and call the call-backs for each + while ((pdata = (NonTimerData *)gfxQueueGSyncGet(&lsListDone, TIME_IMMEDIATE))) { + pdata->callback(pdata->job.buffer, pdata->param); + gfxFree(pdata); + } +} + +void gadcLowSpeedGet(uint32_t physdev, adcsample_t *buffer) { + NonTimerData ndata; + + // Prepare the job + gfxSemInit(&ndata.sigdone, 0, 1); + ndata.job.physdev = physdev; + ndata.job.buffer = buffer; + ndata.callback = 0; + + // Activate it + gfxSystemLock(); + if (!(hsFlags & GADC_ADC_RUNNING)) { + // Nothing is running - start the job + lsData = &ndata; + hsFlags |= GADC_ADC_RUNNING; + hsFlags &= ~GADC_HSADC_CONVERTION; + gadc_lld_nontimerjobI(&ndata.job); + } else { + // Just put it on the queue + gfxQueueGSyncPutI(&lsListToDo, (gfxQueueGSyncItem *)&ndata); + } + gfxSystemUnlock(); + + // Wait for it to complete + gfxSemWait(&ndata.sigdone, TIME_INFINITE); + gfxSemDestroy(&ndata.sigdone); +} + +bool_t gadcLowSpeedStart(uint32_t physdev, adcsample_t *buffer, GADCCallbackFunction fn, void *param) { + NonTimerData *pdata; + + /* Start the Low Speed Timer */ + if (!gtimerIsActive(&lsGTimer)) + gtimerStart(&lsGTimer, LowSpeedGTimerCallback, 0, TRUE, TIME_INFINITE); + + // Prepare the job + if (!(pdata = gfxAlloc(sizeof(NonTimerData)))) + return FALSE; + pdata->job.physdev = physdev; + pdata->job.buffer = buffer; + pdata->callback = fn; + pdata->param = param; + + // Activate it + gfxSystemLock(); + if (!(hsFlags & GADC_ADC_RUNNING)) { + // Nothing is running - start the job + lsData = pdata; + hsFlags |= GADC_ADC_RUNNING; + hsFlags &= ~GADC_HSADC_CONVERTION; + gadc_lld_nontimerjobI(&pdata->job); + } else { + // Just put it on the queue + gfxQueueGSyncPutI(&lsListToDo, (gfxQueueGSyncItem *)pdata); + } + gfxSystemUnlock(); + return TRUE; +} + +#endif /* GFX_USE_GADC */ +/** @} */ + -- cgit v1.2.3