<commit_before>/* Copyright 2015 Stanford University, NVIDIA Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// inlined methods for Realm logging

// nop, but helps IDEs
#include "logging.h"

namespace Realm {

  ////////////////////////////////////////////////////////////////////////
  //
  // class Logger

  inline const std::string& Logger::get_name(void) const
  {
    return name;
  }

  inline Logger::LoggingLevel Logger::get_level(void) const
  {
    return log_level;
  }

  // the static early outs are exactly to identify dead code, so ignore
  //  compiler warnings related to that
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wtautological-compare"
  inline LoggerMessage Logger::spew(void)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_SPEW) ||  // static early out
       (log_level > LEVEL_SPEW))                  // dynamic early out
      return LoggerMessage();

    return LoggerMessage(this, true, LEVEL_SPEW);
  }

  inline LoggerMessage Logger::debug(void)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_DEBUG) ||  // static early out
       (log_level > LEVEL_DEBUG))                  // dynamic early out
      return LoggerMessage();

    return LoggerMessage(this, true, LEVEL_DEBUG);
  }

  inline LoggerMessage Logger::info(void)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_INFO) ||  // static early out
       (log_level > LEVEL_INFO))                  // dynamic early out
      return LoggerMessage();

    return LoggerMessage(this, true, LEVEL_INFO);
  }

  inline LoggerMessage Logger::print(void)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_PRINT) ||  // static early out
       (log_level > LEVEL_PRINT))                  // dynamic early out
      return LoggerMessage();

    return LoggerMessage(this, true, LEVEL_PRINT);
  }

  inline LoggerMessage Logger::warning(void)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_WARNING) ||  // static early out
       (log_level > LEVEL_WARNING))                  // dynamic early out
      return LoggerMessage();

    return LoggerMessage(this, true, LEVEL_WARNING);
  }

  inline LoggerMessage Logger::error(void)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_ERROR) ||  // static early out
       (log_level > LEVEL_ERROR))                  // dynamic early out
      return LoggerMessage();

    return LoggerMessage(this, true, LEVEL_ERROR);
  }

  inline LoggerMessage Logger::fatal(void)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_FATAL) ||  // static early out
       (log_level > LEVEL_FATAL))                  // dynamic early out
      return LoggerMessage();

    return LoggerMessage(this, true, LEVEL_FATAL);
  }

  // use this only if you want a dynamic level for some reason
  inline LoggerMessage Logger::newmsg(LoggingLevel level)
  {
    if((REALM_LOGGING_MIN_LEVEL > level) ||
       (log_level > level))
      return LoggerMessage();

    return LoggerMessage(this, true, level);
  }

  // old printf-style interface
  inline void Logger::spew(const char *fmt, ...)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_SPEW) ||  // static early out
       (log_level > LEVEL_SPEW))                  // dynamic early out
      return;

    va_list args;
    va_start(args, fmt);
    spew().vprintf(fmt, args);
    va_end(args);
  }

  inline void Logger::debug(const char *fmt, ...)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_DEBUG) ||  // static early out
       (log_level > LEVEL_DEBUG))                  // dynamic early out
      return;

    va_list args;
    va_start(args, fmt);
    debug().vprintf(fmt, args);
    va_end(args);
  }

  inline void Logger::info(const char *fmt, ...)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_INFO) ||  // static early out
       (log_level > LEVEL_INFO))                  // dynamic early out
      return;

    va_list args;
    va_start(args, fmt);
    info().vprintf(fmt, args);
    va_end(args);
  }

  inline void Logger::print(const char *fmt, ...)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_PRINT) ||  // static early out
       (log_level > LEVEL_PRINT))                  // dynamic early out
      return;

    va_list args;
    va_start(args, fmt);
    print().vprintf(fmt, args);
    va_end(args);
  }

  inline void Logger::warning(const char *fmt, ...)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_WARNING) ||  // static early out
       (log_level > LEVEL_WARNING))                  // dynamic early out
      return;

    va_list args;
    va_start(args, fmt);
    warning().vprintf(fmt, args);
    va_end(args);
  }

  inline void Logger::error(const char *fmt, ...)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_ERROR) ||  // static early out
       (log_level > LEVEL_ERROR))                  // dynamic early out
      return;

    va_list args;
    va_start(args, fmt);
    error().vprintf(fmt, args);
    va_end(args);
  }

  inline void Logger::fatal(const char *fmt, ...)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_FATAL) ||  // static early out
       (log_level > LEVEL_FATAL))                  // dynamic early out
      return;

    va_list args;
    va_start(args, fmt);
    fatal().vprintf(fmt, args);
    va_end(args);
  }
#pragma GCC diagnostic pop

  ////////////////////////////////////////////////////////////////////////
  //
  // class LoggerMessage

  // default constructor makes an inactive message
  inline LoggerMessage::LoggerMessage(void)
    : logger(0), active(false), level(Logger::LEVEL_NONE)
  {}

  inline LoggerMessage::LoggerMessage(Logger *_logger, bool _active, Logger::LoggingLevel _level)
    : logger(_logger), active(_active), level(_level)
  {}

  inline LoggerMessage::LoggerMessage(const LoggerMessage& to_copy)
    : logger(to_copy.logger), active(to_copy.active), level(to_copy.level)
  {}

  inline LoggerMessage::~LoggerMessage(void)
  {
    if(active)
      logger->log_msg(level, oss.str());
  }

  template <typename T>
  inline LoggerMessage& LoggerMessage::operator<<(T val)
  {
    // send through to normal ostringstream formatting routines if active
    if(active)
      oss << val;
    return *this;
  }

}; // namespace Realm
<commit_msg>realm: more compiler warning fun<commit_after>/* Copyright 2015 Stanford University, NVIDIA Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// inlined methods for Realm logging

// nop, but helps IDEs
#include "logging.h"

namespace Realm {

  ////////////////////////////////////////////////////////////////////////
  //
  // class Logger

  inline const std::string& Logger::get_name(void) const
  {
    return name;
  }

  inline Logger::LoggingLevel Logger::get_level(void) const
  {
    return log_level;
  }

  // the static early outs are exactly to identify dead code, so ignore
  //  compiler warnings related to that (and warnings for compilers that
  //  don't understand -Wtautological-compare...)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpragmas"
#pragma GCC diagnostic ignored "-Wtautological-compare"
  inline LoggerMessage Logger::spew(void)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_SPEW) ||  // static early out
       (log_level > LEVEL_SPEW))                  // dynamic early out
      return LoggerMessage();

    return LoggerMessage(this, true, LEVEL_SPEW);
  }

  inline LoggerMessage Logger::debug(void)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_DEBUG) ||  // static early out
       (log_level > LEVEL_DEBUG))                  // dynamic early out
      return LoggerMessage();

    return LoggerMessage(this, true, LEVEL_DEBUG);
  }

  inline LoggerMessage Logger::info(void)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_INFO) ||  // static early out
       (log_level > LEVEL_INFO))                  // dynamic early out
      return LoggerMessage();

    return LoggerMessage(this, true, LEVEL_INFO);
  }

  inline LoggerMessage Logger::print(void)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_PRINT) ||  // static early out
       (log_level > LEVEL_PRINT))                  // dynamic early out
      return LoggerMessage();

    return LoggerMessage(this, true, LEVEL_PRINT);
  }

  inline LoggerMessage Logger::warning(void)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_WARNING) ||  // static early out
       (log_level > LEVEL_WARNING))                  // dynamic early out
      return LoggerMessage();

    return LoggerMessage(this, true, LEVEL_WARNING);
  }

  inline LoggerMessage Logger::error(void)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_ERROR) ||  // static early out
       (log_level > LEVEL_ERROR))                  // dynamic early out
      return LoggerMessage();

    return LoggerMessage(this, true, LEVEL_ERROR);
  }

  inline LoggerMessage Logger::fatal(void)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_FATAL) ||  // static early out
       (log_level > LEVEL_FATAL))                  // dynamic early out
      return LoggerMessage();

    return LoggerMessage(this, true, LEVEL_FATAL);
  }

  // use this only if you want a dynamic level for some reason
  inline LoggerMessage Logger::newmsg(LoggingLevel level)
  {
    if((REALM_LOGGING_MIN_LEVEL > level) ||
       (log_level > level))
      return LoggerMessage();

    return LoggerMessage(this, true, level);
  }

  // old printf-style interface
  inline void Logger::spew(const char *fmt, ...)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_SPEW) ||  // static early out
       (log_level > LEVEL_SPEW))                  // dynamic early out
      return;

    va_list args;
    va_start(args, fmt);
    spew().vprintf(fmt, args);
    va_end(args);
  }

  inline void Logger::debug(const char *fmt, ...)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_DEBUG) ||  // static early out
       (log_level > LEVEL_DEBUG))                  // dynamic early out
      return;

    va_list args;
    va_start(args, fmt);
    debug().vprintf(fmt, args);
    va_end(args);
  }

  inline void Logger::info(const char *fmt, ...)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_INFO) ||  // static early out
       (log_level > LEVEL_INFO))                  // dynamic early out
      return;

    va_list args;
    va_start(args, fmt);
    info().vprintf(fmt, args);
    va_end(args);
  }

  inline void Logger::print(const char *fmt, ...)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_PRINT) ||  // static early out
       (log_level > LEVEL_PRINT))                  // dynamic early out
      return;

    va_list args;
    va_start(args, fmt);
    print().vprintf(fmt, args);
    va_end(args);
  }

  inline void Logger::warning(const char *fmt, ...)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_WARNING) ||  // static early out
       (log_level > LEVEL_WARNING))                  // dynamic early out
      return;

    va_list args;
    va_start(args, fmt);
    warning().vprintf(fmt, args);
    va_end(args);
  }

  inline void Logger::error(const char *fmt, ...)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_ERROR) ||  // static early out
       (log_level > LEVEL_ERROR))                  // dynamic early out
      return;

    va_list args;
    va_start(args, fmt);
    error().vprintf(fmt, args);
    va_end(args);
  }

  inline void Logger::fatal(const char *fmt, ...)
  {
    if((REALM_LOGGING_MIN_LEVEL > LEVEL_FATAL) ||  // static early out
       (log_level > LEVEL_FATAL))                  // dynamic early out
      return;

    va_list args;
    va_start(args, fmt);
    fatal().vprintf(fmt, args);
    va_end(args);
  }
#pragma GCC diagnostic pop

  ////////////////////////////////////////////////////////////////////////
  //
  // class LoggerMessage

  // default constructor makes an inactive message
  inline LoggerMessage::LoggerMessage(void)
    : logger(0), active(false), level(Logger::LEVEL_NONE)
  {}

  inline LoggerMessage::LoggerMessage(Logger *_logger, bool _active, Logger::LoggingLevel _level)
    : logger(_logger), active(_active), level(_level)
  {}

  inline LoggerMessage::LoggerMessage(const LoggerMessage& to_copy)
    : logger(to_copy.logger), active(to_copy.active), level(to_copy.level)
  {}

  inline LoggerMessage::~LoggerMessage(void)
  {
    if(active)
      logger->log_msg(level, oss.str());
  }

  template <typename T>
  inline LoggerMessage& LoggerMessage::operator<<(T val)
  {
    // send through to normal ostringstream formatting routines if active
    if(active)
      oss << val;
    return *this;
  }

}; // namespace Realm
<|endoftext|>


<commit_before>/*
  HardwareSerial.cpp - Hardware serial library for 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 23 November 2006 by David A. Mellis
  Modified 28 September 2010 by Mark Sproul
  Modified 14 August 2012 by Alarus
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "Arduino.h"
#include "wiring_private.h"

// this next line disables the entire HardwareSerial.cpp,
// this is so I can support Attiny series and any other chip without a uart
#if defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H)

#include "HardwareSerial.h"

// Ensure that the various bit positions we use are available with a 0
// postfix, so we can always use the values for UART0 for all UARTs. The
// alternative, passing the various values for each UART to the
// HardwareSerial constructor also works, but makes the code bigger and
// slower.
#if !defined(TXC0)
#if defined(TXC)
// On ATmega8, the uart and its bits are not numbered, so there is no TXC0 etc.
#define TXC0 TXC
#define RXEN0 RXEN
#define TXEN0 TXEN
#define RXCIE0 RXCIE
#define UDRIE0 UDRIE
#define U2X0 U2X
#define UPE0 UPE
#define UDRE0 UDRE
#elif defined(TXC1)
// Some devices have uart1 but no uart0
#define TXC0 TXC1
#define RXEN0 RXEN1
#define TXEN0 TXEN1
#define RXCIE0 RXCIE1
#define UDRIE0 UDRIE1
#define U2X0 U2X1
#define UPE0 UPE1
#define UDRE0 UDRE1
#else
#error No UART found in HardwareSerial.cpp
#endif
#endif // !defined TXC0

// Check at compiletime that it is really ok to use the bit positions of
// UART0 for the other UARTs as well, in case these values ever get
// changed for future hardware.
#if defined(TXC1) && (TXC1 != TXC0 || RXEN1 != RXEN0 || RXCIE1 != RXCIE0 || \
		      UDRIE1 != UDRIE0 || U2X1 != U2X0 || UPE1 != UPE0 || \
		      UDRE1 != UDRE0)
#error "Not all bit positions for UART1 are the same as for UART0"
#endif
#if defined(TXC2) && (TXC2 != TXC0 || RXEN2 != RXEN0 || RXCIE2 != RXCIE0 || \
		      UDRIE2 != UDRIE0 || U2X2 != U2X0 || UPE2 != UPE0 || \
		      UDRE2 != UDRE0)
#error "Not all bit positions for UART2 are the same as for UART0"
#endif
#if defined(TXC3) && (TXC3 != TXC0 || RXEN3 != RXEN0 || RXCIE3 != RXCIE0 || \
		      UDRIE3 != UDRIE0 || U3X3 != U3X0 || UPE3 != UPE0 || \
		      UDRE3 != UDRE0)
#error "Not all bit positions for UART3 are the same as for UART0"
#endif

#if !defined(USART0_RX_vect) && defined(USART1_RX_vect)
// do nothing - on the 32u4 the first USART is USART1
#else
#if !defined(USART_RX_vect) && !defined(USART0_RX_vect) && \
    !defined(USART_RXC_vect)
  #error "Don't know what the Data Received vector is called for the first UART"
#else
  void serialEvent() __attribute__((weak));
  void serialEvent() {}
  #define serialEvent_implemented
#if defined(USART_RX_vect)
  ISR(USART_RX_vect)
#elif defined(USART0_RX_vect)
  ISR(USART0_RX_vect)
#elif defined(USART_RXC_vect)
  ISR(USART_RXC_vect) // ATmega8
#endif
  {
    Serial._rx_complete_irq();
  }
#endif
#endif

#if defined(USART1_RX_vect)
  void serialEvent1() __attribute__((weak));
  void serialEvent1() {}
  #define serialEvent1_implemented
  ISR(USART1_RX_vect)
  {
    Serial1._rx_complete_irq();
  }
#endif

#if defined(USART2_RX_vect) && defined(UDR2)
  void serialEvent2() __attribute__((weak));
  void serialEvent2() {}
  #define serialEvent2_implemented
  ISR(USART2_RX_vect)
  {
    Serial2._rx_complete_irq();
  }
#endif

#if defined(USART3_RX_vect) && defined(UDR3)
  void serialEvent3() __attribute__((weak));
  void serialEvent3() {}
  #define serialEvent3_implemented
  ISR(USART3_RX_vect)
  {
    Serial3._rx_complete_irq();
  }
#endif

void serialEventRun(void)
{
#ifdef serialEvent_implemented
  if (Serial.available()) serialEvent();
#endif
#ifdef serialEvent1_implemented
  if (Serial1.available()) serialEvent1();
#endif
#ifdef serialEvent2_implemented
  if (Serial2.available()) serialEvent2();
#endif
#ifdef serialEvent3_implemented
  if (Serial3.available()) serialEvent3();
#endif
}

#if !defined(USART0_UDRE_vect) && defined(USART1_UDRE_vect)
// do nothing - on the 32u4 the first USART is USART1
#else
#if !defined(UART0_UDRE_vect) && !defined(UART_UDRE_vect) && !defined(USART0_UDRE_vect) && !defined(USART_UDRE_vect)
  #error "Don't know what the Data Register Empty vector is called for the first UART"
#else
#if defined(UART0_UDRE_vect)
ISR(UART0_UDRE_vect)
#elif defined(UART_UDRE_vect)
ISR(UART_UDRE_vect)
#elif defined(USART0_UDRE_vect)
ISR(USART0_UDRE_vect)
#elif defined(USART_UDRE_vect)
ISR(USART_UDRE_vect)
#endif
{
  Serial._tx_udr_empty_irq();
}
#endif
#endif

#ifdef USART1_UDRE_vect
ISR(USART1_UDRE_vect)
{
  Serial1._tx_udr_empty_irq();
}
#endif

#ifdef USART2_UDRE_vect
ISR(USART2_UDRE_vect)
{
  Serial2._tx_udr_empty_irq();
}
#endif

#ifdef USART3_UDRE_vect
ISR(USART3_UDRE_vect)
{
  Serial3._tx_udr_empty_irq();
}
#endif

// Actual interrupt handlers //////////////////////////////////////////////////////////////

void HardwareSerial::_rx_complete_irq(void)
{
  if (bit_is_clear(*_ucsra, UPE0)) {
    // No Parity error, read byte and store it in the buffer if there is
    // room
    unsigned char c = *_udr;
    int i = (unsigned int)(_rx_buffer_head + 1) % SERIAL_BUFFER_SIZE;

    // if we should be storing the received character into the location
    // just before the tail (meaning that the head would advance to the
    // current location of the tail), we're about to overflow the buffer
    // and so we don't write the character or advance the head.
    if (i != _rx_buffer_tail) {
      _rx_buffer[_rx_buffer_head] = c;
      _rx_buffer_head = i;
    }
  } else {
    // Parity error, read byte but discard it
    unsigned char c = *_udr;
  };
}

void HardwareSerial::_tx_udr_empty_irq(void)
{
  if (_tx_buffer_head == _tx_buffer_tail) {
    // Buffer empty, so disable interrupts
    cbi(*_ucsrb, UDRIE0);
  }
  else {
    // There is more data in the output buffer. Send the next byte
    unsigned char c = _tx_buffer[_tx_buffer_tail];
    _tx_buffer_tail = (_tx_buffer_tail + 1) % SERIAL_BUFFER_SIZE;

    *_udr = c;
  }
}

// Constructors ////////////////////////////////////////////////////////////////

HardwareSerial::HardwareSerial(
  volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
  volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
  volatile uint8_t *ucsrc, volatile uint8_t *udr)
{
  _tx_buffer_head = _tx_buffer_tail = 0;
  _rx_buffer_head = _rx_buffer_tail = 0;
  _ubrrh = ubrrh;
  _ubrrl = ubrrl;
  _ucsra = ucsra;
  _ucsrb = ucsrb;
  _ucsrc = ucsrc;
  _udr = udr;
}

// Public Methods //////////////////////////////////////////////////////////////

void HardwareSerial::begin(unsigned long baud, byte config)
{
  // Try u2x mode first
  uint16_t baud_setting = (F_CPU / 4 / baud - 1) / 2;
  *_ucsra = 1 << U2X0;

  // hardcoded exception for 57600 for compatibility with the bootloader
  // shipped with the Duemilanove and previous boards and the firmware
  // on the 8U2 on the Uno and Mega 2560. Also, The baud_setting cannot
  // be > 4095, so switch back to non-u2x mode if the baud rate is too
  // low.
  if (((F_CPU == 16000000UL) && (baud == 57600)) || (baud_setting >4095))
  {
    *_ucsra = 0;
    baud_setting = (F_CPU / 8 / baud - 1) / 2;
  }

  // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
  *_ubrrh = baud_setting >> 8;
  *_ubrrl = baud_setting;

  //set the data bits, parity, and stop bits
#if defined(__AVR_ATmega8__)
  config |= 0x80; // select UCSRC register (shared with UBRRH)
#endif
  *_ucsrc = config;

  sbi(*_ucsrb, RXEN0);
  sbi(*_ucsrb, TXEN0);
  sbi(*_ucsrb, RXCIE0);
  cbi(*_ucsrb, UDRIE0);
}

void HardwareSerial::end()
{
  // wait for transmission of outgoing data
  while (_tx_buffer_head != _tx_buffer_tail)
    ;

  cbi(*_ucsrb, RXEN0);
  cbi(*_ucsrb, TXEN0);
  cbi(*_ucsrb, RXCIE0);
  cbi(*_ucsrb, UDRIE0);

  // clear any received data
  _rx_buffer_head = _rx_buffer_tail;
}

int HardwareSerial::available(void)
{
  return (unsigned int)(SERIAL_BUFFER_SIZE + _rx_buffer_head - _rx_buffer_tail) % SERIAL_BUFFER_SIZE;
}

int HardwareSerial::peek(void)
{
  if (_rx_buffer_head == _rx_buffer_tail) {
    return -1;
  } else {
    return _rx_buffer[_rx_buffer_tail];
  }
}

int HardwareSerial::read(void)
{
  // if the head isn't ahead of the tail, we don't have any characters
  if (_rx_buffer_head == _rx_buffer_tail) {
    return -1;
  } else {
    unsigned char c = _rx_buffer[_rx_buffer_tail];
    _rx_buffer_tail = (unsigned int)(_rx_buffer_tail + 1) % SERIAL_BUFFER_SIZE;
    return c;
  }
}

void HardwareSerial::flush()
{
  // UDR is kept full while the buffer is not empty, so TXC triggers when EMPTY && SENT
  while (transmitting && ! (*_ucsra & _BV(TXC0)));
  transmitting = false;
}

size_t HardwareSerial::write(uint8_t c)
{
  int i = (_tx_buffer_head + 1) % SERIAL_BUFFER_SIZE;

  // If the output buffer is full, there's nothing for it other than to
  // wait for the interrupt handler to empty it a bit
  // ???: return 0 here instead?
  while (i == _tx_buffer_tail)
    ;

  _tx_buffer[_tx_buffer_head] = c;
  _tx_buffer_head = i;

  sbi(*_ucsrb, UDRIE0);
  // clear the TXC bit -- "can be cleared by writing a one to its bit location"
  transmitting = true;
  sbi(*_ucsra, TXC0);

  return 1;
}

// Preinstantiate Objects //////////////////////////////////////////////////////

#if defined(UBRRH) && defined(UBRRL)
  HardwareSerial Serial(&UBRRH, &UBRRL, &UCSRA, &UCSRB, &UCSRC, &UDR);
#elif defined(UBRR0H) && defined(UBRR0L)
  HardwareSerial Serial(&UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UCSR0C, &UDR0);
#elif defined(USBCON)
  // do nothing - Serial object and buffers are initialized in CDC code
#else
  #error no serial port defined  (port 0)
#endif

#if defined(UBRR1H)
  HardwareSerial Serial1(&UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UCSR1C, &UDR1);
#endif
#if defined(UBRR2H)
  HardwareSerial Serial2(&UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UCSR2C, &UDR2);
#endif
#if defined(UBRR3H)
  HardwareSerial Serial3(&UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UCSR3C, &UDR3);
#endif

#endif // whole file

<commit_msg>Use bit_is_clear in HardwareSerial::flush()<commit_after>/*
  HardwareSerial.cpp - Hardware serial library for 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 23 November 2006 by David A. Mellis
  Modified 28 September 2010 by Mark Sproul
  Modified 14 August 2012 by Alarus
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "Arduino.h"
#include "wiring_private.h"

// this next line disables the entire HardwareSerial.cpp,
// this is so I can support Attiny series and any other chip without a uart
#if defined(UBRRH) || defined(UBRR0H) || defined(UBRR1H) || defined(UBRR2H) || defined(UBRR3H)

#include "HardwareSerial.h"

// Ensure that the various bit positions we use are available with a 0
// postfix, so we can always use the values for UART0 for all UARTs. The
// alternative, passing the various values for each UART to the
// HardwareSerial constructor also works, but makes the code bigger and
// slower.
#if !defined(TXC0)
#if defined(TXC)
// On ATmega8, the uart and its bits are not numbered, so there is no TXC0 etc.
#define TXC0 TXC
#define RXEN0 RXEN
#define TXEN0 TXEN
#define RXCIE0 RXCIE
#define UDRIE0 UDRIE
#define U2X0 U2X
#define UPE0 UPE
#define UDRE0 UDRE
#elif defined(TXC1)
// Some devices have uart1 but no uart0
#define TXC0 TXC1
#define RXEN0 RXEN1
#define TXEN0 TXEN1
#define RXCIE0 RXCIE1
#define UDRIE0 UDRIE1
#define U2X0 U2X1
#define UPE0 UPE1
#define UDRE0 UDRE1
#else
#error No UART found in HardwareSerial.cpp
#endif
#endif // !defined TXC0

// Check at compiletime that it is really ok to use the bit positions of
// UART0 for the other UARTs as well, in case these values ever get
// changed for future hardware.
#if defined(TXC1) && (TXC1 != TXC0 || RXEN1 != RXEN0 || RXCIE1 != RXCIE0 || \
		      UDRIE1 != UDRIE0 || U2X1 != U2X0 || UPE1 != UPE0 || \
		      UDRE1 != UDRE0)
#error "Not all bit positions for UART1 are the same as for UART0"
#endif
#if defined(TXC2) && (TXC2 != TXC0 || RXEN2 != RXEN0 || RXCIE2 != RXCIE0 || \
		      UDRIE2 != UDRIE0 || U2X2 != U2X0 || UPE2 != UPE0 || \
		      UDRE2 != UDRE0)
#error "Not all bit positions for UART2 are the same as for UART0"
#endif
#if defined(TXC3) && (TXC3 != TXC0 || RXEN3 != RXEN0 || RXCIE3 != RXCIE0 || \
		      UDRIE3 != UDRIE0 || U3X3 != U3X0 || UPE3 != UPE0 || \
		      UDRE3 != UDRE0)
#error "Not all bit positions for UART3 are the same as for UART0"
#endif

#if !defined(USART0_RX_vect) && defined(USART1_RX_vect)
// do nothing - on the 32u4 the first USART is USART1
#else
#if !defined(USART_RX_vect) && !defined(USART0_RX_vect) && \
    !defined(USART_RXC_vect)
  #error "Don't know what the Data Received vector is called for the first UART"
#else
  void serialEvent() __attribute__((weak));
  void serialEvent() {}
  #define serialEvent_implemented
#if defined(USART_RX_vect)
  ISR(USART_RX_vect)
#elif defined(USART0_RX_vect)
  ISR(USART0_RX_vect)
#elif defined(USART_RXC_vect)
  ISR(USART_RXC_vect) // ATmega8
#endif
  {
    Serial._rx_complete_irq();
  }
#endif
#endif

#if defined(USART1_RX_vect)
  void serialEvent1() __attribute__((weak));
  void serialEvent1() {}
  #define serialEvent1_implemented
  ISR(USART1_RX_vect)
  {
    Serial1._rx_complete_irq();
  }
#endif

#if defined(USART2_RX_vect) && defined(UDR2)
  void serialEvent2() __attribute__((weak));
  void serialEvent2() {}
  #define serialEvent2_implemented
  ISR(USART2_RX_vect)
  {
    Serial2._rx_complete_irq();
  }
#endif

#if defined(USART3_RX_vect) && defined(UDR3)
  void serialEvent3() __attribute__((weak));
  void serialEvent3() {}
  #define serialEvent3_implemented
  ISR(USART3_RX_vect)
  {
    Serial3._rx_complete_irq();
  }
#endif

void serialEventRun(void)
{
#ifdef serialEvent_implemented
  if (Serial.available()) serialEvent();
#endif
#ifdef serialEvent1_implemented
  if (Serial1.available()) serialEvent1();
#endif
#ifdef serialEvent2_implemented
  if (Serial2.available()) serialEvent2();
#endif
#ifdef serialEvent3_implemented
  if (Serial3.available()) serialEvent3();
#endif
}

#if !defined(USART0_UDRE_vect) && defined(USART1_UDRE_vect)
// do nothing - on the 32u4 the first USART is USART1
#else
#if !defined(UART0_UDRE_vect) && !defined(UART_UDRE_vect) && !defined(USART0_UDRE_vect) && !defined(USART_UDRE_vect)
  #error "Don't know what the Data Register Empty vector is called for the first UART"
#else
#if defined(UART0_UDRE_vect)
ISR(UART0_UDRE_vect)
#elif defined(UART_UDRE_vect)
ISR(UART_UDRE_vect)
#elif defined(USART0_UDRE_vect)
ISR(USART0_UDRE_vect)
#elif defined(USART_UDRE_vect)
ISR(USART_UDRE_vect)
#endif
{
  Serial._tx_udr_empty_irq();
}
#endif
#endif

#ifdef USART1_UDRE_vect
ISR(USART1_UDRE_vect)
{
  Serial1._tx_udr_empty_irq();
}
#endif

#ifdef USART2_UDRE_vect
ISR(USART2_UDRE_vect)
{
  Serial2._tx_udr_empty_irq();
}
#endif

#ifdef USART3_UDRE_vect
ISR(USART3_UDRE_vect)
{
  Serial3._tx_udr_empty_irq();
}
#endif

// Actual interrupt handlers //////////////////////////////////////////////////////////////

void HardwareSerial::_rx_complete_irq(void)
{
  if (bit_is_clear(*_ucsra, UPE0)) {
    // No Parity error, read byte and store it in the buffer if there is
    // room
    unsigned char c = *_udr;
    int i = (unsigned int)(_rx_buffer_head + 1) % SERIAL_BUFFER_SIZE;

    // if we should be storing the received character into the location
    // just before the tail (meaning that the head would advance to the
    // current location of the tail), we're about to overflow the buffer
    // and so we don't write the character or advance the head.
    if (i != _rx_buffer_tail) {
      _rx_buffer[_rx_buffer_head] = c;
      _rx_buffer_head = i;
    }
  } else {
    // Parity error, read byte but discard it
    unsigned char c = *_udr;
  };
}

void HardwareSerial::_tx_udr_empty_irq(void)
{
  if (_tx_buffer_head == _tx_buffer_tail) {
    // Buffer empty, so disable interrupts
    cbi(*_ucsrb, UDRIE0);
  }
  else {
    // There is more data in the output buffer. Send the next byte
    unsigned char c = _tx_buffer[_tx_buffer_tail];
    _tx_buffer_tail = (_tx_buffer_tail + 1) % SERIAL_BUFFER_SIZE;

    *_udr = c;
  }
}

// Constructors ////////////////////////////////////////////////////////////////

HardwareSerial::HardwareSerial(
  volatile uint8_t *ubrrh, volatile uint8_t *ubrrl,
  volatile uint8_t *ucsra, volatile uint8_t *ucsrb,
  volatile uint8_t *ucsrc, volatile uint8_t *udr)
{
  _tx_buffer_head = _tx_buffer_tail = 0;
  _rx_buffer_head = _rx_buffer_tail = 0;
  _ubrrh = ubrrh;
  _ubrrl = ubrrl;
  _ucsra = ucsra;
  _ucsrb = ucsrb;
  _ucsrc = ucsrc;
  _udr = udr;
}

// Public Methods //////////////////////////////////////////////////////////////

void HardwareSerial::begin(unsigned long baud, byte config)
{
  // Try u2x mode first
  uint16_t baud_setting = (F_CPU / 4 / baud - 1) / 2;
  *_ucsra = 1 << U2X0;

  // hardcoded exception for 57600 for compatibility with the bootloader
  // shipped with the Duemilanove and previous boards and the firmware
  // on the 8U2 on the Uno and Mega 2560. Also, The baud_setting cannot
  // be > 4095, so switch back to non-u2x mode if the baud rate is too
  // low.
  if (((F_CPU == 16000000UL) && (baud == 57600)) || (baud_setting >4095))
  {
    *_ucsra = 0;
    baud_setting = (F_CPU / 8 / baud - 1) / 2;
  }

  // assign the baud_setting, a.k.a. ubbr (USART Baud Rate Register)
  *_ubrrh = baud_setting >> 8;
  *_ubrrl = baud_setting;

  //set the data bits, parity, and stop bits
#if defined(__AVR_ATmega8__)
  config |= 0x80; // select UCSRC register (shared with UBRRH)
#endif
  *_ucsrc = config;

  sbi(*_ucsrb, RXEN0);
  sbi(*_ucsrb, TXEN0);
  sbi(*_ucsrb, RXCIE0);
  cbi(*_ucsrb, UDRIE0);
}

void HardwareSerial::end()
{
  // wait for transmission of outgoing data
  while (_tx_buffer_head != _tx_buffer_tail)
    ;

  cbi(*_ucsrb, RXEN0);
  cbi(*_ucsrb, TXEN0);
  cbi(*_ucsrb, RXCIE0);
  cbi(*_ucsrb, UDRIE0);

  // clear any received data
  _rx_buffer_head = _rx_buffer_tail;
}

int HardwareSerial::available(void)
{
  return (unsigned int)(SERIAL_BUFFER_SIZE + _rx_buffer_head - _rx_buffer_tail) % SERIAL_BUFFER_SIZE;
}

int HardwareSerial::peek(void)
{
  if (_rx_buffer_head == _rx_buffer_tail) {
    return -1;
  } else {
    return _rx_buffer[_rx_buffer_tail];
  }
}

int HardwareSerial::read(void)
{
  // if the head isn't ahead of the tail, we don't have any characters
  if (_rx_buffer_head == _rx_buffer_tail) {
    return -1;
  } else {
    unsigned char c = _rx_buffer[_rx_buffer_tail];
    _rx_buffer_tail = (unsigned int)(_rx_buffer_tail + 1) % SERIAL_BUFFER_SIZE;
    return c;
  }
}

void HardwareSerial::flush()
{
  // UDR is kept full while the buffer is not empty, so TXC triggers when EMPTY && SENT
  while (transmitting && bit_is_clear(*_ucsra, TXC0));
  transmitting = false;
}

size_t HardwareSerial::write(uint8_t c)
{
  int i = (_tx_buffer_head + 1) % SERIAL_BUFFER_SIZE;

  // If the output buffer is full, there's nothing for it other than to
  // wait for the interrupt handler to empty it a bit
  // ???: return 0 here instead?
  while (i == _tx_buffer_tail)
    ;

  _tx_buffer[_tx_buffer_head] = c;
  _tx_buffer_head = i;

  sbi(*_ucsrb, UDRIE0);
  // clear the TXC bit -- "can be cleared by writing a one to its bit location"
  transmitting = true;
  sbi(*_ucsra, TXC0);

  return 1;
}

// Preinstantiate Objects //////////////////////////////////////////////////////

#if defined(UBRRH) && defined(UBRRL)
  HardwareSerial Serial(&UBRRH, &UBRRL, &UCSRA, &UCSRB, &UCSRC, &UDR);
#elif defined(UBRR0H) && defined(UBRR0L)
  HardwareSerial Serial(&UBRR0H, &UBRR0L, &UCSR0A, &UCSR0B, &UCSR0C, &UDR0);
#elif defined(USBCON)
  // do nothing - Serial object and buffers are initialized in CDC code
#else
  #error no serial port defined  (port 0)
#endif

#if defined(UBRR1H)
  HardwareSerial Serial1(&UBRR1H, &UBRR1L, &UCSR1A, &UCSR1B, &UCSR1C, &UDR1);
#endif
#if defined(UBRR2H)
  HardwareSerial Serial2(&UBRR2H, &UBRR2L, &UCSR2A, &UCSR2B, &UCSR2C, &UDR2);
#endif
#if defined(UBRR3H)
  HardwareSerial Serial3(&UBRR3H, &UBRR3L, &UCSR3A, &UCSR3B, &UCSR3C, &UDR3);
#endif

#endif // whole file

<|endoftext|>


<commit_before>/*
    This file is part of Akregator.

    Copyright (C) 2004 Sashmit Bhaduri <smt@vfemail.net>

    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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include "tabwidget.h"

#include <QStyle>
#include <QApplication>
#include <QIcon>
#include <QClipboard>
#include <QHash>
#include <QString>
#include <QPushButton>

#include <QMenu>
#include <QStyleOption>

#include <kapplication.h>
#include <kdebug.h>
#include <ktabwidget.h>
#include <ktabbar.h>
#include <kmenu.h>
#include <krun.h>
#include <klocale.h>
#include <khtmlview.h>
#include <khtml_part.h>
#include <kiconloader.h>
#include <ktoolinvocation.h>
#include <kurl.h>
#include <kmimetype.h>
#include <kio/global.h>

#include "actionmanager.h"
#include "akregatorconfig.h"
#include "frame.h"
#include "framemanager.h"
#include "kernel.h"
#include "openurlrequest.h"

#include <cassert>

namespace Akregator {

class TabWidget::Private
{
private:
    TabWidget* const q;

public:
    explicit Private( TabWidget * qq ) : q( qq ) {}

    TabWidget* parent;
    QHash<QWidget*, Frame*> frames;
    QHash<int, Frame*> framesById;
    int currentMaxLength;
    QWidget* currentItem;
    QPushButton* tabsClose;

    uint tabBarWidthForMaxChars(int maxLength);
    void setTitle(const QString &title , QWidget* sender);
    void updateTabBarVisibility();
    Frame* currentFrame();
};

void TabWidget::Private::updateTabBarVisibility()
{
    q->setTabBarHidden( q->count() <= 1 );
}

TabWidget::TabWidget(QWidget * parent)
    :KTabWidget(parent), d(new Private( this ) )
{
    d->parent = this;
    d->currentMaxLength = 30;
    setMinimumSize(250,150);
    setTabReorderingEnabled(false);
    connect( this, SIGNAL( currentChanged(QWidget *) ),
             this, SLOT( slotTabChanged(QWidget *) ) );
    connect(this, SIGNAL(closeRequest(QWidget*)),
            this, SLOT(slotCloseRequest(QWidget*)));
    setHoverCloseButton(Settings::closeButtonOnTabs());

    d->tabsClose = new QPushButton(this);
    d->tabsClose->setShortcut(QKeySequence("Ctrl+W"));
    connect( d->tabsClose, SIGNAL( clicked() ), this,
            SLOT( slotRemoveCurrentFrame() ) );

    d->tabsClose->setIcon( KIcon( "tab-close" ) );
    d->tabsClose->setEnabled( false );
    d->tabsClose->adjustSize();
    d->tabsClose->setToolTip( i18n("Close the current tab"));
    setCornerWidget( d->tabsClose, Qt::TopRightCorner );
    setTabBarHidden( true );
}

TabWidget::~TabWidget()
{
    delete d;
}

void TabWidget::slotSettingsChanged()
{
    if (hoverCloseButton() != Settings::closeButtonOnTabs())
        setHoverCloseButton(Settings::closeButtonOnTabs());
}

void TabWidget::slotNextTab()
{
    setCurrentIndex((currentIndex()+1) % count());
}

void TabWidget::slotPreviousTab()
{
    if (currentIndex() == 0)
        setCurrentIndex(count()-1);
    else
        setCurrentIndex(currentIndex()-1);
}
void TabWidget::slotSelectFrame(int frameId)
{
    Frame* frame = d->framesById[frameId];
    if (frame && frame != d->currentFrame())
    {
        setCurrentWidget(frame);
        if (frame->part() && frame->part()->widget())
        {
            frame->part()->widget()->setFocus();
        }
        else
        {
            frame->setFocus();
        }
    }
}

void TabWidget::slotAddFrame(Frame* frame)
{
    if (!frame)
        return;
    d->frames.insert(frame, frame);
    d->framesById[frame->id()] = frame;
    addTab(frame, frame->title());
    connect(frame, SIGNAL(signalTitleChanged(Akregator::Frame*, const QString& )),
            this, SLOT(slotSetTitle(Akregator::Frame*, const QString& )));
    slotSetTitle(frame, frame->title());
}

Frame * TabWidget::Private::currentFrame()
{
    QWidget* w = q->currentWidget();
    assert( frames[w] );
    return w ? frames[w] : 0;
}

void TabWidget::slotTabChanged(QWidget *w)
{
    Frame* frame = d->frames[w];
    d->tabsClose->setEnabled(frame && frame->isRemovable());
    emit signalCurrentFrameChanged(frame ? frame->id() : -1);
}

void TabWidget::tabInserted( int )
{
    d->updateTabBarVisibility();
}

void TabWidget::tabRemoved( int )
{
    d->updateTabBarVisibility();
}

void TabWidget::slotRemoveCurrentFrame()
{
    Frame* const frame = d->currentFrame();
    if (frame)
        emit signalRemoveFrameRequest(frame->id());
}

void TabWidget::slotRemoveFrame(int frameId)
{
    if (!d->framesById.contains(frameId))
        return;
    Frame* f = d->framesById[frameId];
    d->frames.remove(f);
    d->framesById.remove(frameId);
    slotPreviousTab();
    removeTab(indexOf(f));
    if (d->currentFrame())
      d->setTitle( d->currentFrame()->title(), currentWidget() );
}

// copied wholesale from KonqFrameTabs
uint TabWidget::Private::tabBarWidthForMaxChars( int maxLength )
{
    int hframe, overlap;
    QStyleOption o;
    hframe = parent->tabBar()->style()->pixelMetric( QStyle::PM_TabBarTabHSpace, &o, parent );
    overlap = parent->tabBar()->style()->pixelMetric( QStyle::PM_TabBarTabOverlap, &o, parent );

    QFontMetrics fm = parent->tabBar()->fontMetrics();
    int x = 0;
    for (int i = 0; i < parent->count(); ++i)
    {
        Frame* f = frames[parent->widget(i)];
        QString newTitle = f->title();
        if ( newTitle.length() > maxLength )
            newTitle = newTitle.left( maxLength-3 ) + "...";

        int lw = fm.width( newTitle );
        int iw = parent->tabBar()->tabIcon( i ).pixmap( parent->tabBar()->style()->pixelMetric(
QStyle::PM_SmallIconSize ), QIcon::Normal
).width() + 4;

        x += ( parent->tabBar()->style()->sizeFromContents( QStyle::CT_TabBarTab, &o,
               QSize( qMax( lw + hframe + iw, QApplication::globalStrut().width() ), 0 ), parent ) ).width();
    }
    return x;
}

void TabWidget::slotSetTitle(Frame* frame, const QString& title)
{
    d->setTitle(title, frame);
}

void TabWidget::Private::setTitle( const QString &title, QWidget* sender)
{
    int senderIndex = parent->indexOf(sender);

    parent->setTabToolTip( senderIndex, QString() );

    uint lcw=0, rcw=0;
    int tabBarHeight = parent->tabBar()->sizeHint().height();

    QWidget* leftCorner = parent->cornerWidget( Qt::TopLeftCorner );

    if ( leftCorner  && leftCorner->isVisible() )
        lcw = qMax( leftCorner->width(), tabBarHeight );

    QWidget* rightCorner = parent->cornerWidget( Qt::TopRightCorner );

    if ( rightCorner && rightCorner->isVisible() )
        rcw = qMax( rightCorner->width(), tabBarHeight );
    uint maxTabBarWidth = parent->width() - lcw - rcw;

    int newMaxLength = 30;

    for ( ; newMaxLength > 3; newMaxLength-- )
    {
        if ( tabBarWidthForMaxChars( newMaxLength ) < maxTabBarWidth )
            break;
    }

    QString newTitle = title;
    if ( newTitle.length() > newMaxLength )
    {
        parent->setTabToolTip( senderIndex, newTitle );
        newTitle = newTitle.left( newMaxLength-3 ) + "...";
    }

    newTitle.replace( '&', "&&" );

    if ( parent->tabText(senderIndex) != newTitle )
        parent->setTabText( senderIndex, newTitle );

    if( newMaxLength != currentMaxLength )
    {
        for( int i = 0; i < parent->count(); ++i)
        {
            Frame* f = frames[parent->widget(i)];
            newTitle = f->title();
            int index = parent->indexOf(parent->widget( i ));
            parent->setTabToolTip( index, QString() );

            if ( newTitle.length() > newMaxLength )
            {
                parent->setTabToolTip( index, newTitle );
                newTitle = newTitle.left( newMaxLength-3 ) + "...";
            }

            newTitle.replace( '&', "&&" );
            if ( newTitle != parent->tabText( index ) )
                parent->setTabText( index, newTitle );
        }
        currentMaxLength = newMaxLength;
    }
}

void TabWidget::contextMenu(int i, const QPoint &p)
{
    QWidget* w = ActionManager::getInstance()->container("tab_popup");
    d->currentItem = widget(i);
    //kDebug() << indexOf(d->currentItem);
    // FIXME: do not hardcode index of maintab
    if (w && indexOf(d->currentItem) != 0)
        static_cast<QMenu *>(w)->exec(p);
    d->currentItem = 0;
}

void TabWidget::slotDetachTab()
{
    if (!d->currentItem || indexOf(d->currentItem) == -1)
        d->currentItem = currentWidget();

    Frame* frame = d->frames[d->currentItem];

    if (frame && frame->url().isValid() && frame->isRemovable())
    {
        OpenUrlRequest request;
        request.setUrl(frame->url());
        request.setOptions(OpenUrlRequest::ExternalBrowser);
        emit signalOpenUrlRequest(request);
        slotCloseTab();
    }
}

void TabWidget::slotCopyLinkAddress()
{
    if(!d->currentItem || indexOf(d->currentItem) == -1)
        d->currentItem = currentWidget();
    Frame* frame = d->frames[d->currentItem];

    if (frame && frame->url().isValid())
    {
        KUrl url = frame->url();
        // don't set url to selection as it's a no-no according to a fd.o spec
        //kapp->clipboard()->setText(url.prettyUrl(), QClipboard::Selection);
        kapp->clipboard()->setText(url.prettyUrl(), QClipboard::Clipboard);
    }
}

void TabWidget::slotCloseTab()
{
    if (!d->currentItem || indexOf(d->currentItem) == -1)
        d->currentItem = currentWidget();
    if (d->frames[d->currentItem] == 0 || !d->frames[d->currentItem]->isRemovable() )
        return;

    emit signalRemoveFrameRequest(d->frames[d->currentItem]->id());
}

void TabWidget::initiateDrag(int tab)
{
    Frame* frame = d->frames[widget(tab)];

    if (frame && frame->url().isValid())
    {
        KUrl::List lst;
        lst.append( frame->url() );
        QDrag* drag = new QDrag( this );
        QMimeData *md = new QMimeData;
        drag->setMimeData( md );
        lst.populateMimeData( md );
        drag->setPixmap( KIO::pixmapForUrl( lst.first(), 0, KIconLoader::Small ) );
        drag->start();
    }
}

void TabWidget::slotCloseRequest(QWidget* widget)
{
    if (d->frames[widget])
        emit signalRemoveFrameRequest(d->frames[widget]->id());
}

} // namespace Akregator

#include "tabwidget.moc"
<commit_msg>behave like a normal tabwidget, ie. don't move to the previous tab when closing the current<commit_after>/*
    This file is part of Akregator.

    Copyright (C) 2004 Sashmit Bhaduri <smt@vfemail.net>

    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 2 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include "tabwidget.h"

#include <QStyle>
#include <QApplication>
#include <QIcon>
#include <QClipboard>
#include <QHash>
#include <QString>
#include <QPushButton>

#include <QMenu>
#include <QStyleOption>

#include <kapplication.h>
#include <kdebug.h>
#include <ktabwidget.h>
#include <ktabbar.h>
#include <kmenu.h>
#include <krun.h>
#include <klocale.h>
#include <khtmlview.h>
#include <khtml_part.h>
#include <kiconloader.h>
#include <ktoolinvocation.h>
#include <kurl.h>
#include <kmimetype.h>
#include <kio/global.h>

#include "actionmanager.h"
#include "akregatorconfig.h"
#include "frame.h"
#include "framemanager.h"
#include "kernel.h"
#include "openurlrequest.h"

#include <cassert>

namespace Akregator {

class TabWidget::Private
{
private:
    TabWidget* const q;

public:
    explicit Private( TabWidget * qq ) : q( qq ) {}

    TabWidget* parent;
    QHash<QWidget*, Frame*> frames;
    QHash<int, Frame*> framesById;
    int currentMaxLength;
    QWidget* currentItem;
    QPushButton* tabsClose;

    uint tabBarWidthForMaxChars(int maxLength);
    void setTitle(const QString &title , QWidget* sender);
    void updateTabBarVisibility();
    Frame* currentFrame();
};

void TabWidget::Private::updateTabBarVisibility()
{
    q->setTabBarHidden( q->count() <= 1 );
}

TabWidget::TabWidget(QWidget * parent)
    :KTabWidget(parent), d(new Private( this ) )
{
    d->parent = this;
    d->currentMaxLength = 30;
    setMinimumSize(250,150);
    setTabReorderingEnabled(false);
    connect( this, SIGNAL( currentChanged(QWidget *) ),
             this, SLOT( slotTabChanged(QWidget *) ) );
    connect(this, SIGNAL(closeRequest(QWidget*)),
            this, SLOT(slotCloseRequest(QWidget*)));
    setHoverCloseButton(Settings::closeButtonOnTabs());

    d->tabsClose = new QPushButton(this);
    d->tabsClose->setShortcut(QKeySequence("Ctrl+W"));
    connect( d->tabsClose, SIGNAL( clicked() ), this,
            SLOT( slotRemoveCurrentFrame() ) );

    d->tabsClose->setIcon( KIcon( "tab-close" ) );
    d->tabsClose->setEnabled( false );
    d->tabsClose->adjustSize();
    d->tabsClose->setToolTip( i18n("Close the current tab"));
    setCornerWidget( d->tabsClose, Qt::TopRightCorner );
    setTabBarHidden( true );
}

TabWidget::~TabWidget()
{
    delete d;
}

void TabWidget::slotSettingsChanged()
{
    if (hoverCloseButton() != Settings::closeButtonOnTabs())
        setHoverCloseButton(Settings::closeButtonOnTabs());
}

void TabWidget::slotNextTab()
{
    setCurrentIndex((currentIndex()+1) % count());
}

void TabWidget::slotPreviousTab()
{
    if (currentIndex() == 0)
        setCurrentIndex(count()-1);
    else
        setCurrentIndex(currentIndex()-1);
}
void TabWidget::slotSelectFrame(int frameId)
{
    Frame* frame = d->framesById[frameId];
    if (frame && frame != d->currentFrame())
    {
        setCurrentWidget(frame);
        if (frame->part() && frame->part()->widget())
        {
            frame->part()->widget()->setFocus();
        }
        else
        {
            frame->setFocus();
        }
    }
}

void TabWidget::slotAddFrame(Frame* frame)
{
    if (!frame)
        return;
    d->frames.insert(frame, frame);
    d->framesById[frame->id()] = frame;
    addTab(frame, frame->title());
    connect(frame, SIGNAL(signalTitleChanged(Akregator::Frame*, const QString& )),
            this, SLOT(slotSetTitle(Akregator::Frame*, const QString& )));
    slotSetTitle(frame, frame->title());
}

Frame * TabWidget::Private::currentFrame()
{
    QWidget* w = q->currentWidget();
    assert( frames[w] );
    return w ? frames[w] : 0;
}

void TabWidget::slotTabChanged(QWidget *w)
{
    Frame* frame = d->frames[w];
    d->tabsClose->setEnabled(frame && frame->isRemovable());
    emit signalCurrentFrameChanged(frame ? frame->id() : -1);
}

void TabWidget::tabInserted( int )
{
    d->updateTabBarVisibility();
}

void TabWidget::tabRemoved( int )
{
    d->updateTabBarVisibility();
}

void TabWidget::slotRemoveCurrentFrame()
{
    Frame* const frame = d->currentFrame();
    if (frame)
        emit signalRemoveFrameRequest(frame->id());
}

void TabWidget::slotRemoveFrame(int frameId)
{
    if (!d->framesById.contains(frameId))
        return;
    Frame* f = d->framesById[frameId];
    d->frames.remove(f);
    d->framesById.remove(frameId);
    removeTab(indexOf(f));
    if (d->currentFrame())
      d->setTitle( d->currentFrame()->title(), currentWidget() );
}

// copied wholesale from KonqFrameTabs
uint TabWidget::Private::tabBarWidthForMaxChars( int maxLength )
{
    int hframe, overlap;
    QStyleOption o;
    hframe = parent->tabBar()->style()->pixelMetric( QStyle::PM_TabBarTabHSpace, &o, parent );
    overlap = parent->tabBar()->style()->pixelMetric( QStyle::PM_TabBarTabOverlap, &o, parent );

    QFontMetrics fm = parent->tabBar()->fontMetrics();
    int x = 0;
    for (int i = 0; i < parent->count(); ++i)
    {
        Frame* f = frames[parent->widget(i)];
        QString newTitle = f->title();
        if ( newTitle.length() > maxLength )
            newTitle = newTitle.left( maxLength-3 ) + "...";

        int lw = fm.width( newTitle );
        int iw = parent->tabBar()->tabIcon( i ).pixmap( parent->tabBar()->style()->pixelMetric(
QStyle::PM_SmallIconSize ), QIcon::Normal
).width() + 4;

        x += ( parent->tabBar()->style()->sizeFromContents( QStyle::CT_TabBarTab, &o,
               QSize( qMax( lw + hframe + iw, QApplication::globalStrut().width() ), 0 ), parent ) ).width();
    }
    return x;
}

void TabWidget::slotSetTitle(Frame* frame, const QString& title)
{
    d->setTitle(title, frame);
}

void TabWidget::Private::setTitle( const QString &title, QWidget* sender)
{
    int senderIndex = parent->indexOf(sender);

    parent->setTabToolTip( senderIndex, QString() );

    uint lcw=0, rcw=0;
    int tabBarHeight = parent->tabBar()->sizeHint().height();

    QWidget* leftCorner = parent->cornerWidget( Qt::TopLeftCorner );

    if ( leftCorner  && leftCorner->isVisible() )
        lcw = qMax( leftCorner->width(), tabBarHeight );

    QWidget* rightCorner = parent->cornerWidget( Qt::TopRightCorner );

    if ( rightCorner && rightCorner->isVisible() )
        rcw = qMax( rightCorner->width(), tabBarHeight );
    uint maxTabBarWidth = parent->width() - lcw - rcw;

    int newMaxLength = 30;

    for ( ; newMaxLength > 3; newMaxLength-- )
    {
        if ( tabBarWidthForMaxChars( newMaxLength ) < maxTabBarWidth )
            break;
    }

    QString newTitle = title;
    if ( newTitle.length() > newMaxLength )
    {
        parent->setTabToolTip( senderIndex, newTitle );
        newTitle = newTitle.left( newMaxLength-3 ) + "...";
    }

    newTitle.replace( '&', "&&" );

    if ( parent->tabText(senderIndex) != newTitle )
        parent->setTabText( senderIndex, newTitle );

    if( newMaxLength != currentMaxLength )
    {
        for( int i = 0; i < parent->count(); ++i)
        {
            Frame* f = frames[parent->widget(i)];
            newTitle = f->title();
            int index = parent->indexOf(parent->widget( i ));
            parent->setTabToolTip( index, QString() );

            if ( newTitle.length() > newMaxLength )
            {
                parent->setTabToolTip( index, newTitle );
                newTitle = newTitle.left( newMaxLength-3 ) + "...";
            }

            newTitle.replace( '&', "&&" );
            if ( newTitle != parent->tabText( index ) )
                parent->setTabText( index, newTitle );
        }
        currentMaxLength = newMaxLength;
    }
}

void TabWidget::contextMenu(int i, const QPoint &p)
{
    QWidget* w = ActionManager::getInstance()->container("tab_popup");
    d->currentItem = widget(i);
    //kDebug() << indexOf(d->currentItem);
    // FIXME: do not hardcode index of maintab
    if (w && indexOf(d->currentItem) != 0)
        static_cast<QMenu *>(w)->exec(p);
    d->currentItem = 0;
}

void TabWidget::slotDetachTab()
{
    if (!d->currentItem || indexOf(d->currentItem) == -1)
        d->currentItem = currentWidget();

    Frame* frame = d->frames[d->currentItem];

    if (frame && frame->url().isValid() && frame->isRemovable())
    {
        OpenUrlRequest request;
        request.setUrl(frame->url());
        request.setOptions(OpenUrlRequest::ExternalBrowser);
        emit signalOpenUrlRequest(request);
        slotCloseTab();
    }
}

void TabWidget::slotCopyLinkAddress()
{
    if(!d->currentItem || indexOf(d->currentItem) == -1)
        d->currentItem = currentWidget();
    Frame* frame = d->frames[d->currentItem];

    if (frame && frame->url().isValid())
    {
        KUrl url = frame->url();
        // don't set url to selection as it's a no-no according to a fd.o spec
        //kapp->clipboard()->setText(url.prettyUrl(), QClipboard::Selection);
        kapp->clipboard()->setText(url.prettyUrl(), QClipboard::Clipboard);
    }
}

void TabWidget::slotCloseTab()
{
    if (!d->currentItem || indexOf(d->currentItem) == -1)
        d->currentItem = currentWidget();
    if (d->frames[d->currentItem] == 0 || !d->frames[d->currentItem]->isRemovable() )
        return;

    emit signalRemoveFrameRequest(d->frames[d->currentItem]->id());
}

void TabWidget::initiateDrag(int tab)
{
    Frame* frame = d->frames[widget(tab)];

    if (frame && frame->url().isValid())
    {
        KUrl::List lst;
        lst.append( frame->url() );
        QDrag* drag = new QDrag( this );
        QMimeData *md = new QMimeData;
        drag->setMimeData( md );
        lst.populateMimeData( md );
        drag->setPixmap( KIO::pixmapForUrl( lst.first(), 0, KIconLoader::Small ) );
        drag->start();
    }
}

void TabWidget::slotCloseRequest(QWidget* widget)
{
    if (d->frames[widget])
        emit signalRemoveFrameRequest(d->frames[widget]->id());
}

} // namespace Akregator

#include "tabwidget.moc"
<|endoftext|>


<commit_before>// ft2232spi.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

/* Standard C libraries */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
/* OS specific libraries */
#ifdef _WIN32
#include<windows.h>
#endif

