/* * ALDL Dashboard, core 160 baud handling code * * (c) 2019 Solomon Peachy * * The latest version of this program can be found at: * * http://git.shaftnet.org/cgit/users/pizza/public/aldl_pi.git * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 3 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 General Public License * for more details. * * You should have received a copy of the GNU 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. * * [http://www.gnu.org/licenses/gpl-3.0.html] * * SPDX-License-Identifier: GPL-3.0+ * */ #include #include #include #include #include #include "aldl.h" /* shift register & sync word */ #define SYNC_WORD 0x1ff #define DWELL_TIME 1000 /* microseconds after falling edge */ #define DEBOUNCE_TIME 200 /* microseconds */ #define MAX_STREAM_WORDS 255 static uint16_t ALDLSR = 0; static uint8_t bits = 0; static int datalen = 0; static uint8_t data[MAX_STREAM_WORDS]; int gotsync = 0; static FILE *datalog_handle; struct stream_common decoded = { 0 }; void (*aldl_callback)(uint8_t *data, int datalen) = NULL; /* Datalogging */ void datalog_init(char *fname) { datalog_handle = fopen(fname, "a"); if (!datalog_handle) perror("Can't open datalog file!\n"); fprintf(datalog_handle, "# New session\n"); } void datalog_close(void) { if (datalog_handle) fclose(datalog_handle); } static void aldl_datalog(uint8_t *data, int datalen) { int i; if (!datalog_handle) return; fprintf(datalog_handle, "%ld", time(NULL)); for (i = 0 ; i < datalen ; i++) { fprintf(datalog_handle, ",%02x", *data++); } fprintf(datalog_handle, "\n"); } static void process_bit(int val) { ALDLSR <<= 1; ALDLSR |= (val & 1); if ((ALDLSR & SYNC_WORD) == SYNC_WORD) { /* New sync word, we've finished a sequence */ printf(" - %d\n", datalen); /* Received a sync word.. */ ALDLSR = 0; if (!gotsync) { gotsync = 1; return; /* First one, we don't do anything */ } /* Process ALDL payload */ if (aldl_callback) aldl_callback(data, datalen); /* Log data */ if (datalog_handle) aldl_datalog(data, datalen); /* Reset state */ bits = 0; datalen = 0; } else if (++bits == 9) { printf(" %02x", ALDLSR & 0xFF); /* Just latch in the word */ data[datalen++] = ALDLSR & 0xff; /* Reset state */ bits = 0; ALDLSR = 0; } } /* ISR */ void isrfn(void) { int val; delayfn(DWELL_TIME); // To handle both variations, minimum of 0.5, max of 1.8ms val = !readbit(); // If hi, represents ALDL 0; if low, ALDL1. process_bit(val); } #include int run_sampler = 1; long tv_diff(struct timeval *tv1, struct timeval *tv2) { long usecs = (tv2->tv_sec - tv1->tv_sec) * 1000000; usecs += (tv2->tv_usec - tv1->tv_usec); return usecs; } /* Alternatively.. continually poll. */ void poll_gpio(void) { struct timeval tv, last_tv; int pin, last_pin; long total_us = 0; gettimeofday(&last_tv, NULL); last_pin = readbit(); while(run_sampler) { /* Read */ gettimeofday(&tv, NULL); pin = readbit(); /* Work out how long it's been since our last sample */ total_us += tv_diff(&last_tv, &tv); last_tv = tv; /* No edge.. or possibly false edge. */ if (pin == last_pin || total_us < DEBOUNCE_TIME) continue; if (pin == 1) { /* ie Rising edge */ // printf ("%06d\n", total_us); /* Rising edge. tells us when the bit ends */ if (total_us > DWELL_TIME) process_bit(0); /* long period high is logical 0 */ else process_bit(1); /* short period high is logical 1 */ } /* Edge transition, reset time and record new pin */ total_us = 0; last_pin = pin; } } static pthread_t poller; static int polling = 0; static void *thread_poller(void *arg) { poll_gpio(); pthread_exit(NULL); } int thread_start(void) { polling = 1; return pthread_create(&poller, NULL, thread_poller, NULL); } void thread_shutdown(void) { if (polling) { run_sampler = 0; pthread_join(poller, NULL); polling = 0; } }