diff --git a/pigpio.c b/pigpio.c index 05bde0d..d7625f7 100644 --- a/pigpio.c +++ b/pigpio.c @@ -25,7 +25,7 @@ OTHER DEALINGS IN THE SOFTWARE. For more information, please refer to */ -/* pigpio version 44 */ +/* pigpio version 45 */ /* include ------------------------------------------------------- */ @@ -742,7 +742,8 @@ Assumes two counters per block. Each counter 4 * 16 (16^4=65536) #define PI_WF_MICROS 1 -#define DATUMS 125 +#define MAX_REPORT 120 +#define MAX_SAMPLE 4000 #define DEFAULT_PWM_IDX 5 @@ -1174,10 +1175,7 @@ static volatile uint32_t wdogBits = 0; static volatile int runState = PI_STARTING; -static int triggerAlert2 = 0; - -static int pthAlert1Running = 0; -static int pthAlert2Running = 0; +static int pthAlertRunning = 0; static int pthFifoRunning = 0; static int pthSocketRunning = 0; @@ -1215,8 +1213,6 @@ static int fdMem = -1; static int fdSock = -1; static int fdPmap = -1; static int fdMbox = -1; -static int fdAlertRead = -1; -static int fdAlertWrite = -1; static DMAMem_t *dmaMboxBlk = MAP_FAILED; static uintptr_t * * dmaPMapBlk = MAP_FAILED; @@ -1266,13 +1262,10 @@ static volatile gpioCfg_t gpioCfg = static unsigned bufferBlocks; /* number of blocks in buffer */ static unsigned bufferCycles; /* number of cycles */ -static pthread_t pthAlert1; -static pthread_t pthAlert2; +static pthread_t pthAlert; static pthread_t pthFifo; static pthread_t pthSocket; -static gpioReport_t gpioReport[DATUMS]; - static uint32_t spi_dummy; static unsigned old_mode_ce0; @@ -5108,10 +5101,30 @@ static void sigSetHandler(void) } } +/* + freq mics net + 0 1000 1000 900 + 1 4000 250 225 + 2 3750 266 240 + 3 3500 285 257 + 4 3250 307 276 + 5 3000 333 300 + 6 2750 363 327 + 7 2500 400 360 + 8 2250 444 400 + 9 2000 500 450 +10 1750 571 514 +11 1500 666 600 +12 1250 800 720 +13 1000 1000 900 +14 750 1333 1200 +15 500 2000 1800 +*/ + unsigned alert_delays[]= { - 1000000, 1034000, 1071000, 1111000, 1154000, 1200000, 1250000, 1304000, - 1364000, 1429000, 1500000, 1579000, 1667000, 1765000, 1875000, 2000000 + 900000, 225000, 240000, 257142, 276923, 300000, 327272, 360000, + 400000, 450000, 514285, 600000, 720000, 900000, 1200000, 1800000 }; /* ======================================================================= */ @@ -5119,7 +5132,7 @@ unsigned alert_delays[]= static void alertGlitchFilter(gpioSample_t *sample, int numSamples) { int i, j, diff; - uint32_t steadyUs, nowTick, RBitV, LBitV; + uint32_t steadyUs, changedTick, RBitV, LBitV; uint32_t bit, bitV; for (i=0; i<=PI_MAX_USER_GPIO; i++) @@ -5128,20 +5141,29 @@ static void alertGlitchFilter(gpioSample_t *sample, int numSamples) if (monitorBits & bit & gFilterBits) { - steadyUs = gpioAlert[i].gfSteadyUs; - RBitV = gpioAlert[i].gfRBitV; - LBitV = gpioAlert[i].gfLBitV; - nowTick = gpioAlert[i].gfTick; + steadyUs = gpioAlert[i].gfSteadyUs; + RBitV = gpioAlert[i].gfRBitV; + LBitV = gpioAlert[i].gfLBitV; + changedTick = gpioAlert[i].gfTick; for (j=0; j= steadyUs) { @@ -5156,19 +5178,11 @@ static void alertGlitchFilter(gpioSample_t *sample, int numSamples) } } - if (bitV != LBitV) - { - /* Difference between level and last level. - Restart steady timer. */ - - nowTick = sample[j].tick; - LBitV = bitV; - } } gpioAlert[i].gfRBitV = RBitV; gpioAlert[i].gfLBitV = LBitV; - gpioAlert[i].gfTick = nowTick; + gpioAlert[i].gfTick = changedTick; } } } @@ -5239,16 +5253,351 @@ static void alertNoiseFilter(gpioSample_t *sample, int numSamples) } } -static void alertWdogCheck(gpioSample_t *sample, int numSamples, uint32_t tick) +uint32_t _reportedLevel, _changedBits; + +static void alertEmit(gpioSample_t *sample, int numSamples, uint32_t eTick) +{ + uint32_t oldLevel, newLevel; + int32_t diff; + int emit, seqno, emitted; + uint32_t changes, bits, timeoutBits; + int d; + int b, n, v; + int err; + int max_emits; + char fifo[32]; + gpioReport_t report[MAX_REPORT]; + + if (_changedBits) + { + if (gpioGetSamples.func) + { + if (gpioGetSamples.ex) + { + (gpioGetSamples.func) + (sample, numSamples, gpioGetSamples.userdata); + } + else + { + (gpioGetSamples.func)(sample, numSamples); + } + } + } + + /* call alert callbacks for each bit transition */ + + if (_changedBits & alertBits) + { + oldLevel = (_reportedLevel & alertBits); + + for (d=0; d= gpioAlert[b].wdSteadyUs) + { + timeoutBits |= (1< 60000000) + { + if (numSamples) + newLevel = sample[numSamples-1].level; + else + newLevel = _reportedLevel; + + report[emit].seqno = seqno; + report[emit].flags = PI_NTFY_FLAGS_ALIVE; + report[emit].tick = eTick; + report[emit].level = newLevel; + + emit++; + seqno++; + } + } + + if (emit) + { + DBG(DBG_FAST_TICK, "notification %d (%d reports, %x-%x)", + n, emit, report[0].seqno, report[emit-1].seqno); + gpioNotify[n].lastReportTick = eTick; + max_emits = gpioNotify[n].max_emits; + + if (emit > gpioStats.maxEmit) gpioStats.maxEmit = emit; + + emitted = 0; + + while (emit > 0) + { + if (emit > max_emits) + { + gpioStats.emitFrags++; + + err = write(gpioNotify[n].fd, + report+emitted, + max_emits*sizeof(gpioReport_t)); + + if (err != (max_emits*sizeof(gpioReport_t))) + { + if (err < 0) + { + if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) + { + /* serious error, no point continuing */ + + DBG(DBG_ALWAYS, "fd=%d err=%d errno=%d", + gpioNotify[n].fd, err, errno); + + DBG(DBG_ALWAYS, "%s", strerror(errno)); + + gpioNotify[n].bits = 0; + gpioNotify[n].state = PI_NOTIFY_CLOSING; + intNotifyBits(); + break; + } + else gpioStats.wouldBlockPipeWrite++; + } + else + { + gpioCfg.internals |= PI_CFG_STATS; + gpioStats.shortPipeWrite++; + DBG(DBG_ALWAYS, "emitted %d, asked for %d", + err/sizeof(gpioReport_t), max_emits); + } + } + else gpioStats.goodPipeWrite++; + + emitted += max_emits; + emit -= max_emits; + } + else + { + err = write(gpioNotify[n].fd, + report+emitted, + emit*sizeof(gpioReport_t)); + + if (err != (emit*sizeof(gpioReport_t))) + { + if (err < 0) + { + if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) + { + DBG(DBG_ALWAYS, "fd=%d err=%d errno=%d", + gpioNotify[n].fd, err, errno); + + DBG(DBG_ALWAYS, "%s", strerror(errno)); + + /* serious error, no point continuing */ + gpioNotify[n].bits = 0; + gpioNotify[n].state = PI_NOTIFY_CLOSING; + intNotifyBits(); + break; + } + else gpioStats.wouldBlockPipeWrite++; + } + else + { + gpioCfg.internals |= PI_CFG_STATS; + gpioStats.shortPipeWrite++; + DBG(DBG_ALWAYS, "emitted %d, asked for %d", + err/sizeof(gpioReport_t), emit); + } + } + else gpioStats.goodPipeWrite++; + + emitted += emit; + emit = 0; + } + } + + gpioNotify[n].seqno = seqno; + } + } + } + + if (_changedBits & scriptBits) + { + for (n=0; n= gpioAlert[i].wdSteadyUs) triggerAlert2 = 1; } } } -#define PIPE_MAX 500 - -static void * pthAlert1Thread(void *x) +static void * pthAlertThread(void *x) { struct timespec req, rem; - uint32_t oldLevel, newLevel, level, reportedLevel; + uint32_t oldLevel, newLevel, level; uint32_t oldSlot, newSlot; - uint32_t stick, expected, ft; + uint32_t expected, ft, sTick; int32_t diff, minDiff, stickInited; int cycle, pulse; - uint32_t changedBits; int numSamples, ticks, i; - int rp, compactedSamples; + int rp, compactedSamples, totalSamples; int stopped; int moreToDo; - int skippedAlert2Count; - gpioSample_t sample[PIPE_MAX]; - int pipefd[2]; - - pipe(pipefd); - - fdAlertRead = pipefd[0]; - fdAlertWrite = pipefd[1]; - - i = fcntl(fdAlertRead, F_SETPIPE_SZ, 32*4096); + gpioSample_t sample[MAX_SAMPLE]; req.tv_sec = 0; @@ -5310,7 +5643,7 @@ static void * pthAlert1Thread(void *x) spinWhileStarting(); - reportedLevel = gpioReg[GPLEV0]; + _reportedLevel = gpioReg[GPLEV0]; oldSlot = dmaCurrentSlot(dmaNowAtICB()); @@ -5326,39 +5659,63 @@ static void * pthAlert1Thread(void *x) stickInited = 0; - stick = 0; + sTick = 0; minDiff = gpioCfg.clockMicros / 2; - skippedAlert2Count = 0; - while (1) { + /* Check that DMA is running okay */ + + if (dmaIn[DMA_CONBLK_AD]) + { + if (stopped) + { + DBG(DBG_STARTUP, "****** GOING ******"); + stopped = 0; + } + } + else + { + stopped = 1; + + myGpioDelay(5000); + + if (runState == PI_RUNNING) + { + /* should never be executed, leave code just in case */ + + gpioCfg.internals |= PI_CFG_STATS; + + dmaInitCbs(); + flushMemory(); + initDMAgo((uint32_t *)dmaIn, (uint32_t)dmaIBus[0]); + myGpioDelay(5000); /* let DMA run for a while */ + oldSlot = dmaCurrentSlot(dmaNowAtICB()); + gpioStats.DMARestarts++; + } + } + newSlot = dmaCurrentSlot(dmaNowAtICB()); newSlot = (newSlot / PULSE_PER_CYCLE) * PULSE_PER_CYCLE; numSamples = 0; - changedBits = 0; - - oldLevel = reportedLevel & monitorBits; - /* - Work through latest samples saving any level - changes of gpios of interest. + Extract samples from DMA ring buffer. */ - while ((oldSlot != newSlot) && (numSamples < PIPE_MAX)) + while ((oldSlot != newSlot) && (numSamples < MAX_SAMPLE)) { level = myGetLevel(oldSlot++); - sample[numSamples].tick = stick; + sample[numSamples].tick = sTick; sample[numSamples].level = level; numSamples++; - stick += gpioCfg.clockMicros; + sTick += gpioCfg.clockMicros; if (++pulse >= PULSE_PER_CYCLE) { @@ -5370,19 +5727,19 @@ static void * pthAlert1Thread(void *x) oldSlot = 0; } - expected = stick; + expected = sTick; - stick = myGetTick(cycle); + sTick = myGetTick(cycle); if (stickInited) { - diff = stick - expected; + diff = sTick - expected; if (abs(diff) > minDiff) { ft = sample[numSamples-PULSE_PER_CYCLE].tick; - ticks = stick - ft; + ticks = sTick - ft; for (i=1; i= MAX_REPORT) + { + totalSamples += compactedSamples; + + /* Rebase watchdog timeouts */ + if (wdogBits) alertWdogCheck(sample, compactedSamples); + + gpioStats.numSamples += compactedSamples; + + alertEmit(sample, compactedSamples, sample[rp].tick); + + compactedSamples = 0; + } } } - if (++skippedAlert2Count > 10000) - { - /* call alert 2 thread at least every 10 seconds */ - - triggerAlert2 = 1; - } - if (compactedSamples) { - numSamples = compactedSamples; - if (wdogBits) - alertWdogCheck(sample, numSamples, sample[numSamples-1].tick); - } - else - { - if (wdogBits) alertWdogCheck(sample, 0, sample[numSamples-1].tick); + totalSamples += compactedSamples; - if (triggerAlert2) - { - /* emit a null report to trigger alert 2 thread */ - - sample[0].tick = sample[numSamples-1].tick; - sample[0].level = sample[numSamples-1].level; - numSamples = 1; - } - else numSamples = 0; - } - - if (numSamples) - { - write(fdAlertWrite, sample, numSamples * sizeof(gpioSample_t)); - - skippedAlert2Count = 0; - - /* once all outputs have been emitted set reported level */ - - reportedLevel = sample[numSamples-1].level; - - if (compactedSamples > gpioStats.maxSamples) - gpioStats.maxSamples = compactedSamples; + /* Rebase watchdog timeouts */ + if (wdogBits) alertWdogCheck(sample, compactedSamples); gpioStats.numSamples += compactedSamples; } - /* Check that DMA is running okay */ + alertEmit(sample, compactedSamples, sTick); - if (dmaIn[DMA_CONBLK_AD]) - { - if (stopped) - { - DBG(DBG_STARTUP, "****** GOING ******"); - stopped = 0; - } - } - else - { - stopped = 1; - - myGpioDelay(5000); - - if (runState == PI_RUNNING) - { - /* should never be executed, leave code just in case */ - - gpioCfg.internals |= PI_CFG_STATS; - - dmaInitCbs(); - flushMemory(); - initDMAgo((uint32_t *)dmaIn, (uint32_t)dmaIBus[0]); - myGpioDelay(5000); /* let DMA run for a while */ - oldSlot = dmaCurrentSlot(dmaNowAtICB()); - gpioStats.DMARestarts++; - } - } + if (totalSamples > gpioStats.maxSamples) + gpioStats.maxSamples = numSamples; req.tv_sec = 0; req.tv_nsec = alert_delays[(gpioCfg.internals>>PI_CFG_ALERT_FREQ)&15]; if (moreToDo) { - req.tv_nsec /= 2; - gpioStats.moreToDo++; } else { gpioStats.alertTicks++; - } - while (nanosleep(&req, &rem)) - { - req.tv_sec = rem.tv_sec; - req.tv_nsec = rem.tv_nsec; - } - } - - return 0; -} - -static void * pthAlert2Thread(void *x) -{ - uint32_t oldLevel, newLevel, reportedLevel; - uint32_t stick; - int32_t diff; - int emit, seqno, emitted; - uint32_t changes, bits, changedBits, timeoutBits; - int numSamples, d, i; - int b, n, v; - int err; - int max_emits; - int bytes; - char fifo[32]; - gpioSample_t sample[DATUMS]; - - while (fdAlertRead < 0) time_sleep(0.01) ; - - reportedLevel = gpioReg[GPLEV0]; - - oldLevel = reportedLevel & monitorBits; - - while (1) - { - bytes = read(fdAlertRead, sample, DATUMS * sizeof(gpioSample_t)); - - triggerAlert2 = 0; - - numSamples = bytes / sizeof(gpioSample_t); - - changedBits = 0; - - stick = sample[numSamples-1].tick; - - for (i=0; i= gpioAlert[b].wdSteadyUs) - { - timeoutBits |= (1< 60000000) - { - if (numSamples) - newLevel = sample[numSamples-1].level; - else - newLevel = reportedLevel; - - gpioReport[emit].seqno = seqno; - gpioReport[emit].flags = PI_NTFY_FLAGS_ALIVE; - gpioReport[emit].tick = stick; - gpioReport[emit].level = newLevel; - - emit++; - seqno++; - } - } - - if (emit) - { - DBG(DBG_FAST_TICK, "notification %d (%d reports, %x-%x)", - n, emit, gpioReport[0].seqno, gpioReport[emit-1].seqno); - gpioNotify[n].lastReportTick = stick; - max_emits = gpioNotify[n].max_emits; - - if (emit > gpioStats.maxEmit) gpioStats.maxEmit = emit; - - emitted = 0; - - while (emit > 0) - { - if (emit > max_emits) - { - gpioStats.emitFrags++; - - err = write(gpioNotify[n].fd, - gpioReport+emitted, - max_emits*sizeof(gpioReport_t)); - - if (err != (max_emits*sizeof(gpioReport_t))) - { - if (err < 0) - { - if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) - { - /* serious error, no point continuing */ - - DBG(DBG_ALWAYS, "fd=%d err=%d errno=%d", - gpioNotify[n].fd, err, errno); - - DBG(DBG_ALWAYS, "%s", strerror(errno)); - - gpioNotify[n].bits = 0; - gpioNotify[n].state = PI_NOTIFY_CLOSING; - triggerAlert2 = 1; - intNotifyBits(); - break; - } - else gpioStats.wouldBlockPipeWrite++; - } - else - { - gpioCfg.internals |= PI_CFG_STATS; - gpioStats.shortPipeWrite++; - DBG(DBG_ALWAYS, "emitted %d, asked for %d", - err/sizeof(gpioReport_t), max_emits); - } - } - else gpioStats.goodPipeWrite++; - - emitted += max_emits; - emit -= max_emits; - } - else - { - err = write(gpioNotify[n].fd, - gpioReport+emitted, - emit*sizeof(gpioReport_t)); - - if (err != (emit*sizeof(gpioReport_t))) - { - if (err < 0) - { - if ((errno != EAGAIN) && (errno != EWOULDBLOCK)) - { - DBG(DBG_ALWAYS, "fd=%d err=%d errno=%d", - gpioNotify[n].fd, err, errno); - - DBG(DBG_ALWAYS, "%s", strerror(errno)); - - /* serious error, no point continuing */ - gpioNotify[n].bits = 0; - gpioNotify[n].state = PI_NOTIFY_CLOSING; - triggerAlert2 = 1; - intNotifyBits(); - break; - } - else gpioStats.wouldBlockPipeWrite++; - } - else - { - gpioCfg.internals |= PI_CFG_STATS; - gpioStats.shortPipeWrite++; - DBG(DBG_ALWAYS, "emitted %d, asked for %d", - err/sizeof(gpioReport_t), emit); - } - } - else gpioStats.goodPipeWrite++; - - emitted += emit; - emit = 0; - } - } - - gpioNotify[n].seqno = seqno; - } - } - } - - if (changedBits & scriptBits) - { - for (n=0; n #include #include -#define PIGPIO_VERSION 44 +#define PIGPIO_VERSION 45 /*TEXT diff --git a/x_pigpio.c b/x_pigpio.c index 4554950..50212b0 100644 --- a/x_pigpio.c +++ b/x_pigpio.c @@ -522,12 +522,12 @@ void t7() /* type of edge shouldn't matter for watchdogs */ gpioSetAlertFunc(GPIO, t7cbf); - gpioSetWatchdog(GPIO, 10); /* 10 ms, 100 per second */ + gpioSetWatchdog(GPIO, 50); /* 50 ms, 20 per second */ time_sleep(0.5); oc = t7_count; time_sleep(2); c = t7_count - oc; - CHECK(7, 1, c, 200, 1, "set watchdog on count"); + CHECK(7, 1, c, 39, 5, "set watchdog on count"); gpioSetWatchdog(GPIO, 0); /* 0 switches watchdog off */ time_sleep(0.5); diff --git a/x_pigpio.py b/x_pigpio.py index 261a71a..9136f48 100755 --- a/x_pigpio.py +++ b/x_pigpio.py @@ -109,7 +109,6 @@ def t2(): f = t2_count - oc CHECK(2, 3, f, 0, 0, "set PWM dutycycle, callback") - pi.set_PWM_dutycycle(GPIO, 128) dc = pi.get_PWM_dutycycle(GPIO) CHECK(2, 4, dc, 128, 0, "get PWM dutycycle") @@ -155,6 +154,8 @@ def t2(): pi.set_PWM_dutycycle(GPIO, 0) + t2cb.cancel() + t3_reset=True t3_count=0 t3_tick=0 @@ -234,6 +235,8 @@ def t3(): pi.set_PWM_dutycycle(GPIO, 0) + t3cb.cancel() + def t4(): print("Pipe notification tests.") @@ -465,6 +468,8 @@ To the lascivious pleasing of a lute. e = pi.wave_delete(0) CHECK(5, 33, e, 0, 0, "wave delete") + t5cb.cancel() + t6_count=0 t6_on=0 t6_on_tick=None @@ -501,6 +506,8 @@ def t6(): CHECK(6, 2, t6_on, tp, 25, "gpio trigger pulse length") + t6cb.cancel() + t7_count=0 def t7cbf(gpio, level, tick): @@ -516,12 +523,12 @@ def t7(): # type of edge shouldn't matter for watchdogs t7cb = pi.callback(GPIO, pigpio.FALLING_EDGE, t7cbf) - pi.set_watchdog(GPIO, 10) # 10 ms, 100 per second + pi.set_watchdog(GPIO, 50) # 50 ms, 20 per second time.sleep(0.5) oc = t7_count time.sleep(2) c = t7_count - oc - CHECK(7, 1, c, 200, 5, "set watchdog on count") + CHECK(7, 1, c, 39, 5, "set watchdog on count") pi.set_watchdog(GPIO, 0) # 0 switches watchdog off time.sleep(0.5) @@ -530,6 +537,8 @@ def t7(): c = t7_count - oc CHECK(7, 2, c, 0, 1, "set watchdog off count") + t7cb.cancel() + def t8(): print("Bank read/write tests.") @@ -661,6 +670,8 @@ def t9(): e = pi.delete_script(s) CHECK(9, 4, e, 0, 0, "delete script") + t9cb.cancel() + pigpio.exceptions = old_exceptions def ta(): @@ -830,6 +841,116 @@ def tc(): e = pi.spi_close(h) CHECK(12, 99, e, 0, 0, "spi close") +def td(): + + print("Wavechains & filter tests.") + + tdcb = pi.callback(GPIO) + + pi.set_mode(GPIO, pigpio.OUTPUT) + + pi.write(GPIO, pigpio.LOW) + + e = pi.wave_clear() + CHECK(13, 1, e, 0, 0, "callback, set mode, wave clear") + + wf = [] + + wf.append(pigpio.pulse(1< 1: tests = "" for C in sys.argv[1]: @@ -838,7 +959,7 @@ if len(sys.argv) > 1: tests += c else: - tests = "0123456789" + tests = "0123456789d" pi = pigpio.pi() @@ -858,6 +979,7 @@ if pi.connected: if 'a' in tests: ta() if 'b' in tests: tb() if 'c' in tests: tc() + if 'd' in tests: td() pi.stop() diff --git a/x_pigpiod_if.c b/x_pigpiod_if.c index 17fd8a8..df2af4b 100644 --- a/x_pigpiod_if.c +++ b/x_pigpiod_if.c @@ -490,12 +490,12 @@ void t7() /* type of edge shouldn't matter for watchdogs */ callback(GPIO, FALLING_EDGE, t7cbf); - set_watchdog(GPIO, 10); /* 10 ms, 100 per second */ + set_watchdog(GPIO, 50); /* 50 ms, 20 per second */ time_sleep(0.5); oc = t7_count; time_sleep(2); c = t7_count - oc; - CHECK(7, 1, c, 200, 1, "set watchdog on count"); + CHECK(7, 1, c, 39, 5, "set watchdog on count"); set_watchdog(GPIO, 0); /* 0 switches watchdog off */ time_sleep(0.5); diff --git a/x_pigpiod_if2.c b/x_pigpiod_if2.c index ec2da1e..5e18469 100644 --- a/x_pigpiod_if2.c +++ b/x_pigpiod_if2.c @@ -498,12 +498,12 @@ void t7(int pi) /* type of edge shouldn't matter for watchdogs */ id = callback(pi, GPIO, FALLING_EDGE, t7cbf); - set_watchdog(pi, GPIO, 10); /* 10 ms, 100 per second */ + set_watchdog(pi, GPIO, 50); /* 50 ms, 20 per second */ time_sleep(0.5); oc = t7_count; time_sleep(2); c = t7_count - oc; - CHECK(7, 1, c, 200, 1, "set watchdog on count"); + CHECK(7, 1, c, 39, 5, "set watchdog on count"); set_watchdog(pi, GPIO, 0); /* 0 switches watchdog off */ time_sleep(0.5);