/* Include D2XX header*/
#include "ftd2xx.h"

#pragma comment(lib, "FTD2XX.lib")
#pragma comment(lib, "libMPSSE.lib")

/* Include libMPSSE header */
#include "libMPSSE_spi.h"

/* Helper macros */

#define APP_CHECK_STATUS(exp) {if(exp!=FT_OK){printf("%s:%d:%s(): status(0x%x) \
!= FT_OK\n",__FILE__, __LINE__, __FUNCTION__,exp);exit(1);}else{;}};
#define CHECK_NULL(exp){if(exp==NULL){printf("%s:%d:%s():  NULL expression \
encountered \n",__FILE__, __LINE__, __FUNCTION__);exit(1);}else{;}};

/* Definitions */
#define PROG_BUFFER_SIZE        4000000
#define SPI_DEVICE_BUFFER_SIZE		256
#define CHANNEL_TO_OPEN			0	/*0 for first available channel, 1 for next... */
#define SPI_WRITE_COMPLETION_RETRY 100
#define SPI_OPTS               SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES | SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE | SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE
#define GPIO_DIR			   0x93 /* 0b10010011 */
#define GPIO_INIT			   GPIO_DIR /* Everything that's an output should be set high */
#define RESET_CHIP

int _tmain(int argc, _TCHAR* argv[]) {
	FT_STATUS ftStatus;
	FT_HANDLE ftHandle;
	uint8* wBuffer = new uint8[PROG_BUFFER_SIZE];
	uint8* rBuffer = new uint8[SPI_DEVICE_BUFFER_SIZE];

	FILE* fileHandle;
	size_t fileSize;
	FT_STATUS status = FT_OK;
	FT_DEVICE_LIST_INFO_NODE devList = {0};
	ChannelConfig channelConf = {0};
	uint8 address = 0;
	uint32 channels = 0;
	uint32 sizeTransferred;
	uint16 data = 0;
	uint8 i = 0;

	if (wBuffer == NULL) {
		printf("Couln't allocate memeory for write buffer.\r\n");
		exit(1);
	}
	if (rBuffer == NULL) {
		printf("Couln't allocate memeory for read buffer.\r\n");
		exit(1);
	}

	channelConf.ClockRate = 3000000;
	channelConf.LatencyTimer = 255;
	channelConf.configOptions = SPI_CONFIG_OPTION_MODE0 | SPI_CONFIG_OPTION_CS_DBUS4 | SPI_CONFIG_OPTION_CS_ACTIVELOW;
	channelConf.Pin = 0x80B080B0;/*FinalVal-FinalDir-InitVal-InitDir (for dir 0=in, 1=out)*/
	channelConf.reserved = 0;

	/* init library */
#ifdef _MSC_VER
	Init_libMPSSE();
#endif
	status = SPI_GetNumChannels(&channels);
	APP_CHECK_STATUS(status);
	printf("Number of available SPI channels = %d\n",(int)channels);

	if(channels>0)
	{
		/* Open the first available channel */
		status = SPI_OpenChannel(CHANNEL_TO_OPEN,&ftHandle);
		APP_CHECK_STATUS(status);
		printf("\nhandle=0x%x status=0x%x\n",(unsigned int)ftHandle,status);

		status = SPI_InitChannel(ftHandle,&channelConf);
		APP_CHECK_STATUS(status);

#ifdef RESET_CHIP
		// Reset the FPGA by setting a dummy pin as the chip select with active high which sets both SS and CRESET_B low
		status = SPI_ChangeCS(ftHandle, SPI_CONFIG_OPTION_CS_DBUS5);
		APP_CHECK_STATUS(status);
		SPI_Write(ftHandle, wBuffer, 1, &sizeTransferred, SPI_OPTS);
		APP_CHECK_STATUS(status);

		Sleep(1);

		// Change the chip select back to the actual chip select
		SPI_ChangeCS(ftHandle, SPI_CONFIG_OPTION_CS_DBUS4 | SPI_CONFIG_OPTION_CS_ACTIVELOW);
		APP_CHECK_STATUS(status);

		Sleep(1);
#endif

		// Write some data for the lattice iCE40Ultra EVK demo

		fileHandle = fopen("C:\\Users\\DanielCascner\\Documents\\peripherals\\peripherals_Implmnt\\sbt\\outputs\\bitmap\\top_bitmap.bin", "rb");
		if (fileHandle == NULL) {
			printf("Couldn't open programming file\r\n");
			exit(1);
		}
		fseek(fileHandle, 0, SEEK_END);
		fileSize   = ftell(fileHandle);
		printf("Programming file is %d bytes\r\n", fileSize);
		fseek(fileHandle, 0, SEEK_SET);

		sizeTransferred = fread(wBuffer, sizeof(uint8), fileSize, fileHandle);
		if (sizeTransferred != fileSize) {
			printf("Didn't read full programming file %d < %d\r\n", sizeTransferred, fileSize);
			exit(1);
		}
		for (int i=0; i<50; ++i) wBuffer[sizeTransferred++] = 0; // Add dummy bytes

		status = SPI_Write(ftHandle, wBuffer, sizeTransferred, &sizeTransferred, SPI_OPTS);
		APP_CHECK_STATUS(status);
		printf("Wrote/Read %d bytes\r\n", sizeTransferred);
		unsigned long retry = 0;
		bool state=FALSE;
		SPI_IsBusy(ftHandle,&state);
		while((FALSE==state) && (retry<SPI_WRITE_COMPLETION_RETRY))
		{
			printf("SPI device is busy(%u)\n",(unsigned)retry);
			SPI_IsBusy(ftHandle,&state);
			retry++;
		}

		status = SPI_CloseChannel(ftHandle);
	}

	delete wBuffer;
	delete rBuffer;

#ifdef _MSC_VER
	Cleanup_libMPSSE();
#endif

#ifndef __linux__
	system("pause");
#endif
	return 0;
}

