////////////////////////////////////////////////////// // First things first, all the includes we need // ////////////////////////////////////////////////////// #ifndef FSK_MODEM_H #define FSK_MODEM_H #include "config.h" // Various configuration values #include "hardware.h" // Hardware functions #include // Compiler info from BertOS #include // FIFO buffer implementation from BertOS #include // The BertOS KFile interface. This is // used for letting other functions read // from or write to the modem like a // file descriptor. ////////////////////////////////////////////////////// // Our type definitions and function declarations // ////////////////////////////////////////////////////// #define SAMPLERATE 9600 // The rate at which we are sampling and synthesizing #define BITRATE 1200 // The actual bitrate at baseband. This is the baudrate. #define SAMPLESPERBIT (SAMPLERATE / BITRATE) // How many DAC/ADC samples constitute one bit (8). // This defines an errortype for a receive- // buffer overrun. #define RX_OVERRUN BV(0) // This struct defines a Hdlc parser. It will let // us parse the raw bits coming in from the modem // and synchronise to byte boundaries. typedef struct Hdlc { uint8_t demodulatedBits; // Incoming bitstream from demodulator uint8_t bitIndex; // The current received bit in the current received byte uint8_t currentByte; // The byte we're currently receiving bool receiving; // Whether or not where actually receiving data (or just noise ;P) } Hdlc; // This is our primary modem struct. It defines // all the values we need to modulate and // demodulate data from the physical medium. typedef struct Afsk { KFile fd; // A file descriptor for reading from and // writing to the modem // I/O hardware pins int adcPin; // Pin for incoming signal // General values Hdlc hdlc; // We need a link control structure uint16_t preambleLength; // Length of sync preamble uint16_t tailLength; // Length of transmission tail // Modulation values uint8_t sampleIndex; // Current sample index for outgoing bit uint8_t currentOutputByte; // Current byte to be modulated uint8_t txBit; // Mask of current modulated bit bool bitStuff; // Whether bitstuffing is allowed uint8_t bitstuffCount; // Counter for bit-stuffing uint16_t phaseAcc; // Phase accumulator uint16_t phaseInc; // Phase increment per sample FIFOBuffer txFifo; // FIFO for transmit data uint8_t txBuf[CONFIG_AFSK_TX_BUFLEN]; // Actial data storage for said FIFO volatile bool sending; // Set when modem is sending // Demodulation values FIFOBuffer delayFifo; // Delayed FIFO for frequency discrimination int8_t delayBuf[SAMPLESPERBIT / 2 + 1];// Actual data storage for said FIFO FIFOBuffer rxFifo; // FIFO for received data uint8_t rxBuf[CONFIG_AFSK_RX_BUFLEN]; // Actual data storage for said FIFO int16_t iirX[2]; // IIR Filter X cells int16_t iirY[2]; // IIR Filter Y cells uint8_t sampledBits; // Bits sampled by the demodulator (at ADC speed) int8_t currentPhase; // Current phase of the demodulator uint8_t actualBits; // Actual found bits at correct bitrate volatile int status; // Status of the modem, 0 means OK } Afsk; // Explanation nessecary for this. BertOS uses an // object-oriented approach for handling "file-like" // transactions (yes, we are using C :P). What we are // doing here is defining a specific "file type" for // the standard KFile to identify the modem as a "file" // that can be read from and written to. #define KFT_AFSK MAKE_ID('F', 'S', 'K', 'M') // We then make a macro that can "typecast" a generic // KFile file-pointer to an Afsk "object". This lets // other pieces of code read from and write to the AFSK // "objects" buffers with the standard KFile operations. // If this seems weird and confusing, check out the // BertOS KFile explanation at: // http://www.bertos.org/use/tutorial-front-page/drivers-kfile-interface INLINE Afsk *AFSK_CAST(KFile *fd) { // We need to assert that the what we are trying // to read/write is actually an AFSK "object", // identified by the KFT_AFSK constant ASSERT(fd->_type == KFT_AFSK); return (Afsk *)fd; } // Declare Interrupt Service Routines // and initialization functions void afsk_adc_isr(Afsk *af, int8_t sample); uint8_t afsk_dac_isr(Afsk *af); void afsk_init(Afsk *af, int adc_ch); #endif