/*
  TwoWire.h - TWI/I2C library for Arduino & Wiring
  Copyright (c) 2006 Nicholas Zambetti.  All right reserved.

  This library 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.1 of the License, or (at your option) any later version.

  This library 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 library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

  Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts
*/

#ifndef TwoWire_h
#define TwoWire_h

#if defined(__IMXRT1052__) || defined(__IMXRT1062__)
#include "WireIMXRT.h"

#elif defined(__arm__) && defined(TEENSYDUINO)
#include "WireKinetis.h"

#elif defined(__AVR__)

#include <inttypes.h>
#include <Arduino.h>

#define BUFFER_LENGTH 32
#define WIRE_HAS_END 1

class TwoWire : public Stream
{
  private:
    static uint8_t rxBuffer[];
    static uint8_t rxBufferIndex;
    static uint8_t rxBufferLength;

    static uint8_t txAddress;
    static uint8_t txBuffer[];
    static uint8_t txBufferIndex;
    static uint8_t txBufferLength;

    static uint8_t transmitting;
    static void onRequestService(void);
    static void onReceiveService(uint8_t*, int);
    static void (*user_onRequest)(void);
    static void (*user_onReceive)(int);
    static void sda_rising_isr(void);
  public:
    TwoWire();
    friend uintptr_t Teensyduino_Test_constinit_Wire(int instance, int index);
    void begin();
    void begin(uint8_t address);
    void begin(int address) {
      begin((uint8_t)address);
    }
    void end();
    void setClock(uint32_t frequency);
    void setSDA(uint8_t pin);
    void setSCL(uint8_t pin);
    void beginTransmission(uint8_t address);
    void beginTransmission(int address) {
      beginTransmission((uint8_t)address);
    }
    uint8_t endTransmission(uint8_t sendStop);
    uint8_t endTransmission(void) {
      return endTransmission(1);
    }
    uint8_t requestFrom(uint8_t address, uint8_t quantity, uint8_t sendStop);
    uint8_t requestFrom(uint8_t address, uint8_t quantity, bool sendStop) {
      return requestFrom(address, quantity, (uint8_t)(sendStop ? 1 : 0));
    }
    uint8_t requestFrom(uint8_t address, uint8_t quantity) {
      return requestFrom(address, quantity, (uint8_t)1);
    }
    uint8_t requestFrom(int address, int quantity, int sendStop) {
      return requestFrom((uint8_t)address, (uint8_t)quantity,
        (uint8_t)(sendStop ? 1 : 0));
    }
    uint8_t requestFrom(int address, int quantity) {
      return requestFrom((uint8_t)address, (uint8_t)quantity, (uint8_t)1);
    }
    uint8_t requestFrom(uint8_t addr, uint8_t qty, uint32_t iaddr, uint8_t n, uint8_t stop);
    virtual size_t write(uint8_t);
    virtual size_t write(const uint8_t *, size_t);
    virtual int available(void);
    virtual int read(void);
    virtual int peek(void);
	virtual void flush(void);
    void onReceive( void (*)(int) );
    void onRequest( void (*)(void) );
  
#ifdef CORE_TEENSY
    // added by Teensyduino installer, for compatibility
    // with pre-1.0 sketches and libraries
    void send(uint8_t b)               { write(b); }
    void send(uint8_t *s, uint8_t n)   { write(s, n); }
    void send(int n)                   { write((uint8_t)n); }
    void send(char *s)                 { write(s); }
    uint8_t receive(void) {
        int c = read();
        if (c < 0) return 0;
        return c;
    }
#endif
    inline size_t write(unsigned long n) { return write((uint8_t)n); }
    inline size_t write(long n) { return write((uint8_t)n); }
    inline size_t write(unsigned int n) { return write((uint8_t)n); }
    inline size_t write(int n) { return write((uint8_t)n); }
    using Print::write;
};

extern TwoWire Wire;

#endif
#endif