<commit_msg>Resetting the chip this way doesn't work but setting the IO defaults appropriately is nessisary.<commit_after>// ft2232spi.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

/* Standard C libraries */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
/* OS specific libraries */
#ifdef _WIN32
#include<windows.h>
#endif

/* Include D2XX header*/
#include "ftd2xx.h"

#pragma comment(lib, "FTD2XX.lib")
#pragma comment(lib, "libMPSSE.lib")

/* Include libMPSSE header */
#include "libMPSSE_spi.h"

/* Helper macros */

#define APP_CHECK_STATUS(exp) {if(exp!=FT_OK){printf("%s:%d:%s(): status(0x%x) \
!= FT_OK\n",__FILE__, __LINE__, __FUNCTION__,exp);exit(1);}else{;}};
#define CHECK_NULL(exp){if(exp==NULL){printf("%s:%d:%s():  NULL expression \
encountered \n",__FILE__, __LINE__, __FUNCTION__);exit(1);}else{;}};

/* Definitions */
#define PROG_BUFFER_SIZE        4000000
#define SPI_DEVICE_BUFFER_SIZE		256
#define CHANNEL_TO_OPEN			0	/*0 for first available channel, 1 for next... */
#define SPI_WRITE_COMPLETION_RETRY 100
#define SPI_OPTS               SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES | SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE | SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE
#define GPIO_INIT			   GPIO_DIR /* Everything that's an output should be set high */
//#define RESET_CHIP
#define TEST_COMMUNICATION

int _tmain(int argc, _TCHAR* argv[]) {
	FT_STATUS ftStatus;
	FT_HANDLE ftHandle;
	uint8* wBuffer = new uint8[PROG_BUFFER_SIZE];
	uint8* rBuffer = new uint8[SPI_DEVICE_BUFFER_SIZE];

	FILE* fileHandle;
	size_t fileSize;
	FT_STATUS status = FT_OK;
	FT_DEVICE_LIST_INFO_NODE devList = {0};
	ChannelConfig channelConf = {0};
	uint8 address = 0;
	uint32 channels = 0;
	uint32 sizeTransferred;
	uint16 data = 0;
	uint8 i = 0;

	if (wBuffer == NULL) {
		printf("Couln't allocate memeory for write buffer.\r\n");
		exit(1);
	}
	if (rBuffer == NULL) {
		printf("Couln't allocate memeory for read buffer.\r\n");
		exit(1);
	}

	channelConf.ClockRate = 3000000;
	channelConf.LatencyTimer = 255;
	channelConf.configOptions = SPI_CONFIG_OPTION_MODE0 | SPI_CONFIG_OPTION_CS_DBUS4 | SPI_CONFIG_OPTION_CS_ACTIVELOW;
	channelConf.Pin = 0x80B080B0;/*FinalVal-FinalDir-InitVal-InitDir (for dir 0=in, 1=out)*/
	channelConf.reserved = 0;

	/* init library */
#ifdef _MSC_VER
	Init_libMPSSE();
#endif
	status = SPI_GetNumChannels(&channels);
	APP_CHECK_STATUS(status);
	printf("Number of available SPI channels = %d\n",(int)channels);

	if(channels>0)
	{
		/* Open the first available channel */
		status = SPI_OpenChannel(CHANNEL_TO_OPEN,&ftHandle);
		APP_CHECK_STATUS(status);
		printf("\nhandle=0x%x status=0x%x\n",(unsigned int)ftHandle,status);

		status = SPI_InitChannel(ftHandle,&channelConf);
		APP_CHECK_STATUS(status);

#ifdef RESET_CHIP
		// Reset the FPGA by setting a dummy pin as the chip select with active high which sets both SS and CRESET_B low
		status = SPI_ChangeCS(ftHandle, SPI_CONFIG_OPTION_CS_DBUS5);
		APP_CHECK_STATUS(status);
		SPI_Write(ftHandle, wBuffer, 1, &sizeTransferred, SPI_OPTS);
		APP_CHECK_STATUS(status);

		Sleep(1);

		// Change the chip select back to the actual chip select
		SPI_ChangeCS(ftHandle, SPI_CONFIG_OPTION_CS_DBUS4 | SPI_CONFIG_OPTION_CS_ACTIVELOW);
		APP_CHECK_STATUS(status);

		Sleep(1);
#endif

		// Write some data for the lattice iCE40Ultra EVK demo

		fileHandle = fopen("C:\\Users\\DanielCascner\\Documents\\peripherals\\peripherals_Implmnt\\sbt\\outputs\\bitmap\\top_bitmap.bin", "rb");
		if (fileHandle == NULL) {
			printf("Couldn't open programming file\r\n");
			exit(1);
		}
		fseek(fileHandle, 0, SEEK_END);
		fileSize   = ftell(fileHandle);
		printf("Programming file is %d bytes\r\n", fileSize);
		fseek(fileHandle, 0, SEEK_SET);

		sizeTransferred = fread(wBuffer, sizeof(uint8), fileSize, fileHandle);
		if (sizeTransferred != fileSize) {
			printf("Didn't read full programming file %d < %d\r\n", sizeTransferred, fileSize);
			exit(1);
		}
		for (int i=0; i<50; ++i) wBuffer[sizeTransferred++] = 0; // Add dummy bytes

		status = SPI_Write(ftHandle, wBuffer, sizeTransferred, &sizeTransferred, SPI_OPTS);
		APP_CHECK_STATUS(status);
		printf("Transferred %d bytes\r\n", sizeTransferred);
		unsigned long retry = 0;
		bool state=FALSE;
		SPI_IsBusy(ftHandle,&state);
		while((FALSE==state) && (retry<SPI_WRITE_COMPLETION_RETRY))
		{
			printf("SPI device is busy(%u)\n",(unsigned)retry);
			SPI_IsBusy(ftHandle,&state);
			retry++;
		}

#ifdef TEST_COMMUNICATION
		Sleep(10);

		for (sizeTransferred = 0; sizeTransferred < 10; sizeTransferred++) wBuffer[sizeTransferred] = sizeTransferred;
		status = SPI_ReadWrite(ftHandle, rBuffer, wBuffer, sizeTransferred, &sizeTransferred, SPI_OPTS);
		APP_CHECK_STATUS(status);
		printf("Transferred %d bytes\r\n", sizeTransferred);
		rBuffer[sizeTransferred] = 0;
		printf("Received %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x \r\n", rBuffer[0], rBuffer[1], rBuffer[2], rBuffer[3], rBuffer[4], rBuffer[5], rBuffer[6], rBuffer[7], rBuffer[8], rBuffer[9]);

#endif
		status = SPI_CloseChannel(ftHandle);
	}

	delete wBuffer;
	delete rBuffer;

#ifdef _MSC_VER
	Cleanup_libMPSSE();
#endif

#ifndef __linux__
	system("pause");
#endif
	return 0;
}

<|endoftext|>


<commit_before><commit_msg>can now accept multiple arguments to hash multiple files at once<commit_after><|endoftext|>


<commit_before>/* Copyright (c) 2009 - http://ruinwesen.com/ */

#ifndef DATA_ENCODER_CHECKING_H__
#define DATA_ENCODER_CHECKING_H__

/**
 * \addtogroup CommonTools
 *
 * @{
 *
 * \addtogroup helpers_data_encoder Data encoding classes
 *
 * @{
 *
 * \file
 * Length checking versions of the DataEncoder and the DataDecoder.
 **/

#define DATA_ENCODER_RETURN_TYPE bool
#define DATA_ENCODER_CHECK(condition) { if (!(condition)) return false; }
#define DATA_ENCODER_TRUE() { return true; }
#define DATA_ENCODER_FALSE() { return true; }
#define DATA_ENCODER_INIT(data, length) data, length

#define DATA_ENCODER_CHECKING 1

/**
 * \addtogroup dataencoder Data Encoder
 * Checking version of the data encoder.
 *
 * @{
 */

/** DataEncoder class, packing various values into a data buffer. **/
class DataEncoder {
	/**
	 * \addtogroup dataencoder
	 * @{
	 **/
public:
  uint8_t *data;
  uint8_t *ptr;
  uint16_t maxLen;

  virtual void init(uint8_t *_data, uint16_t _maxLen) {
    data = _data;
    maxLen = _maxLen;
    ptr = data;
  }

	uint16_t getIdx() {
		return ptr - data;
	}

	DATA_ENCODER_RETURN_TYPE pack(uint8_t *inb, uint16_t len) {
		for (uint16_t i = 0; i < len; i++) {
			if (!pack8(inb[i]))
				return false;
		}
		return true;
	}

  virtual DATA_ENCODER_RETURN_TYPE pack8(uint8_t inb) {
    return false;
  }

	virtual DATA_ENCODER_RETURN_TYPE packb(bool inb) {
		if (inb)
			return pack8(1);
		else
			return pack8(0);
  }

	DATA_ENCODER_RETURN_TYPE fill8(uint8_t inb, uint16_t cnt) {
		for (uint16_t i = 0; i < cnt; i++) {
			if (!pack8(inb))
				return false;
		}
		return true;
	}

	DATA_ENCODER_RETURN_TYPE pack16(uint16_t inw) {
		return pack8((inw >> 8) & 0xFF) &&
			pack8(inw & 0xFF);

	}

	DATA_ENCODER_RETURN_TYPE pack32(uint32_t inw) {
		return pack8((inw >> 24) & 0xFF) &&
			pack8((inw >> 16) & 0xFF) &&
			pack8((inw >> 8) & 0xFF) &&
			pack8(inw & 0xFF);
	}

	DATA_ENCODER_RETURN_TYPE pack32(uint32_t *addr, uint16_t cnt) {
		for (uint16_t i = 0; i < cnt; i++) {
			if (!pack32(addr[i]))
				return false;
		}
		return true;
	}

	DATA_ENCODER_RETURN_TYPE pack32(uint64_t *addr, uint16_t cnt) {
		for (uint16_t i = 0; i < cnt; i++) {
			if (!pack32(addr[i]))
				return false;
		}
		return true;
	}

	DATA_ENCODER_RETURN_TYPE pack32hi(uint64_t inw) {
		return pack32(inw >> 32);
	}

	DATA_ENCODER_RETURN_TYPE pack32hi(uint64_t *addr, uint16_t cnt) {
		for (uint16_t i = 0; i < cnt; i++) {
			if (!pack32hi(addr[i]))
				return false;
		}
		return true;
	}

	DATA_ENCODER_RETURN_TYPE pack64(uint64_t inw) {
		return pack32hi(inw) && pack32(inw & 0xFFFFFFFF);
	}

	DATA_ENCODER_RETURN_TYPE pack64(uint64_t *addr, uint16_t cnt) {
		for (uint16_t i = 0; i < cnt; i++) {
			if (!pack64(addr[i]))
				return false;
		}
		return true;
	}

  virtual uint16_t finish() {
    return 0;
  }
#ifdef HOST_MIDIDUINO
  virtual ~DataEncoder() { };
#endif
	/* @} */
};

/** @} **/

/**
 * \addtogroup datadecoder Data Decoder
 * Checking version of the data decoder.
 *
 * @{
 **/

/** DataDecoder class, unpacking various values out of a data buffer. **/
class DataDecoder {
	/**
	 * \addtogroup datadecoder
	 * @{
	 **/
public:
	uint8_t *data;
	uint8_t *ptr;
	uint16_t maxLen;

	DataDecoder() {
	}

	virtual void init(uint8_t *_data, uint16_t _maxLen) {
		data = _data;
		maxLen = _maxLen;
		ptr = data;
	}

	uint16_t getIdx() {
		return ptr - data;
	}

	virtual DATA_ENCODER_RETURN_TYPE getb(bool *b) {
		uint8_t c;
		bool ret = get8(&c);
		if (!ret) {
			*b = c;
		}
		return ret;
	}

	virtual DATA_ENCODER_RETURN_TYPE get8(uint8_t *c) {
		return false;
	}

	virtual DATA_ENCODER_RETURN_TYPE skip8() {
		uint8_t b;
		return get8(&b);
	}

	virtual DATA_ENCODER_RETURN_TYPE skip(uint16_t cnt) {
		for (uint16_t i = 0; i < cnt; i++) {
			if (!skip8()) {
				return false;
			}
		}
		return true;
	}

	DATA_ENCODER_RETURN_TYPE get16(uint16_t *c) {
		uint8_t b1, b2;
		bool ret = get8(&b1) && get8(&b2);
		if (ret) {
			*c = (((uint16_t)b1) << 8) | b2;
		}
		return ret;
	}
	DATA_ENCODER_RETURN_TYPE get32(uint32_t *c) {
		uint16_t b1, b2;
		bool ret = get16(&b1) && get16(&b2);
		if (ret) {
			*c = (((uint32_t)b1) << 16) | b2;
		}
		return ret;
	}
	DATA_ENCODER_RETURN_TYPE get32(uint32_t *c, uint16_t cnt) {
		for (uint16_t i = 0; i < cnt; i++) {
			if (!get32(&c[i]))
				return false;
		}
		return true;
	}
	DATA_ENCODER_RETURN_TYPE get32(uint64_t *c) {
		uint32_t c2;
		if (!get32(&c2)) {
			return false;
		}
		*c = c2;
		return true;
	}
	DATA_ENCODER_RETURN_TYPE get32(uint64_t *c, uint16_t cnt) {
		for (uint16_t i = 0; i < cnt; i++) {
			if (!get32(&c[i]))
				return false;
		}
		return true;
	}
	DATA_ENCODER_RETURN_TYPE get32hi(uint64_t *c) {
		uint32_t c2;
		if (!get32(&c2)) {
			return false;
		}
		*c |= ((uint64_t)c2) << 32;
		return true;
	}
	DATA_ENCODER_RETURN_TYPE get32hi(uint64_t *c, uint16_t cnt) {
		for (uint16_t i = 0; i < cnt; i++) {
			if (!get32hi(&c[i]))
				return false;
		}
		return true;
	}

	DATA_ENCODER_RETURN_TYPE get64(uint64_t *c) {
		uint32_t c1, c2;
		if (!(get32(&c1) && get32(&c2))) {
			return false;
		}
		*c = ((uint64_t)c1 << 32) | c2;
		return true;
	}

	DATA_ENCODER_RETURN_TYPE get64(uint64_t *c, uint16_t cnt) {
		for (uint16_t i = 0; i < cnt; i++) {
			if (!get64(&c[i]))
				return false;
		}
		return true;
	}

	uint16_t get(uint8_t *data, uint16_t len) {
		uint16_t i;
		for (i = 0; i < len; i++) {
			if (!get8(data + i))
				break;
		}
		return i;
	}

	uint8_t gget8() {
		uint8_t b;
		get8(&b);
		return b;
	}

	uint16_t gget16() {
		uint16_t a1 = ((uint16_t)gget8()) << 8;
		uint8_t a2 = gget8();
		return a1 | a2;
	}

	uint32_t gget32() {
		uint32_t a1 = ((uint32_t)gget16()) << 16;
		uint16_t a2 = gget16();
		return a1 | a2;
	}

	uint64_t gget64() {
		uint64_t a1 = ((uint64_t)gget32()) << 32;
		uint32_t a2 = gget32();
		return a1 | a2;
	}

#ifdef HOST_MIDIDUINO
  virtual ~DataDecoder() { };
#endif
	/* @} */
};

/* @} @} @} */

#endif /* DATA_ENCODER_CHECKING_H__ */
<commit_msg>Fix encoder checking eclipse warnings<commit_after>/* Copyright (c) 2009 - http://ruinwesen.com/ */

#ifndef DATA_ENCODER_CHECKING_H__
#define DATA_ENCODER_CHECKING_H__

#include "PlatformConfig.h"

/**
 * \addtogroup CommonTools
 *
 * @{
 *
 * \addtogroup helpers_data_encoder Data encoding classes
 *
 * @{
 *
 * \file
 * Length checking versions of the DataEncoder and the DataDecoder.
 **/

#define DATA_ENCODER_RETURN_TYPE bool
#define DATA_ENCODER_CHECK(condition) { if (!(condition)) return false; }
#define DATA_ENCODER_TRUE() { return true; }
#define DATA_ENCODER_FALSE() { return true; }
#define DATA_ENCODER_INIT(data, length) data, length

#define DATA_ENCODER_CHECKING 1

/**
 * \addtogroup dataencoder Data Encoder
 * Checking version of the data encoder.
 *
 * @{
 */

/** DataEncoder class, packing various values into a data buffer. **/
class DataEncoder {
	/**
	 * \addtogroup dataencoder
	 * @{
	 **/
public:
  uint8_t *data;
  uint8_t *ptr;
  uint16_t maxLen;

  virtual void init(uint8_t *_data, uint16_t _maxLen) {
    data = _data;
    maxLen = _maxLen;
    ptr = data;
  }

	uint16_t getIdx() {
		return ptr - data;
	}

	DATA_ENCODER_RETURN_TYPE pack(uint8_t *inb, uint16_t len) {
		for (uint16_t i = 0; i < len; i++) {
			if (!pack8(inb[i]))
				return false;
		}
		return true;
	}

  virtual DATA_ENCODER_RETURN_TYPE pack8(uint8_t inb) {
    return false;
  }

	virtual DATA_ENCODER_RETURN_TYPE packb(bool inb) {
		if (inb)
			return pack8(1);
		else
			return pack8(0);
  }

	DATA_ENCODER_RETURN_TYPE fill8(uint8_t inb, uint16_t cnt) {
		for (uint16_t i = 0; i < cnt; i++) {
			if (!pack8(inb))
				return false;
		}
		return true;
	}

	DATA_ENCODER_RETURN_TYPE pack16(uint16_t inw) {
		return pack8((inw >> 8) & 0xFF) &&
			pack8(inw & 0xFF);

	}

	DATA_ENCODER_RETURN_TYPE pack32(uint32_t inw) {
		return pack8((inw >> 24) & 0xFF) &&
			pack8((inw >> 16) & 0xFF) &&
			pack8((inw >> 8) & 0xFF) &&
			pack8(inw & 0xFF);
	}

	DATA_ENCODER_RETURN_TYPE pack32(uint32_t *addr, uint16_t cnt) {
		for (uint16_t i = 0; i < cnt; i++) {
			if (!pack32(addr[i]))
				return false;
		}
		return true;
	}

	DATA_ENCODER_RETURN_TYPE pack32(uint64_t *addr, uint16_t cnt) {
		for (uint16_t i = 0; i < cnt; i++) {
			if (!pack32(addr[i]))
				return false;
		}
		return true;
	}

	DATA_ENCODER_RETURN_TYPE pack32hi(uint64_t inw) {
		return pack32(inw >> 32);
	}

	DATA_ENCODER_RETURN_TYPE pack32hi(uint64_t *addr, uint16_t cnt) {
		for (uint16_t i = 0; i < cnt; i++) {
			if (!pack32hi(addr[i]))
				return false;
		}
		return true;
	}

	DATA_ENCODER_RETURN_TYPE pack64(uint64_t inw) {
		return pack32hi(inw) && pack32(inw & 0xFFFFFFFF);
	}

	DATA_ENCODER_RETURN_TYPE pack64(uint64_t *addr, uint16_t cnt) {
		for (uint16_t i = 0; i < cnt; i++) {
			if (!pack64(addr[i]))
				return false;
		}
		return true;
	}

  virtual uint16_t finish() {
    return 0;
  }
#ifdef HOST_MIDIDUINO
  virtual ~DataEncoder() { };
#endif
	/* @} */
};

/** @} **/

/**
 * \addtogroup datadecoder Data Decoder
 * Checking version of the data decoder.
 *
 * @{
 **/

/** DataDecoder class, unpacking various values out of a data buffer. **/
class DataDecoder {
	/**
	 * \addtogroup datadecoder
	 * @{
	 **/
public:
	uint8_t *data;
	uint8_t *ptr;
	uint16_t maxLen;

	DataDecoder() {
	}

	virtual void init(uint8_t *_data, uint16_t _maxLen) {
		data = _data;
		maxLen = _maxLen;
		ptr = data;
	}

	uint16_t getIdx() {
		return ptr - data;
	}

	virtual DATA_ENCODER_RETURN_TYPE getb(bool *b) {
		uint8_t c;
		bool ret = get8(&c);
		if (!ret) {
			*b = c;
		}
		return ret;
	}

	virtual DATA_ENCODER_RETURN_TYPE get8(uint8_t *c) {
		return false;
	}

	virtual DATA_ENCODER_RETURN_TYPE skip8() {
		uint8_t b;
		return get8(&b);
	}

	virtual DATA_ENCODER_RETURN_TYPE skip(uint16_t cnt) {
		for (uint16_t i = 0; i < cnt; i++) {
			if (!skip8()) {
				return false;
			}
		}
		return true;
	}

	DATA_ENCODER_RETURN_TYPE get16(uint16_t *c) {
		uint8_t b1, b2;
		bool ret = get8(&b1) && get8(&b2);
		if (ret) {
			*c = (((uint16_t)b1) << 8) | b2;
		}
		return ret;
	}
	DATA_ENCODER_RETURN_TYPE get32(uint32_t *c) {
		uint16_t b1, b2;
		bool ret = get16(&b1) && get16(&b2);
		if (ret) {
			*c = (((uint32_t)b1) << 16) | b2;
		}
		return ret;
	}
	DATA_ENCODER_RETURN_TYPE get32(uint32_t *c, uint16_t cnt) {
		for (uint16_t i = 0; i < cnt; i++) {
			if (!get32(&c[i]))
				return false;
		}
		return true;
	}
	DATA_ENCODER_RETURN_TYPE get32(uint64_t *c) {
		uint32_t c2;
		if (!get32(&c2)) {
			return false;
		}
		*c = c2;
		return true;
	}
	DATA_ENCODER_RETURN_TYPE get32(uint64_t *c, uint16_t cnt) {
		for (uint16_t i = 0; i < cnt; i++) {
			if (!get32(&c[i]))
				return false;
		}
		return true;
	}
	DATA_ENCODER_RETURN_TYPE get32hi(uint64_t *c) {
		uint32_t c2;
		if (!get32(&c2)) {
			return false;
		}
		*c |= ((uint64_t)c2) << 32;
		return true;
	}
	DATA_ENCODER_RETURN_TYPE get32hi(uint64_t *c, uint16_t cnt) {
		for (uint16_t i = 0; i < cnt; i++) {
			if (!get32hi(&c[i]))
				return false;
		}
		return true;
	}

	DATA_ENCODER_RETURN_TYPE get64(uint64_t *c) {
		uint32_t c1, c2;
		if (!(get32(&c1) && get32(&c2))) {
			return false;
		}
		*c = ((uint64_t)c1 << 32) | c2;
		return true;
	}

	DATA_ENCODER_RETURN_TYPE get64(uint64_t *c, uint16_t cnt) {
		for (uint16_t i = 0; i < cnt; i++) {
			if (!get64(&c[i]))
				return false;
		}
		return true;
	}

	uint16_t get(uint8_t *data, uint16_t len) {
		uint16_t i;
		for (i = 0; i < len; i++) {
			if (!get8(data + i))
				break;
		}
		return i;
	}

	uint8_t gget8() {
		uint8_t b;
		get8(&b);
		return b;
	}

	uint16_t gget16() {
		uint16_t a1 = ((uint16_t)gget8()) << 8;
		uint8_t a2 = gget8();
		return a1 | a2;
	}

	uint32_t gget32() {
		uint32_t a1 = ((uint32_t)gget16()) << 16;
		uint16_t a2 = gget16();
		return a1 | a2;
	}

	uint64_t gget64() {
		uint64_t a1 = ((uint64_t)gget32()) << 32;
		uint32_t a2 = gget32();
		return a1 | a2;
	}

#ifdef HOST_MIDIDUINO
  virtual ~DataDecoder() { };
#endif
	/* @} */
};

/* @} @} @} */

#endif /* DATA_ENCODER_CHECKING_H__ */
<|endoftext|>


<commit_before>// Copyright 2022 The gRPC Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <grpc/support/port_platform.h>

#include "src/core/lib/event_engine/work_queue.h"

#include <cstdint>
#include <memory>
#include <utility>

#include "absl/functional/any_invocable.h"

#include "src/core/lib/event_engine/common_closures.h"

namespace grpc_event_engine {
namespace experimental {

// ------ WorkQueue::Storage --------------------------------------------------

WorkQueue::Storage::Storage(EventEngine::Closure* closure) noexcept
    : closure_(closure),
      enqueued_(
          grpc_core::Timestamp::Now().milliseconds_after_process_epoch()) {}

WorkQueue::Storage::Storage(absl::AnyInvocable<void()> callback) noexcept
    : closure_(SelfDeletingClosure::Create(std::move(callback))),
      enqueued_(
          grpc_core::Timestamp::Now().milliseconds_after_process_epoch()) {}

WorkQueue::Storage::Storage(Storage&& other) noexcept
    : closure_(other.closure_), enqueued_(other.enqueued_) {}

WorkQueue::Storage& WorkQueue::Storage::operator=(Storage&& other) noexcept {
  std::swap(closure_, other.closure_);
  std::swap(enqueued_, other.enqueued_);
  return *this;
}

EventEngine::Closure* WorkQueue::Storage::closure() { return closure_; }

// ------ WorkQueue -----------------------------------------------------------

// Returns whether the queue is empty
bool WorkQueue::Empty() const {
  return (most_recent_element_enqueue_timestamp_.load(
              std::memory_order_relaxed) == kInvalidTimestamp &&
          oldest_enqueued_timestamp_.load(std::memory_order_relaxed) ==
              kInvalidTimestamp);
}

grpc_core::Timestamp WorkQueue::OldestEnqueuedTimestamp() const {
  int64_t front_of_queue_timestamp =
      oldest_enqueued_timestamp_.load(std::memory_order_relaxed);
  if (front_of_queue_timestamp != kInvalidTimestamp) {
    return grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(
        front_of_queue_timestamp);
  }
  int64_t most_recent_millis =
      most_recent_element_enqueue_timestamp_.load(std::memory_order_relaxed);
  if (most_recent_millis == kInvalidTimestamp) {
    return grpc_core::Timestamp::InfPast();
  }
  return grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(
      most_recent_millis);
}

EventEngine::Closure* WorkQueue::PopFront() ABSL_LOCKS_EXCLUDED(mu_) {
  if (oldest_enqueued_timestamp_.load(std::memory_order_relaxed) !=
      kInvalidTimestamp) {
    EventEngine::Closure* t = TryLockAndPop(/*front=*/true);
    if (t != nullptr) return t;
  }
  if (most_recent_element_enqueue_timestamp_.load(std::memory_order_relaxed) !=
      kInvalidTimestamp) {
    return TryPopMostRecentElement();
  }
  return nullptr;
}

EventEngine::Closure* WorkQueue::PopBack() {
  if (most_recent_element_enqueue_timestamp_.load(std::memory_order_relaxed) !=
      kInvalidTimestamp) {
    return TryPopMostRecentElement();
  }
  if (oldest_enqueued_timestamp_.load(std::memory_order_relaxed) !=
      kInvalidTimestamp) {
    EventEngine::Closure* t = TryLockAndPop(/*front=*/false);
    if (t != nullptr) return t;
  }
  return nullptr;
}

void WorkQueue::Add(EventEngine::Closure* closure) {
  AddInternal(Storage(closure));
}

void WorkQueue::Add(absl::AnyInvocable<void()> invocable) {
  AddInternal(Storage(std::move(invocable)));
}

void WorkQueue::AddInternal(Storage&& storage) {
  Storage previous_most_recent;
  int64_t previous_ts;
  {
    absl::optional<Storage> tmp_element;
    {
      grpc_core::MutexLock lock(&most_recent_element_lock_);
      previous_ts = most_recent_element_enqueue_timestamp_.exchange(
          storage.enqueued(), std::memory_order_relaxed);
      tmp_element = std::exchange(most_recent_element_, std::move(storage));
    }
    if (!tmp_element.has_value() || previous_ts == kInvalidTimestamp) return;
    previous_most_recent = std::move(*tmp_element);
  }
  grpc_core::MutexLock lock(&mu_);
  if (elements_.empty()) {
    oldest_enqueued_timestamp_.store(previous_ts, std::memory_order_relaxed);
  }
  elements_.push_back(std::move(previous_most_recent));
}

EventEngine::Closure* WorkQueue::TryLockAndPop(bool front)
    ABSL_LOCKS_EXCLUDED(mu_) {
  // Do not block the worker if there are other workers trying to pop
  // tasks from this queue.
  if (!mu_.TryLock()) return nullptr;
  auto ret = PopLocked(front);
  mu_.Unlock();
  return ret;
}

EventEngine::Closure* WorkQueue::PopLocked(bool front)
    ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_) {
  if (GPR_UNLIKELY(elements_.empty())) {
    if (most_recent_element_enqueue_timestamp_.load(
            std::memory_order_relaxed) == kInvalidTimestamp) {
      return nullptr;
    }
    if (!most_recent_element_lock_.TryLock()) return nullptr;
    absl::optional<Storage> ret;
    if (GPR_LIKELY(most_recent_element_.has_value())) {
      most_recent_element_enqueue_timestamp_.store(kInvalidTimestamp,
                                                   std::memory_order_relaxed);
      ret = std::exchange(most_recent_element_, absl::nullopt);
    }
    most_recent_element_lock_.Unlock();
    return ret->closure();
  }
  // the queue has elements, let's pop one and update timestamps
  Storage ret_s;
  if (front) {
    ret_s = std::move(elements_.front());
    elements_.pop_front();
  } else {
    ret_s = std::move(elements_.back());
    elements_.pop_back();
  }
  if (elements_.empty()) {
    oldest_enqueued_timestamp_.store(kInvalidTimestamp,
                                     std::memory_order_relaxed);
  } else if (front) {
    oldest_enqueued_timestamp_.store(elements_.front().enqueued(),
                                     std::memory_order_relaxed);
  }
  return ret_s.closure();
}

EventEngine::Closure* WorkQueue::TryPopMostRecentElement() {
  if (!most_recent_element_lock_.TryLock()) return nullptr;
  if (GPR_UNLIKELY(!most_recent_element_.has_value())) {
    most_recent_element_lock_.Unlock();
    return nullptr;
  }
  most_recent_element_enqueue_timestamp_.store(kInvalidTimestamp,
                                               std::memory_order_relaxed);
  absl::optional<Storage> tmp =
      std::exchange(most_recent_element_, absl::nullopt);
  most_recent_element_lock_.Unlock();
  return tmp->closure();
}

}  // namespace experimental
}  // namespace grpc_event_engine
<commit_msg>[EventEngine] Fix race on WorkQueue's most-recent element (#31557)<commit_after>// Copyright 2022 The gRPC Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <grpc/support/port_platform.h>

#include "src/core/lib/event_engine/work_queue.h"

#include <cstdint>
#include <memory>
#include <utility>

#include "absl/functional/any_invocable.h"

#include "src/core/lib/event_engine/common_closures.h"

namespace grpc_event_engine {
namespace experimental {

// ------ WorkQueue::Storage --------------------------------------------------

WorkQueue::Storage::Storage(EventEngine::Closure* closure) noexcept
    : closure_(closure),
      enqueued_(
          grpc_core::Timestamp::Now().milliseconds_after_process_epoch()) {}

WorkQueue::Storage::Storage(absl::AnyInvocable<void()> callback) noexcept
    : closure_(SelfDeletingClosure::Create(std::move(callback))),
      enqueued_(
          grpc_core::Timestamp::Now().milliseconds_after_process_epoch()) {}

WorkQueue::Storage::Storage(Storage&& other) noexcept
    : closure_(other.closure_), enqueued_(other.enqueued_) {}

WorkQueue::Storage& WorkQueue::Storage::operator=(Storage&& other) noexcept {
  std::swap(closure_, other.closure_);
  std::swap(enqueued_, other.enqueued_);
  return *this;
}

EventEngine::Closure* WorkQueue::Storage::closure() { return closure_; }

// ------ WorkQueue -----------------------------------------------------------

// Returns whether the queue is empty
bool WorkQueue::Empty() const {
  return (most_recent_element_enqueue_timestamp_.load(
              std::memory_order_relaxed) == kInvalidTimestamp &&
          oldest_enqueued_timestamp_.load(std::memory_order_relaxed) ==
              kInvalidTimestamp);
}

grpc_core::Timestamp WorkQueue::OldestEnqueuedTimestamp() const {
  int64_t front_of_queue_timestamp =
      oldest_enqueued_timestamp_.load(std::memory_order_relaxed);
  if (front_of_queue_timestamp != kInvalidTimestamp) {
    return grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(
        front_of_queue_timestamp);
  }
  int64_t most_recent_millis =
      most_recent_element_enqueue_timestamp_.load(std::memory_order_relaxed);
  if (most_recent_millis == kInvalidTimestamp) {
    return grpc_core::Timestamp::InfPast();
  }
  return grpc_core::Timestamp::FromMillisecondsAfterProcessEpoch(
      most_recent_millis);
}

EventEngine::Closure* WorkQueue::PopFront() ABSL_LOCKS_EXCLUDED(mu_) {
  if (oldest_enqueued_timestamp_.load(std::memory_order_relaxed) !=
      kInvalidTimestamp) {
    EventEngine::Closure* t = TryLockAndPop(/*front=*/true);
    if (t != nullptr) return t;
  }
  if (most_recent_element_enqueue_timestamp_.load(std::memory_order_relaxed) !=
      kInvalidTimestamp) {
    return TryPopMostRecentElement();
  }
  return nullptr;
}

EventEngine::Closure* WorkQueue::PopBack() {
  if (most_recent_element_enqueue_timestamp_.load(std::memory_order_relaxed) !=
      kInvalidTimestamp) {
    return TryPopMostRecentElement();
  }
  if (oldest_enqueued_timestamp_.load(std::memory_order_relaxed) !=
      kInvalidTimestamp) {
    EventEngine::Closure* t = TryLockAndPop(/*front=*/false);
    if (t != nullptr) return t;
  }
  return nullptr;
}

void WorkQueue::Add(EventEngine::Closure* closure) {
  AddInternal(Storage(closure));
}

void WorkQueue::Add(absl::AnyInvocable<void()> invocable) {
  AddInternal(Storage(std::move(invocable)));
}

void WorkQueue::AddInternal(Storage&& storage) {
  Storage previous_most_recent;
  int64_t previous_ts;
  {
    absl::optional<Storage> tmp_element;
    {
      grpc_core::MutexLock lock(&most_recent_element_lock_);
      previous_ts = most_recent_element_enqueue_timestamp_.exchange(
          storage.enqueued(), std::memory_order_relaxed);
      tmp_element = std::exchange(most_recent_element_, std::move(storage));
    }
    if (!tmp_element.has_value() || previous_ts == kInvalidTimestamp) return;
    previous_most_recent = std::move(*tmp_element);
  }
  grpc_core::MutexLock lock(&mu_);
  if (elements_.empty()) {
    oldest_enqueued_timestamp_.store(previous_ts, std::memory_order_relaxed);
  }
  elements_.push_back(std::move(previous_most_recent));
}

EventEngine::Closure* WorkQueue::TryLockAndPop(bool front)
    ABSL_LOCKS_EXCLUDED(mu_) {
  // Do not block the worker if there are other workers trying to pop
  // tasks from this queue.
  if (!mu_.TryLock()) return nullptr;
  auto ret = PopLocked(front);
  mu_.Unlock();
  return ret;
}

EventEngine::Closure* WorkQueue::PopLocked(bool front)
    ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_) {
  if (GPR_UNLIKELY(elements_.empty())) {
    if (most_recent_element_enqueue_timestamp_.load(
            std::memory_order_relaxed) == kInvalidTimestamp) {
      return nullptr;
    }
    return TryPopMostRecentElement();
  }
  // the queue has elements, let's pop one and update timestamps
  Storage ret_s;
  if (front) {
    ret_s = std::move(elements_.front());
    elements_.pop_front();
  } else {
    ret_s = std::move(elements_.back());
    elements_.pop_back();
  }
  if (elements_.empty()) {
    oldest_enqueued_timestamp_.store(kInvalidTimestamp,
                                     std::memory_order_relaxed);
  } else if (front) {
    oldest_enqueued_timestamp_.store(elements_.front().enqueued(),
                                     std::memory_order_relaxed);
  }
  return ret_s.closure();
}

EventEngine::Closure* WorkQueue::TryPopMostRecentElement() {
  if (!most_recent_element_lock_.TryLock()) return nullptr;
  if (GPR_UNLIKELY(!most_recent_element_.has_value())) {
    most_recent_element_lock_.Unlock();
    return nullptr;
  }
  most_recent_element_enqueue_timestamp_.store(kInvalidTimestamp,
                                               std::memory_order_relaxed);
  absl::optional<Storage> tmp =
      std::exchange(most_recent_element_, absl::nullopt);
  most_recent_element_lock_.Unlock();
  return tmp->closure();
}

}  // namespace experimental
}  // namespace grpc_event_engine
<|endoftext|>