<commit_before>/*
 *  nextpnr -- Next Generation Place and Route
 *
 *  Copyright (C) 2018  David Shah <david@symbioticeda.com>
 *  Copyright (C) 2021  William D. Jones <wjones@wdj-consulting.com>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include <fstream>

#include "bitstream.h"
#include "config.h"
#include "nextpnr.h"
#include "util.h"

NEXTPNR_NAMESPACE_BEGIN

// These seem simple enough to do inline for now.
namespace BaseConfigs {
    void config_empty_lcmxo2_1200hc(ChipConfig &cc)
    {
        cc.chip_name = "LCMXO2-1200HC";

        cc.tiles["EBR_R6C11:EBR1"].add_unknown(0, 12);
        cc.tiles["EBR_R6C15:EBR1"].add_unknown(0, 12);
        cc.tiles["EBR_R6C18:EBR1"].add_unknown(0, 12);
        cc.tiles["EBR_R6C21:EBR1"].add_unknown(0, 12);
        cc.tiles["EBR_R6C2:EBR1"].add_unknown(0, 12);
        cc.tiles["EBR_R6C5:EBR1"].add_unknown(0, 12);
        cc.tiles["EBR_R6C8:EBR1"].add_unknown(0, 12);

        cc.tiles["PT4:CFG0"].add_unknown(5, 30);
        cc.tiles["PT4:CFG0"].add_unknown(5, 32);
        cc.tiles["PT4:CFG0"].add_unknown(5, 36);

        cc.tiles["PT7:CFG3"].add_unknown(5, 18);
    }
} // namespace BaseConfigs

// Convert an absolute wire name to a relative Trellis one
static std::string get_trellis_wirename(Context *ctx, Location loc, WireId wire)
{
    std::string basename = ctx->tileInfo(wire)->wire_data[wire.index].name.get();
    std::string prefix2 = basename.substr(0, 2);
    std::string prefix7 = basename.substr(0, 7);
    if (prefix2 == "G_" || prefix2 == "L_" || prefix2 == "R_" || prefix2 == "U_" || prefix2 == "D_" || prefix7 == "BRANCH_")
        return basename;
    if (loc == wire.location)
        return basename;
    std::string rel_prefix;
    if (wire.location.y < loc.y)
        rel_prefix += "N" + std::to_string(loc.y - wire.location.y);
    if (wire.location.y > loc.y)
        rel_prefix += "S" + std::to_string(wire.location.y - loc.y);
    if (wire.location.x > loc.x)
        rel_prefix += "E" + std::to_string(wire.location.x - loc.x);
    if (wire.location.x < loc.x)
        rel_prefix += "W" + std::to_string(loc.x - wire.location.x);
    return rel_prefix + "_" + basename;
}

static void set_pip(Context *ctx, ChipConfig &cc, PipId pip)
{
    std::string tile = ctx->getPipTilename(pip);
    std::string source = get_trellis_wirename(ctx, pip.location, ctx->getPipSrcWire(pip));
    std::string sink = get_trellis_wirename(ctx, pip.location, ctx->getPipDstWire(pip));
    cc.tiles[tile].add_arc(sink, source);
}

static std::vector<bool> int_to_bitvector(int val, int size)
{
    std::vector<bool> bv;
    for (int i = 0; i < size; i++) {
        bv.push_back((val & (1 << i)) != 0);
    }
    return bv;
}

static std::vector<bool> str_to_bitvector(std::string str, int size)
{
    std::vector<bool> bv;
    bv.resize(size, 0);
    if (str.substr(0, 2) != "0b")
        log_error("error parsing value '%s', expected 0b prefix\n", str.c_str());
    for (int i = 0; i < int(str.size()) - 2; i++) {
        char c = str.at((str.size() - i) - 1);
        NPNR_ASSERT(c == '0' || c == '1');
        bv.at(i) = (c == '1');
    }
    return bv;
}

std::string intstr_or_default(const std::unordered_map<IdString, Property> &ct, const IdString &key,
                              std::string def = "0")
{
    auto found = ct.find(key);
    if (found == ct.end())
        return def;
    else {
        if (found->second.is_string)
            return found->second.as_string();
        else
            return std::to_string(found->second.as_int64());
    }
};

void write_bitstream(Context *ctx, std::string text_config_file)
{
    ChipConfig cc;

    switch (ctx->args.type) {
    case ArchArgs::LCMXO2_1200HC:
        BaseConfigs::config_empty_lcmxo2_1200hc(cc);
        break;
    default:
        NPNR_ASSERT_FALSE("Unsupported device type");
    }

    cc.metadata.push_back("Part: " + ctx->getFullChipName());

    // Add all set, configurable pips to the config
    for (auto pip : ctx->getPips()) {
        if (ctx->getBoundPipNet(pip) != nullptr) {
            if (ctx->getPipClass(pip) == 0) { // ignore fixed pips
                set_pip(ctx, cc, pip);
            }
        }
    }

    // TODO: Bank Voltages

    // Configure slices
    for (auto &cell : ctx->cells) {
        CellInfo *ci = cell.second.get();
        if (ci->bel == BelId()) {
            log_warning("found unplaced cell '%s' during bitstream gen\n", ci->name.c_str(ctx));
        }
        BelId bel = ci->bel;
        if (ci->type == id_FACADE_SLICE) {
            std::string tname = ctx->getTileByTypeAndLocation(bel.location.y, bel.location.x, "PLC");
            std::string slice = ctx->tileInfo(bel)->bel_data[bel.index].name.get();

            NPNR_ASSERT(slice.substr(0, 5) == "SLICE");
            int int_index = slice[5] - 'A';
            NPNR_ASSERT(int_index >= 0 && int_index < 4);

            int lut0_init = int_or_default(ci->params, ctx->id("LUT0_INITVAL"));
            int lut1_init = int_or_default(ci->params, ctx->id("LUT1_INITVAL"));
            cc.tiles[tname].add_word(slice + ".K0.INIT", int_to_bitvector(lut0_init, 16));
            cc.tiles[tname].add_word(slice + ".K1.INIT", int_to_bitvector(lut1_init, 16));
            cc.tiles[tname].add_enum(slice + ".MODE", str_or_default(ci->params, ctx->id("MODE"), "LOGIC"));
            cc.tiles[tname].add_enum(slice + ".GSR", str_or_default(ci->params, ctx->id("GSR"), "ENABLED"));
            cc.tiles[tname].add_enum("LSR" + std::to_string(int_index) + ".SRMODE", str_or_default(ci->params, ctx->id("SRMODE"), "LSR_OVER_CE"));
            cc.tiles[tname].add_enum(slice + ".CEMUX", intstr_or_default(ci->params, ctx->id("CEMUX"), "1"));
            cc.tiles[tname].add_enum("CLK" + std::to_string(int_index) + ".CLKMUX", intstr_or_default(ci->params, ctx->id("CLKMUX"), "0"));
            cc.tiles[tname].add_enum("LSR" + std::to_string(int_index) + ".LSRMUX", str_or_default(ci->params, ctx->id("LSRMUX"), "LSR"));
            cc.tiles[tname].add_enum("LSR" + std::to_string(int_index) + ".LSRONMUX", intstr_or_default(ci->params, ctx->id("LSRONMUX"), "LSRMUX"));
            cc.tiles[tname].add_enum(slice + ".REG0.SD", intstr_or_default(ci->params, ctx->id("REG0_SD"), "0"));
            cc.tiles[tname].add_enum(slice + ".REG1.SD", intstr_or_default(ci->params, ctx->id("REG1_SD"), "0"));
            cc.tiles[tname].add_enum(slice + ".REG0.REGSET",
                                     str_or_default(ci->params, ctx->id("REG0_REGSET"), "RESET"));
            cc.tiles[tname].add_enum(slice + ".REG1.REGSET",
                                     str_or_default(ci->params, ctx->id("REG1_REGSET"), "RESET"));
        }
    }

    // Configure chip
    if (!text_config_file.empty()) {
        std::ofstream out_config(text_config_file);
        out_config << cc;
    }
}

NEXTPNR_NAMESPACE_END
<commit_msg>machxo2: Add REGMODE to bitstream output.<commit_after>/*
 *  nextpnr -- Next Generation Place and Route
 *
 *  Copyright (C) 2018  David Shah <david@symbioticeda.com>
 *  Copyright (C) 2021  William D. Jones <wjones@wdj-consulting.com>
 *
 *  Permission to use, copy, modify, and/or distribute this software for any
 *  purpose with or without fee is hereby granted, provided that the above
 *  copyright notice and this permission notice appear in all copies.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include <fstream>

#include "bitstream.h"
#include "config.h"
#include "nextpnr.h"
#include "util.h"

NEXTPNR_NAMESPACE_BEGIN

// These seem simple enough to do inline for now.
namespace BaseConfigs {
    void config_empty_lcmxo2_1200hc(ChipConfig &cc)
    {
        cc.chip_name = "LCMXO2-1200HC";

        cc.tiles["EBR_R6C11:EBR1"].add_unknown(0, 12);
        cc.tiles["EBR_R6C15:EBR1"].add_unknown(0, 12);
        cc.tiles["EBR_R6C18:EBR1"].add_unknown(0, 12);
        cc.tiles["EBR_R6C21:EBR1"].add_unknown(0, 12);
        cc.tiles["EBR_R6C2:EBR1"].add_unknown(0, 12);
        cc.tiles["EBR_R6C5:EBR1"].add_unknown(0, 12);
        cc.tiles["EBR_R6C8:EBR1"].add_unknown(0, 12);

        cc.tiles["PT4:CFG0"].add_unknown(5, 30);
        cc.tiles["PT4:CFG0"].add_unknown(5, 32);
        cc.tiles["PT4:CFG0"].add_unknown(5, 36);

        cc.tiles["PT7:CFG3"].add_unknown(5, 18);
    }
} // namespace BaseConfigs

// Convert an absolute wire name to a relative Trellis one
static std::string get_trellis_wirename(Context *ctx, Location loc, WireId wire)
{
    std::string basename = ctx->tileInfo(wire)->wire_data[wire.index].name.get();
    std::string prefix2 = basename.substr(0, 2);
    std::string prefix7 = basename.substr(0, 7);
    if (prefix2 == "G_" || prefix2 == "L_" || prefix2 == "R_" || prefix2 == "U_" || prefix2 == "D_" || prefix7 == "BRANCH_")
        return basename;
    if (loc == wire.location)
        return basename;
    std::string rel_prefix;
    if (wire.location.y < loc.y)
        rel_prefix += "N" + std::to_string(loc.y - wire.location.y);
    if (wire.location.y > loc.y)
        rel_prefix += "S" + std::to_string(wire.location.y - loc.y);
    if (wire.location.x > loc.x)
        rel_prefix += "E" + std::to_string(wire.location.x - loc.x);
    if (wire.location.x < loc.x)
        rel_prefix += "W" + std::to_string(loc.x - wire.location.x);
    return rel_prefix + "_" + basename;
}

static void set_pip(Context *ctx, ChipConfig &cc, PipId pip)
{
    std::string tile = ctx->getPipTilename(pip);
    std::string source = get_trellis_wirename(ctx, pip.location, ctx->getPipSrcWire(pip));
    std::string sink = get_trellis_wirename(ctx, pip.location, ctx->getPipDstWire(pip));
    cc.tiles[tile].add_arc(sink, source);
}

static std::vector<bool> int_to_bitvector(int val, int size)
{
    std::vector<bool> bv;
    for (int i = 0; i < size; i++) {
        bv.push_back((val & (1 << i)) != 0);
    }
    return bv;
}

static std::vector<bool> str_to_bitvector(std::string str, int size)
{
    std::vector<bool> bv;
    bv.resize(size, 0);
    if (str.substr(0, 2) != "0b")
        log_error("error parsing value '%s', expected 0b prefix\n", str.c_str());
    for (int i = 0; i < int(str.size()) - 2; i++) {
        char c = str.at((str.size() - i) - 1);
        NPNR_ASSERT(c == '0' || c == '1');
        bv.at(i) = (c == '1');
    }
    return bv;
}

std::string intstr_or_default(const std::unordered_map<IdString, Property> &ct, const IdString &key,
                              std::string def = "0")
{
    auto found = ct.find(key);
    if (found == ct.end())
        return def;
    else {
        if (found->second.is_string)
            return found->second.as_string();
        else
            return std::to_string(found->second.as_int64());
    }
};

void write_bitstream(Context *ctx, std::string text_config_file)
{
    ChipConfig cc;

    switch (ctx->args.type) {
    case ArchArgs::LCMXO2_1200HC:
        BaseConfigs::config_empty_lcmxo2_1200hc(cc);
        break;
    default:
        NPNR_ASSERT_FALSE("Unsupported device type");
    }

    cc.metadata.push_back("Part: " + ctx->getFullChipName());

    // Add all set, configurable pips to the config
    for (auto pip : ctx->getPips()) {
        if (ctx->getBoundPipNet(pip) != nullptr) {
            if (ctx->getPipClass(pip) == 0) { // ignore fixed pips
                set_pip(ctx, cc, pip);
            }
        }
    }

    // TODO: Bank Voltages

    // Configure slices
    for (auto &cell : ctx->cells) {
        CellInfo *ci = cell.second.get();
        if (ci->bel == BelId()) {
            log_warning("found unplaced cell '%s' during bitstream gen\n", ci->name.c_str(ctx));
        }
        BelId bel = ci->bel;
        if (ci->type == id_FACADE_SLICE) {
            std::string tname = ctx->getTileByTypeAndLocation(bel.location.y, bel.location.x, "PLC");
            std::string slice = ctx->tileInfo(bel)->bel_data[bel.index].name.get();

            NPNR_ASSERT(slice.substr(0, 5) == "SLICE");
            int int_index = slice[5] - 'A';
            NPNR_ASSERT(int_index >= 0 && int_index < 4);

            int lut0_init = int_or_default(ci->params, ctx->id("LUT0_INITVAL"));
            int lut1_init = int_or_default(ci->params, ctx->id("LUT1_INITVAL"));
            cc.tiles[tname].add_word(slice + ".K0.INIT", int_to_bitvector(lut0_init, 16));
            cc.tiles[tname].add_word(slice + ".K1.INIT", int_to_bitvector(lut1_init, 16));
            cc.tiles[tname].add_enum(slice + ".MODE", str_or_default(ci->params, ctx->id("MODE"), "LOGIC"));
            cc.tiles[tname].add_enum(slice + ".GSR", str_or_default(ci->params, ctx->id("GSR"), "ENABLED"));
            cc.tiles[tname].add_enum("LSR" + std::to_string(int_index) + ".SRMODE", str_or_default(ci->params, ctx->id("SRMODE"), "LSR_OVER_CE"));
            cc.tiles[tname].add_enum(slice + ".CEMUX", intstr_or_default(ci->params, ctx->id("CEMUX"), "1"));
            cc.tiles[tname].add_enum("CLK" + std::to_string(int_index) + ".CLKMUX", intstr_or_default(ci->params, ctx->id("CLKMUX"), "0"));
            cc.tiles[tname].add_enum("LSR" + std::to_string(int_index) + ".LSRMUX", str_or_default(ci->params, ctx->id("LSRMUX"), "LSR"));
            cc.tiles[tname].add_enum("LSR" + std::to_string(int_index) + ".LSRONMUX", intstr_or_default(ci->params, ctx->id("LSRONMUX"), "LSRMUX"));
            cc.tiles[tname].add_enum(slice + ".REGMODE", str_or_default(ci->params, ctx->id("REGMODE"), "FF"));
            cc.tiles[tname].add_enum(slice + ".REG0.SD", intstr_or_default(ci->params, ctx->id("REG0_SD"), "0"));
            cc.tiles[tname].add_enum(slice + ".REG1.SD", intstr_or_default(ci->params, ctx->id("REG1_SD"), "0"));
            cc.tiles[tname].add_enum(slice + ".REG0.REGSET",
                                     str_or_default(ci->params, ctx->id("REG0_REGSET"), "RESET"));
            cc.tiles[tname].add_enum(slice + ".REG1.REGSET",
                                     str_or_default(ci->params, ctx->id("REG1_REGSET"), "RESET"));
        }
    }

    // Configure chip
    if (!text_config_file.empty()) {
        std::ofstream out_config(text_config_file);
        out_config << cc;
    }
}

NEXTPNR_NAMESPACE_END
<|endoftext|>


<commit_before>/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

/* HANDLER ... commands - direct access to ISAM */

#include "mysql_priv.h"
#include "sql_select.h"
#include <assert.h>

/* TODO:
  HANDLER blabla OPEN [ AS foobar ] [ (column-list) ]

  the most natural (easiest, fastest) way to do it is to
  compute List<Item> field_list not in mysql_ha_read
  but in mysql_ha_open, and then store it in TABLE structure.

  The problem here is that mysql_parse calls free_item to free all the
  items allocated at the end of every query. The workaround would to
  keep two item lists per THD - normal free_list and handler_items.
  The second is to be freeed only on thread end. mysql_ha_open should
  then do { handler_items=concat(handler_items, free_list); free_list=0; }

  But !!! do_cammand calls free_root at the end of every query and frees up
  all the sql_alloc'ed memory. It's harder to work around...
 */

#define HANDLER_TABLES_HACK(thd) {      \
  TABLE *tmp=thd->open_tables;          \
  thd->open_tables=thd->handler_tables; \
  thd->handler_tables=tmp; }

static TABLE **find_table_ptr_by_name(THD *thd,const char *db,
				      const char *table_name, bool is_alias);

int mysql_ha_open(THD *thd, TABLE_LIST *tables)
{
  HANDLER_TABLES_HACK(thd);
  int err=open_tables(thd,tables);
  HANDLER_TABLES_HACK(thd);
  if (err)
    return -1;

  // there can be only one table in *tables
  if (!(tables->table->file->table_flags() & HA_CAN_SQL_HANDLER))
  {
    my_printf_error(ER_ILLEGAL_HA,ER(ER_ILLEGAL_HA),MYF(0), tables->alias);
    mysql_ha_close(thd, tables,1);
    return -1;
  }

  send_ok(&thd->net);
  return 0;
}

int mysql_ha_close(THD *thd, TABLE_LIST *tables, bool dont_send_ok)
{
  TABLE **ptr=find_table_ptr_by_name(thd, tables->db, tables->alias, 1);

  if (*ptr)
  {
    VOID(pthread_mutex_lock(&LOCK_open));
    close_thread_table(thd, ptr);
    VOID(pthread_mutex_unlock(&LOCK_open));
  }
  else
  {
    my_printf_error(ER_UNKNOWN_TABLE,ER(ER_UNKNOWN_TABLE),MYF(0),
		    tables->alias, "HANDLER");
    return -1;
  }
  if (!dont_send_ok)
    send_ok(&thd->net);
  return 0;
}

int mysql_ha_closeall(THD *thd, TABLE_LIST *tables)
{
  TABLE **ptr=find_table_ptr_by_name(thd, tables->db, tables->real_name, 0);
  if (*ptr)
    close_thread_table(thd, ptr);
  return 0;
}

static enum enum_ha_read_modes rkey_to_rnext[]=
    { RNEXT, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV };

int mysql_ha_read(THD *thd, TABLE_LIST *tables,
    enum enum_ha_read_modes mode, char *keyname, List<Item> *key_expr,
    enum ha_rkey_function ha_rkey_mode, Item *cond,
    ha_rows select_limit,ha_rows offset_limit)
{
  int err, keyno=-1;
  TABLE *table=*find_table_ptr_by_name(thd, tables->db, tables->alias, 1);
  if (!table)
  {
    my_printf_error(ER_UNKNOWN_TABLE,ER(ER_UNKNOWN_TABLE),MYF(0),
		    tables->alias,"HANDLER");
    return -1;
  }
  tables->table=table;

  if (cond && cond->fix_fields(thd,tables))
    return -1;

  table->file->init_table_handle_for_HANDLER(); // Only InnoDB requires it

  if (keyname)
  {
    if ((keyno=find_type(keyname, &table->keynames, 1+2)-1)<0)
    {
      my_printf_error(ER_KEY_DOES_NOT_EXITS,ER(ER_KEY_DOES_NOT_EXITS),MYF(0),
          keyname,tables->alias);
      return -1;
    }
    table->file->index_init(keyno);
  }

  List<Item> list;
  list.push_front(new Item_field(NULL,NULL,"*"));
  List_iterator<Item> it(list);
  uint num_rows;
  it++;

  insert_fields(thd,tables,tables->db,tables->alias,&it);

  select_limit+=offset_limit;
  send_fields(thd,list,1);

  HANDLER_TABLES_HACK(thd);
  MYSQL_LOCK *lock=mysql_lock_tables(thd,&tables->table,1);
  HANDLER_TABLES_HACK(thd);
  if (!lock)
     goto err0; // mysql_lock_tables() printed error message already

  table->file->init_table_handle_for_HANDLER(); // Only InnoDB requires it

  for (num_rows=0; num_rows < select_limit; )
  {
    switch(mode) {
    case RFIRST:
      if (keyname)
        err=table->file->index_first(table->record[0]);
      else
      {
	if (!(err=table->file->rnd_init(1)))
          err=table->file->rnd_next(table->record[0]);
      }
      mode=RNEXT;
      break;
    case RLAST:
      DBUG_ASSERT(keyname != 0);
      err=table->file->index_last(table->record[0]);
      mode=RPREV;
      break;
    case RNEXT:
      err=keyname ?
	table->file->index_next(table->record[0]) :
	table->file->rnd_next(table->record[0]);
      break;
    case RPREV:
      DBUG_ASSERT(keyname != 0);
      err=table->file->index_prev(table->record[0]);
      break;
    case RKEY:
    {
      DBUG_ASSERT(keyname != 0);
      KEY *keyinfo=table->key_info+keyno;
      KEY_PART_INFO *key_part=keyinfo->key_part;
      uint key_len;
      byte *key;
      if (key_expr->elements > keyinfo->key_parts)
      {
	my_printf_error(ER_TOO_MANY_KEY_PARTS,ER(ER_TOO_MANY_KEY_PARTS),
			MYF(0),keyinfo->key_parts);
	goto err;
      }
      List_iterator_fast<Item> it_ke(*key_expr);
      Item *item;
      for (key_len=0 ; (item=it_ke++) ; key_part++)
      {
	if (item->fix_fields(thd, tables))
	    return -1;
	item->save_in_field(key_part->field, 1);
	key_len+=key_part->store_length;
      }
      if (!(key= (byte*) thd->calloc(ALIGN_SIZE(key_len))))
      {
	send_error(&thd->net,ER_OUTOFMEMORY);
	goto err;
      }
      key_copy(key, table, keyno, key_len);
      err=table->file->index_read(table->record[0],
				  key,key_len,ha_rkey_mode);
      mode=rkey_to_rnext[(int)ha_rkey_mode];
      break;
    }
    default:
      send_error(&thd->net,ER_ILLEGAL_HA);
      goto err;
    }

    if (err)
    {
      if (err != HA_ERR_KEY_NOT_FOUND && err != HA_ERR_END_OF_FILE)
      {
        sql_print_error("mysql_ha_read: Got error %d when reading table",
                        err);
        table->file->print_error(err,MYF(0));
        goto err;
      }
      goto ok;
    }
    if (cond)
    {
      err=err;
      if (!cond->val_int())
        continue;
    }
    if (num_rows>=offset_limit)
    {
      if (!err)
      {
        String *packet = &thd->packet;
        Item *item;
        packet->length(0);
        it.rewind();
        while ((item=it++))
        {
          if (item->send(thd,packet))
          {
            packet->free();                             // Free used
            my_error(ER_OUT_OF_RESOURCES,MYF(0));
            goto err;
          }
        }
        my_net_write(&thd->net, (char*)packet->ptr(), packet->length());
      }
    }
    num_rows++;
  }
ok:
  mysql_unlock_tables(thd,lock);
  send_eof(&thd->net);
  return 0;
err:
  mysql_unlock_tables(thd,lock);
err0:
  return -1;
}

static TABLE **find_table_ptr_by_name(THD *thd, const char *db,
				      const char *table_name, bool is_alias)
{
  int dblen;
  TABLE **ptr;

  if (!db || ! *db)
    db= thd->db ? thd->db : "";
  dblen=strlen(db)+1;
  ptr=&(thd->handler_tables);

  for (TABLE *table=*ptr; table ; table=*ptr)
  {
    if (!memcmp(table->table_cache_key, db, dblen) &&
        !my_strcasecmp((is_alias ? table->table_name : table->real_name),table_name))
      break;
    ptr=&(table->next);
  }
  return ptr;
}

<commit_msg>Fixed memory/lock leak from bug fix<commit_after>/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB

   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

/* HANDLER ... commands - direct access to ISAM */

#include "mysql_priv.h"
#include "sql_select.h"
#include <assert.h>

/* TODO:
  HANDLER blabla OPEN [ AS foobar ] [ (column-list) ]

  the most natural (easiest, fastest) way to do it is to
  compute List<Item> field_list not in mysql_ha_read
  but in mysql_ha_open, and then store it in TABLE structure.

  The problem here is that mysql_parse calls free_item to free all the
  items allocated at the end of every query. The workaround would to
  keep two item lists per THD - normal free_list and handler_items.
  The second is to be freeed only on thread end. mysql_ha_open should
  then do { handler_items=concat(handler_items, free_list); free_list=0; }

  But !!! do_cammand calls free_root at the end of every query and frees up
  all the sql_alloc'ed memory. It's harder to work around...
 */

#define HANDLER_TABLES_HACK(thd) {      \
  TABLE *tmp=thd->open_tables;          \
  thd->open_tables=thd->handler_tables; \
  thd->handler_tables=tmp; }

static TABLE **find_table_ptr_by_name(THD *thd,const char *db,
				      const char *table_name, bool is_alias);

int mysql_ha_open(THD *thd, TABLE_LIST *tables)
{
  HANDLER_TABLES_HACK(thd);
  int err=open_tables(thd,tables);
  HANDLER_TABLES_HACK(thd);
  if (err)
    return -1;

  // there can be only one table in *tables
  if (!(tables->table->file->table_flags() & HA_CAN_SQL_HANDLER))
  {
    my_printf_error(ER_ILLEGAL_HA,ER(ER_ILLEGAL_HA),MYF(0), tables->alias);
    mysql_ha_close(thd, tables,1);
    return -1;
  }

  send_ok(&thd->net);
  return 0;
}

int mysql_ha_close(THD *thd, TABLE_LIST *tables, bool dont_send_ok)
{
  TABLE **ptr=find_table_ptr_by_name(thd, tables->db, tables->alias, 1);

  if (*ptr)
  {
    VOID(pthread_mutex_lock(&LOCK_open));
    close_thread_table(thd, ptr);
    VOID(pthread_mutex_unlock(&LOCK_open));
  }
  else
  {
    my_printf_error(ER_UNKNOWN_TABLE,ER(ER_UNKNOWN_TABLE),MYF(0),
		    tables->alias, "HANDLER");
    return -1;
  }
  if (!dont_send_ok)
    send_ok(&thd->net);
  return 0;
}

int mysql_ha_closeall(THD *thd, TABLE_LIST *tables)
{
  TABLE **ptr=find_table_ptr_by_name(thd, tables->db, tables->real_name, 0);
  if (*ptr)
    close_thread_table(thd, ptr);
  return 0;
}

static enum enum_ha_read_modes rkey_to_rnext[]=
    { RNEXT, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV };

int mysql_ha_read(THD *thd, TABLE_LIST *tables,
    enum enum_ha_read_modes mode, char *keyname, List<Item> *key_expr,
    enum ha_rkey_function ha_rkey_mode, Item *cond,
    ha_rows select_limit,ha_rows offset_limit)
{
  int err, keyno=-1;
  TABLE *table=*find_table_ptr_by_name(thd, tables->db, tables->alias, 1);
  if (!table)
  {
    my_printf_error(ER_UNKNOWN_TABLE,ER(ER_UNKNOWN_TABLE),MYF(0),
		    tables->alias,"HANDLER");
    return -1;
  }
  tables->table=table;

  if (cond && cond->fix_fields(thd,tables))
    return -1;

  table->file->init_table_handle_for_HANDLER(); // Only InnoDB requires it

  if (keyname)
  {
    if ((keyno=find_type(keyname, &table->keynames, 1+2)-1)<0)
    {
      my_printf_error(ER_KEY_DOES_NOT_EXITS,ER(ER_KEY_DOES_NOT_EXITS),MYF(0),
          keyname,tables->alias);
      return -1;
    }
    table->file->index_init(keyno);
  }

  List<Item> list;
  list.push_front(new Item_field(NULL,NULL,"*"));
  List_iterator<Item> it(list);
  uint num_rows;
  it++;

  insert_fields(thd,tables,tables->db,tables->alias,&it);

  select_limit+=offset_limit;
  send_fields(thd,list,1);

  HANDLER_TABLES_HACK(thd);
  MYSQL_LOCK *lock=mysql_lock_tables(thd,&tables->table,1);
  HANDLER_TABLES_HACK(thd);
  if (!lock)
     goto err0; // mysql_lock_tables() printed error message already

  table->file->init_table_handle_for_HANDLER(); // Only InnoDB requires it

  for (num_rows=0; num_rows < select_limit; )
  {
    switch(mode) {
    case RFIRST:
      if (keyname)
        err=table->file->index_first(table->record[0]);
      else
      {
	if (!(err=table->file->rnd_init(1)))
          err=table->file->rnd_next(table->record[0]);
      }
      mode=RNEXT;
      break;
    case RLAST:
      DBUG_ASSERT(keyname != 0);
      err=table->file->index_last(table->record[0]);
      mode=RPREV;
      break;
    case RNEXT:
      err=keyname ?
	table->file->index_next(table->record[0]) :
	table->file->rnd_next(table->record[0]);
      break;
    case RPREV:
      DBUG_ASSERT(keyname != 0);
      err=table->file->index_prev(table->record[0]);
      break;
    case RKEY:
    {
      DBUG_ASSERT(keyname != 0);
      KEY *keyinfo=table->key_info+keyno;
      KEY_PART_INFO *key_part=keyinfo->key_part;
      uint key_len;
      byte *key;
      if (key_expr->elements > keyinfo->key_parts)
      {
	my_printf_error(ER_TOO_MANY_KEY_PARTS,ER(ER_TOO_MANY_KEY_PARTS),
			MYF(0),keyinfo->key_parts);
	goto err;
      }
      List_iterator_fast<Item> it_ke(*key_expr);
      Item *item;
      for (key_len=0 ; (item=it_ke++) ; key_part++)
      {
	if (item->fix_fields(thd, tables))
	  goto err;
	item->save_in_field(key_part->field, 1);
	key_len+=key_part->store_length;
      }
      if (!(key= (byte*) thd->calloc(ALIGN_SIZE(key_len))))
      {
	send_error(&thd->net,ER_OUTOFMEMORY);
	goto err;
      }
      key_copy(key, table, keyno, key_len);
      err=table->file->index_read(table->record[0],
				  key,key_len,ha_rkey_mode);
      mode=rkey_to_rnext[(int)ha_rkey_mode];
      break;
    }
    default:
      send_error(&thd->net,ER_ILLEGAL_HA);
      goto err;
    }

    if (err)
    {
      if (err != HA_ERR_KEY_NOT_FOUND && err != HA_ERR_END_OF_FILE)
      {
        sql_print_error("mysql_ha_read: Got error %d when reading table",
                        err);
        table->file->print_error(err,MYF(0));
        goto err;
      }
      goto ok;
    }
    if (cond)
    {
      err=err;
      if (!cond->val_int())
        continue;
    }
    if (num_rows>=offset_limit)
    {
      if (!err)
      {
        String *packet = &thd->packet;
        Item *item;
        packet->length(0);
        it.rewind();
        while ((item=it++))
        {
          if (item->send(thd,packet))
          {
            packet->free();                             // Free used
            my_error(ER_OUT_OF_RESOURCES,MYF(0));
            goto err;
          }
        }
        my_net_write(&thd->net, (char*)packet->ptr(), packet->length());
      }
    }
    num_rows++;
  }
ok:
  mysql_unlock_tables(thd,lock);
  send_eof(&thd->net);
  return 0;
err:
  mysql_unlock_tables(thd,lock);
err0:
  return -1;
}

static TABLE **find_table_ptr_by_name(THD *thd, const char *db,
				      const char *table_name, bool is_alias)
{
  int dblen;
  TABLE **ptr;

  if (!db || ! *db)
    db= thd->db ? thd->db : "";
  dblen=strlen(db)+1;
  ptr=&(thd->handler_tables);

  for (TABLE *table=*ptr; table ; table=*ptr)
  {
    if (!memcmp(table->table_cache_key, db, dblen) &&
        !my_strcasecmp((is_alias ? table->table_name : table->real_name),table_name))
      break;
    ptr=&(table->next);
  }
  return ptr;
}

<|endoftext|>


<commit_before>#include "Atm_player.hpp"

/* Add optional parameters for the state machine to begin()
 * Add extra initialization code
 */

Atm_player& Atm_player::begin( int pin /* = - 1 */ ) {
  // clang-format off
  const static state_t state_table[] PROGMEM = {
    /*             ON_ENTER    ON_LOOP  ON_EXIT  EVT_START  EVT_STOP  EVT_TOGGLE  EVT_TIMER  EVT_EOPAT  EVT_REPEAT   ELSE */
    /*   IDLE */   ENT_IDLE, ATM_SLEEP,      -1,     START,       -1,      START,        -1,        -1,         -1,    -1,
    /*  START */  ENT_START,        -1,      -1,        -1,       -1,         -1,        -1,        -1,         -1, SOUND,
    /*  SOUND */  ENT_SOUND,        -1,      -1,        -1,     IDLE,       IDLE,     QUIET,        -1,         -1,    -1,
    /*  QUIET */  ENT_QUIET,        -1,      -1,        -1,     IDLE,       IDLE,      NEXT,        -1,         -1,    -1,
    /*   NEXT */   ENT_NEXT,        -1,      -1,        -1,     IDLE,       IDLE,        -1,    REPEAT,         -1, SOUND,
    /* REPEAT */ ENT_REPEAT,        -1,      -1,        -1,     IDLE,       IDLE,        -1,        -1,     FINISH, START,
    /* FINISH */ ENT_FINISH,        -1,      -1,        -1,       -1,         -1,        -1,        -1,       IDLE, START,
  };
  Machine::begin( state_table, ELSE );
  Atm_player::pin = pin;
  counter_repeat.set( repeatCount = 1 );
  speed( 100 );
  return *this;
}

/* Add C++ code for each event (input)
 * The code must return 1 if the event should be triggered
 */

int Atm_player::event( int id ) {
  switch ( id ) {
    case EVT_START:
      return 0;
    case EVT_TIMER:
      return timer.expired( this );
    case EVT_EOPAT:
      return ( step * 3 ) >= ( patternsize / sizeof( pattern[0] ) );
    case EVT_REPEAT:
      return counter_repeat.expired();
  }
  return 0;
}

/* Add C++ code for each action
 * This generates the 'output' for the state machine
 */

void Atm_player::action( int id ) {
  switch ( id ) {
    case ENT_FINISH:
      onfinish.push();
      return;
    case ENT_IDLE:
      if ( pin >= 0 ) noTone( pin );
      counter_repeat.set( repeatCount );
      return;
    case ENT_START:
      step = 0;
      counter_repeat.decrement();
      return;
    case ENT_SOUND:
      onnote[1].push( pattern[step * 3], 1 );
      if ( pin >= 0 ) tone( pin, pattern[step * 3] );
      timer.set( pattern[step * 3 + 1] * speedFactor );
      return;
    case ENT_QUIET:
      onnote[0].push( pattern[step * 3], 0 );
      if ( pin >= 0 ) noTone( pin );
      timer.set( pattern[step * 3 + 2] * speedFactor );
      return;
    case ENT_NEXT:
      step++;
      return;
    case ENT_REPEAT:
      return;
  }
}

/* onNote/onFinish connector initialization
 *
 */

Atm_player& Atm_player::onNote( atm_cb_push_t callback, int idx /* = 0 */ ) {
  onnote[0].set( callback, idx );
  onnote[1].set( callback, idx );
  return *this;
}

Atm_player& Atm_player::onNote( Machine& machine, int event /* = 0 */ ) {
  onnote[0].set( &machine, event );
  onnote[1].set( &machine, event );
  return *this;
}

Atm_player& Atm_player::onNote( bool status, atm_cb_push_t callback, int idx /* = 0 */ ) {
  onnote[status?1:0].set( callback, idx );
  return *this;
}

Atm_player& Atm_player::onNote( bool status, Machine& machine, int event /* = 0 */ ) {
  onnote[status?1:0].set( &machine, event );
  return *this;
}

Atm_player& Atm_player::onFinish( atm_cb_push_t callback, int idx /* = 0 */ ) {
  onfinish.set( callback, idx );
  return *this;
}

Atm_player& Atm_player::onFinish( Machine& machine, int event /* = 0 */ ) {
  onfinish.set( &machine, event );
  return *this;
}

/* How many times to repeat the pattern
 *
 */

Atm_player& Atm_player::repeat( int v ) {
  counter_repeat.set( repeatCount = v );
  return *this;
}

Atm_player& Atm_player::speed( int v ) {
  speedFactor = 100 / float( v );
  return *this;
}

/* Sets the pattern and pattern length (in bytes)
 *
 */

Atm_player& Atm_player::play( int* pat, int patsize ) {
  pattern = pat;
  patternsize = patsize;
  step = 0;
  return *this;
}

Atm_player& Atm_player::play( int freq, int period, int pause /* = 0 */ ) {
  stub[0] = freq;
  stub[1] = period;
  stub[2] = pause;
  pattern = stub;
  patternsize = 6;
  counter_repeat.set( repeatCount );
  step = 0;
  return *this;
}

/* Optionally override the default trigger() method
 * Control what triggers your machine can and cannot process
 */

Atm_player& Atm_player::trigger( int event ) {
  Machine::trigger( event );
  return *this;
}

/* Optionally override the default state() method
 * Control what the machine returns when another process requests its state()
 */

int Atm_player::state( void ) {
  return Machine::state();
}

/* State trace method
 * Sets the symbol table and the default logging method for serial monitoring
 */

Atm_player& Atm_player::trace( Stream & stream ) {
  Machine::setTrace( &stream, atm_serial_debug::trace,
    "PLAYER\0EVT_START\0EVT_STOP\0EVT_TOGGLE\0EVT_TIMER\0EVT_EOPAT\0EVT_REPEAT\0ELSE\0IDLE\0START\0SOUND\0QUIET\0NEXT\0REPEAT\0FINISH" );
  return *this;
}
<commit_msg>Better way to do pattern chaining<commit_after>#include "Atm_player.hpp"

/* Add optional parameters for the state machine to begin()
 * Add extra initialization code
 */

Atm_player& Atm_player::begin( int pin /* = - 1 */ ) {
  // clang-format off
  const static state_t state_table[] PROGMEM = {
    /*             ON_ENTER    ON_LOOP  ON_EXIT  EVT_START  EVT_STOP  EVT_TOGGLE  EVT_TIMER  EVT_EOPAT  EVT_REPEAT   ELSE */
    /*   IDLE */   ENT_IDLE, ATM_SLEEP,      -1,     START,       -1,      START,        -1,        -1,         -1,    -1,
    /*  START */  ENT_START,        -1,      -1,        -1,       -1,         -1,        -1,        -1,         -1, SOUND,
    /*  SOUND */  ENT_SOUND,        -1,      -1,        -1,     IDLE,       IDLE,     QUIET,        -1,         -1,    -1,
    /*  QUIET */  ENT_QUIET,        -1,      -1,        -1,     IDLE,       IDLE,      NEXT,        -1,         -1,    -1,
    /*   NEXT */   ENT_NEXT,        -1,      -1,        -1,     IDLE,       IDLE,        -1,    REPEAT,         -1, SOUND,
    /* REPEAT */ ENT_REPEAT,        -1,      -1,        -1,     IDLE,       IDLE,        -1,        -1,     FINISH, START,
    /* FINISH */ ENT_FINISH,        -1,      -1,        -1,     IDLE,         -1,        -1,        -1,       IDLE, START,
  };
  Machine::begin( state_table, ELSE );
  Atm_player::pin = pin;
  counter_repeat.set( repeatCount = 1 );
  speed( 100 );
  return *this;
}

/* Add C++ code for each event (input)
 * The code must return 1 if the event should be triggered
 */

int Atm_player::event( int id ) {
  switch ( id ) {
    case EVT_START:
      return 0;
    case EVT_TIMER:
      return timer.expired( this );
    case EVT_EOPAT:
      return ( step * 3 ) >= ( patternsize / sizeof( pattern[0] ) );
    case EVT_REPEAT:
      return counter_repeat.expired();
  }
  return 0;
}

/* Add C++ code for each action
 * This generates the 'output' for the state machine
 */

void Atm_player::action( int id ) {
  switch ( id ) {
    case ENT_FINISH:
      onfinish.push();
      return;
    case ENT_IDLE:
      if ( pin >= 0 ) noTone( pin );
      counter_repeat.set( repeatCount );
      return;
    case ENT_START:
      step = 0;
      counter_repeat.decrement();
      return;
    case ENT_SOUND:
      onnote[1].push( pattern[step * 3], 1 );
      if ( pin >= 0 ) tone( pin, pattern[step * 3] );
      timer.set( pattern[step * 3 + 1] * speedFactor );
      return;
    case ENT_QUIET:
      onnote[0].push( pattern[step * 3], 0 );
      if ( pin >= 0 ) noTone( pin );
      timer.set( pattern[step * 3 + 2] * speedFactor );
      return;
    case ENT_NEXT:
      step++;
      return;
    case ENT_REPEAT:
      return;
  }
}

/* onNote/onFinish connector initialization
 *
 */

Atm_player& Atm_player::onNote( atm_cb_push_t callback, int idx /* = 0 */ ) {
  onnote[0].set( callback, idx );
  onnote[1].set( callback, idx );
  return *this;
}

Atm_player& Atm_player::onNote( Machine& machine, int event /* = 0 */ ) {
  onnote[0].set( &machine, event );
  onnote[1].set( &machine, event );
  return *this;
}

Atm_player& Atm_player::onNote( bool status, atm_cb_push_t callback, int idx /* = 0 */ ) {
  onnote[status?1:0].set( callback, idx );
  return *this;
}

Atm_player& Atm_player::onNote( bool status, Machine& machine, int event /* = 0 */ ) {
  onnote[status?1:0].set( &machine, event );
  return *this;
}

Atm_player& Atm_player::onFinish( atm_cb_push_t callback, int idx /* = 0 */ ) {
  onfinish.set( callback, idx );
  return *this;
}

Atm_player& Atm_player::onFinish( Machine& machine, int event /* = 0 */ ) {
  onfinish.set( &machine, event );
  return *this;
}

/* How many times to repeat the pattern
 *
 */

Atm_player& Atm_player::repeat( int v ) {
  counter_repeat.set( repeatCount = v );
  return *this;
}

Atm_player& Atm_player::speed( int v ) {
  speedFactor = 100 / float( v );
  return *this;
}

/* Sets the pattern and pattern length (in bytes)
 *
 */

Atm_player& Atm_player::play( int* pat, int patsize ) {
  pattern = pat;
  patternsize = patsize;
  counter_repeat.set( repeatCount );
  step = 0;
  return *this;
}

Atm_player& Atm_player::play( int freq, int period, int pause /* = 0 */ ) {
  stub[0] = freq;
  stub[1] = period;
  stub[2] = pause;
  pattern = stub;
  patternsize = 6;
  step = 0;
  return *this;
}

/* Optionally override the default trigger() method
 * Control what triggers your machine can and cannot process
 */

Atm_player& Atm_player::trigger( int event ) {
  Machine::trigger( event );
  return *this;
}

/* Optionally override the default state() method
 * Control what the machine returns when another process requests its state()
 */

int Atm_player::state( void ) {
  return Machine::state();
}

/* State trace method
 * Sets the symbol table and the default logging method for serial monitoring
 */

Atm_player& Atm_player::trace( Stream & stream ) {
  Machine::setTrace( &stream, atm_serial_debug::trace,
    "PLAYER\0EVT_START\0EVT_STOP\0EVT_TOGGLE\0EVT_TIMER\0EVT_EOPAT\0EVT_REPEAT\0ELSE\0IDLE\0START\0SOUND\0QUIET\0NEXT\0REPEAT\0FINISH" );
  return *this;
}
<|endoftext|>


<commit_before>// WiringPi-Api einbinden
#include <wiringPi.h>

//Rest einbinden
#include <iostream>
#include "sha256.h"
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sstream>
#include <curl/curl.h>

using namespace std;

template <typename T>
string to_string(T value)
{
        ostringstream os ;
        os << value ;
        return os.str() ;
}

//der Status wird übertragen an den Bashscript
int send(string status){
int random = 000000;
int salt  = 000000;

srand (time(NULL));		//random zeug
random = rand() % 9999 + 10000; //random nummer erzeugen 100000 bis 999999

string input;
input = to_string(random + salt); //nur Strings können gehasht werden und random wird gesalzen durch addition

string hash = sha256(input); //hashpower!

stringstream sstr;
sstr << "hash=" << hash << "&pin=" << random << "&status=" << status;
string befehl = sstr.str();

//cout << befehl << endl;

  CURL *curl;
  CURLcode res;

  //static const char *postthis="hash=hash1337&pin=pin2448&status=statusoffen";
	//static const
	const char* postthis = befehl.c_str();

  curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_URL, "nordlab-ev.de/doorstate/setdoorstate.php");
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postthis);

    /* if we don't provide POSTFIELDSIZE, libcurl will strlen() by
       itself */
    curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen(postthis));

    /* Perform the request, res will get the return code */
    res = curl_easy_perform(curl);
    /* Check for errors */
    if(res != CURLE_OK)
      fprintf(stderr, "curl_easy_perform() failed: %s\n",
              curl_easy_strerror(res));

    /* always cleanup */
    curl_easy_cleanup(curl);
  }

}

int main()
{

int last = 2;   //zum start gleich null setzten ist doof, villeicht ist der status noch nicht gemeldet
                //dh. sensor sagt 0 und auf der webseite ist nochd er alte wert 1 ... daher einmal alles melden

        // Starte die WiringPi-Api (wichtig)
        if (wiringPiSetup() == -1)
        return 1;

	//Ja sind mehr als nötig, aber wer weiß was noch dazu kommt :>
        // Schalte GPIO 17 (=WiringPi Pin 0) auf Eingang
        pinMode(0, INPUT);

        // Schalte GPIO 27 (=WiringPi Pin 2) auf Eingang
        pinMode(2, INPUT);

        // Schalte GPIO 22 (=WiringPi Pin 3) auf Eingang
        pinMode(3, INPUT);

        // Dauerschleife
        while(1) {
        delay(1000); //bremseeee ...

        // GPIO lesen
        if(digitalRead(3)==1 && (last == 0 || last == 2)) {
                printf("Geschlossen\n");
                //status = "geschlossen";
                send("geschlossen");
                last = 1;
                delay(1000); //noch ne bremse ... macht kein sinn aber bremsen stören heir ja nicht
        }
        if(digitalRead(3)==0 && (last == 1 || last == 2)){
                printf("Geöffnet\n");
                //status = "offen";
                send("offen");
                last = 0;
                delay(1000); //noch ne bremse ... macht kein sinn aber bremsen stören heir ja nicht
        }
}
return 0;
}

<commit_msg>Cleanup code a bit (indentation, unused code, ...)<commit_after>// WiringPi-API einbinden
#include <wiringPi.h>

// Rest einbinden
#include <iostream>
#include "sha256.h"
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sstream>
#include <curl/curl.h>

using namespace std;

template <typename T>
string to_string(T value)
{
	ostringstream os;
	os << value;

	return os.str();
}

// Status an Webseite übertragen
int send(string status)
{
	int random = 0;
	int salt = 0;

	// Random Zeug
	srand (time(NULL));
	// zufällige Nummer erzeugen (100000 bis 999999)
	random = rand() % 9999 + 10000;

	string input;
	//nur Strings können gehasht werden und random wird gesalzen durch addition
	input = to_string(random + salt);

	string hash = sha256(input); //hashpower!

	stringstream sstr;
	sstr << "hash=" << hash << "&pin=" << random << "&status=" << status;
	string befehl = sstr.str();

	CURL *curl;
	CURLcode res;

	const char* postthis = befehl.c_str();

	curl = curl_easy_init();
	if (curl) {
		curl_easy_setopt(curl, CURLOPT_URL, "nordlab-ev.de/doorstate/setdoorstate.php");
		curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postthis);

		// If we don't provide POSTFIELDSIZE, libcurl will strlen() by itself
		curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen(postthis));

		// Perform the request, res will get the return code
		res = curl_easy_perform(curl);

		// Check for errors
		if (res != CURLE_OK)
			fprintf(stderr, "curl_easy_perform() failed: %s\n",
				curl_easy_strerror(res));

		// Always cleanup
		curl_easy_cleanup(curl);
	}
}

int main()
{
	// zum start gleich null setzten ist doof, vielleicht ist der status noch nicht gemeldet
	// dh. sensor sagt 0 und auf der webseite ist noch der alte wert 1 ... daher einmal alles melden
	int last = 2;

	// Starte die WiringPi-API (wichtig)
	if (wiringPiSetup() == -1)
		return 1;

	// Ja sind mehr als nötig, aber wer weiß was noch dazu kommt :>
	// Schalte GPIO 17 (=WiringPi Pin 0) auf Eingang
	pinMode(0, INPUT);

	// Schalte GPIO 27 (=WiringPi Pin 2) auf Eingang
	pinMode(2, INPUT);

	// Schalte GPIO 22 (=WiringPi Pin 3) auf Eingang
	pinMode(3, INPUT);

	// Dauerschleife
	while (1) {
		delay(1000); //bremseeee ...

		// GPIO lesen
		if (digitalRead(3)==1 && (last == 0 || last == 2)) {
			printf("Geschlossen\n");
			//status = "geschlossen";
			send("geschlossen");
			last = 1;
			delay(1000); //noch ne bremse ... macht kein sinn aber bremsen stören hier ja nicht
		}
		if (digitalRead(3)==0 && (last == 1 || last == 2)) {
			printf("Geöffnet\n");
			//status = "offen";
			send("offen");
			last = 0;
			delay(1000); //noch ne bremse ... macht kein sinn aber bremsen stören hier ja nicht
        }
	}

	return 0;
}
<|endoftext|>


<commit_before>/*!
 *  Copyright (c) 2016 by Contributors
 * \file plan_memory.cc
 * \brief Assign memory tag to each of the data entries.
 */
#include <nnvm/graph.h>
#include <nnvm/pass.h>
#include <nnvm/graph_attr_types.h>
#include <nnvm/op_attr_types.h>
#include <memory>
#include "./graph_algorithm.h"

namespace nnvm {
namespace pass {
namespace {

// simple graph based allocator.
class GraphAllocator {
 public:
  // storage id equals integer.
  using StorageID = int;

  // bad storage id
  static const StorageID kBadStorageID = -1;
  // external storage id
  static const StorageID kExternalStorageID = -2;

  // request a free storage
  StorageID Request(int dev_id, int dtype, TShape shape, uint32_t node_id) {
    if (shape.ndim() == 0) return kBadStorageID;
    // search memory block in [size / match_range_, size * match_range_)
    // TODO(tqchen) add size of the dtype, assume 4 bytes for now
    size_t size = shape.Size() * 4;
    if (match_range_ == 0) return this->Alloc(dev_id, size);
    auto begin = free_.lower_bound(size / match_range_);
    auto mid = free_.lower_bound(size);
    auto end = free_.upper_bound(size * match_range_);
    // search for memory blocks larger than requested
    for (auto it = mid; it != end; ++it) {
      StorageEntry *e = it->second;
      if (e->device_id != dev_id) continue;
      if (node_color_.size() != 0 &&
          node_color_[e->released_by_node] != node_color_[node_id]) continue;
      // Use exect matching strategy
      e->max_bytes = std::max(size, e->max_bytes);
      // find a exact match, erase from map and return
      free_.erase(it);
      return e->id;
    }
    // then search for memory blocks smaller than requested space
    for (auto it = mid; it != begin;) {
      --it;
      StorageEntry *e = it->second;
      if (e->device_id != dev_id) continue;
      if (node_color_.size() != 0 &&
          node_color_[e->released_by_node] != node_color_[node_id]) continue;
      // Use exect matching strategy
      e->max_bytes = std::max(size, e->max_bytes);
      // erase from map and return
      free_.erase(it);
      return e->id;
    }
    // cannot find anything return a new one.
    return this->Alloc(dev_id, size);
  }
  // release a memory space.
  void Release(StorageID id, uint32_t node_id) {
    CHECK_NE(id, kBadStorageID);
    if (id == kExternalStorageID) return;
    StorageEntry *e = data_[id].get();
    e->released_by_node = node_id;
    free_.insert({e->max_bytes, e});
  }

  // totoal number of bytes allocated
  size_t TotalAllocBytes() const {
    size_t total = 0;
    for (auto &p : data_) {
      total += p->max_bytes;
    }
    return total;
  }

  // constructor
  explicit GraphAllocator(const IndexedGraph* idx, const size_t match_range) : idx_(idx) {
    this->Init(match_range, dmlc::GetEnv("NNVM_EXEC_NUM_TEMP", 1));
  }

 private:
  // initialize the graph allocator
  void Init(const size_t match_range, const uint32_t num_match_color) {
    match_range_ = match_range;
    num_match_color_ = num_match_color;
    if (num_match_color_ > 1) {
      std::vector<uint32_t> importance(idx_->num_nodes(), 0);
      for (uint32_t nid = 0; nid < idx_->num_nodes(); ++nid) {
        if ((*idx_)[nid].source->is_variable()) continue;
        importance[nid] = 1;
      }
      num_match_color_ = pass::ColorNodeGroup(
          *idx_, importance, num_match_color_, &node_color_);
    }
  }

  StorageID Alloc(int dev_id, size_t size) {
    StorageID id = static_cast<StorageID>(data_.size());
    std::unique_ptr<StorageEntry> ptr(new StorageEntry());
    ptr->id = id;
    ptr->device_id = dev_id;
    ptr->max_bytes = size;
    data_.emplace_back(std::move(ptr));
    return id;
  }
  // internal storage entry
  struct StorageEntry {
    // the id of the entry.
    StorageID id;
    // the device id of the storage.
    int device_id;
    // maximum size of storage requested.
    size_t max_bytes{0};
    // node index that released it last time
    uint32_t released_by_node{0};
  };
  // scale used for rough match
  size_t match_range_;
  // whether use color based match algorithm
  uint32_t num_match_color_{1};
  // the size of each dtype
  std::vector<size_t> dtype_size_dict_;
  // free list of storage entry
  std::multimap<size_t, StorageEntry*> free_;
  // all the storage resources available
  std::vector<std::unique_ptr<StorageEntry> > data_;
  // color of nodes in the graph, used for auxiliary policy making.
  std::vector<uint32_t> node_color_;
  // internal indexed graph
  const IndexedGraph* idx_;
};

/*
 * Internal method to perform the memory allocation for a graph
 * */
size_t AllocMemory(const Graph& ret, const IndexedGraph& idx, StorageVector* storage_ptr,
                   std::vector<int>* storage_inplace_index_ptr, std::vector<uint32_t> ref_count,
                   GraphAllocator* allocator) {
  // Get reference
  auto &storage = *storage_ptr;
  auto &storage_inplace_index = *storage_inplace_index_ptr;

  // Get attributes from the graph
  const ShapeVector& shape_vec = ret.GetAttr<ShapeVector>("shape");
  const DTypeVector& dtype_vec = ret.GetAttr<DTypeVector>("dtype");
  const DeviceVector* device_vec = nullptr;
  static auto& finplace_option = Op::GetAttr<FInplaceOption>("FInplaceOption");

  if (ret.attrs.count("device") != 0) {
    device_vec = &(ret.GetAttr<DeviceVector>("device"));
  }
  size_t num_not_allocated = 0;

  for (uint32_t nid = 0; nid < idx.num_nodes(); ++nid) {
    const auto& inode = idx[nid];
    if (inode.source->is_variable()) continue;
    // check inplace option
    if (finplace_option.count(inode.source->op()) != 0) {
      auto inplace_pairs = finplace_option[inode.source->op()](inode.source->attrs);
      for (auto& kv : inplace_pairs) {
        uint32_t eid_out = idx.entry_id(nid, kv.second);
        uint32_t eid_in = idx.entry_id(inode.inputs[kv.first]);
        if (ref_count[eid_in] == 1 &&
            ref_count[eid_out] != 0 &&
            storage[eid_out] == GraphAllocator::kBadStorageID &&
            storage[eid_in] != GraphAllocator::kBadStorageID &&
            shape_vec[eid_out].Size() == shape_vec[eid_in].Size() &&
            dtype_vec[eid_out] == dtype_vec[eid_in]) {
          // inplace optimization
          storage[eid_out] = storage[eid_in];
          ref_count[eid_in] = 0;
          storage_inplace_index[eid_out] = kv.first;
        }
      }
    }
    // normal allocation
    const int dev_id = (device_vec != nullptr) ? device_vec->at(nid) : 0;
    // sort output nodes based on size before allocating output
    std::multimap<size_t, uint32_t> eids;
    for (uint32_t index = 0; index < inode.source->num_outputs(); ++index) {
      uint32_t eid = idx.entry_id(nid, index);
      if (storage[eid] == GraphAllocator::kBadStorageID) {
        auto &eshape = shape_vec[eid];
        size_t esize = 0;
        if (eshape.ndim() != 0) esize = eshape.Size();
        eids.insert(std::make_pair(esize, eid));
      }
    }
    for (auto rit = eids.rbegin(); rit != eids.rend(); ++rit) {
        uint32_t eid = rit->second;
        storage[eid] = allocator->Request(dev_id, dtype_vec[eid], shape_vec[eid], nid);
    }

    // check if certain inputs is ignored.
    static auto& fignore_inputs = Op::GetAttr<FIgnoreInputs>("FIgnoreInputs");
    std::vector<uint32_t> ignore_inputs;
    if (fignore_inputs.count(inode.source->op()) != 0) {
      ignore_inputs = fignore_inputs[inode.source->op()](inode.source->attrs);
      std::sort(ignore_inputs.begin(), ignore_inputs.end());
    }
    // then free inputs
    for (size_t i = 0; i < inode.inputs.size(); ++i) {
      // ref counter of ignored input is already decreased.
      if (std::binary_search(ignore_inputs.begin(), ignore_inputs.end(), i)) continue;
      const auto& e = inode.inputs[i];
      uint32_t eid = idx.entry_id(e);
      // temp_ref_count == 0 means it is taken by inplace op
      if (ref_count[eid] == 0) continue;
      // if we decrease it to zero, means we are ready to relase
      --ref_count[eid];
      if (ref_count[eid] == 0 && storage[eid] != GraphAllocator::kBadStorageID) {
        allocator->Release(storage[eid], nid);
      }
    }
    // check if there are outputs that can be freeded immediately
    // these output are not referenced by any operator.
    for (uint32_t index = 0; index < inode.source->num_outputs(); ++index) {
      uint32_t eid = idx.entry_id(nid, index);
      if (ref_count[eid] == 0 && storage[eid] != GraphAllocator::kBadStorageID) {
        allocator->Release(storage[eid], nid);
        // use -2 to indicate that the node was never touched.
        storage_inplace_index[eid] = -2;
      }
      if (storage[eid] == GraphAllocator::kBadStorageID) {
        ++num_not_allocated;
      }
    }
  }
  return num_not_allocated;
}

// function to plan memory
Graph PlanMemory(Graph ret) {
  // setup ref counter
  const IndexedGraph& idx = ret.indexed_graph();
  static auto& fignore_inputs = Op::GetAttr<FIgnoreInputs>("FIgnoreInputs");
  // reference counter of each node
  std::vector<uint32_t> ref_count(idx.num_node_entries(), 0);
  // step 1: initialize reference count
  for (uint32_t nid = 0; nid < idx.num_nodes(); ++nid) {
    const auto& inode = idx[nid];
    if (inode.source->is_variable()) continue;
    for (const auto& e : inode.inputs) {
      ++ref_count[idx.entry_id(e)];
    }
    // no dataflow dependency is needed for those are ignored.
    // revoke the dependency counter.
    if (fignore_inputs.count(inode.source->op()) != 0) {
      auto ignore_inputs = fignore_inputs[inode.source->op()](inode.source->attrs);
      for (uint32_t i : ignore_inputs) {
        --ref_count[idx.entry_id(inode.inputs[i])];
      }
    }
  }
  for (const auto& e : idx.outputs()) {
    ++ref_count[idx.entry_id(e)];
  }
  // step 2: allocate memory.
  StorageVector storage;
  if (ret.attrs.count("storage") != 0) {
    storage = ret.MoveCopyAttr<StorageVector>("storage");
  } else {
    storage.resize(idx.num_node_entries(), -1);
  }

  // Search the best NNVM_EXEC_MATCH_RANGE parameter. This is turned off by default
  size_t min_allocated_bytes = -1;
  size_t max_match_range = dmlc::GetEnv("NNVM_EXEC_MATCH_RANGE", 16);
  size_t min_match_range =
         dmlc::GetEnv("NNVM_AUTO_SEARCH_MATCH_RANGE", false) ? 1 : max_match_range;
  for (size_t match_range = min_match_range; match_range <= max_match_range; match_range *= 2) {
    // Make a copy of related fields
    StorageVector storage_vec(storage);
    std::vector<int> storage_inplace_index(idx.num_node_entries(), -1);

    // the allocator
    GraphAllocator allocator(&idx, match_range);

    // number of entries that are not statically allocated.
    size_t storage_num_not_allocated =
      AllocMemory(ret, idx, &storage_vec, &storage_inplace_index, ref_count, &allocator);
    size_t storage_allocated_bytes = allocator.TotalAllocBytes();
    // Choose the plan which leads to minimal memory usage
    if (min_allocated_bytes > storage_allocated_bytes) {
      ret.attrs["storage_id"] = std::make_shared<any>(std::move(storage_vec));
      ret.attrs["storage_inplace_index"] = std::make_shared<any>(std::move(storage_inplace_index));
      ret.attrs["storage_allocated_bytes"] = std::make_shared<any>(storage_allocated_bytes);
      ret.attrs["storage_num_not_allocated"] = std::make_shared<any>(storage_num_not_allocated);
      min_allocated_bytes = storage_allocated_bytes;
    }
  }
  return ret;
}

NNVM_REGISTER_PASS(PlanMemory)
.describe("Plan the memory allocation of each node entries.")
.set_body(PlanMemory)
.set_change_graph(false)
.depend_graph_attr("dtype")
.depend_graph_attr("shape")
.provide_graph_attr("storage_id")
.provide_graph_attr("storage_inplace_index");

}  // namespace
}  // namespace pass
}  // namespace nnvm
<commit_msg>fix (#111)<commit_after>/*!
 *  Copyright (c) 2016 by Contributors
 * \file plan_memory.cc
 * \brief Assign memory tag to each of the data entries.
 */
#include <nnvm/graph.h>
#include <nnvm/pass.h>
#include <nnvm/graph_attr_types.h>
#include <nnvm/op_attr_types.h>
#include <memory>
#include "./graph_algorithm.h"

namespace nnvm {
namespace pass {
namespace {

// simple graph based allocator.
class GraphAllocator {
 public:
  // storage id equals integer.
  using StorageID = int;

  // bad storage id
  static const StorageID kBadStorageID = -1;
  // external storage id
  static const StorageID kExternalStorageID = -2;

  // request a free storage
  StorageID Request(int dev_id, int dtype, TShape shape, uint32_t node_id) {
    if (shape.ndim() == 0) return kBadStorageID;
    // search memory block in [size / match_range_, size * match_range_)
    // TODO(tqchen) add size of the dtype, assume 4 bytes for now
    size_t size = shape.Size() * 4;
    if (match_range_ == 0) return this->Alloc(dev_id, size);
    auto begin = free_.lower_bound(size / match_range_);
    auto mid = free_.lower_bound(size);
    auto end = free_.upper_bound(size * match_range_);
    // search for memory blocks larger than requested
    for (auto it = mid; it != end; ++it) {
      StorageEntry *e = it->second;
      if (e->device_id != dev_id) continue;
      if (node_color_.size() != 0 &&
          node_color_[e->released_by_node] != node_color_[node_id]) continue;
      // Use exect matching strategy
      e->max_bytes = std::max(size, e->max_bytes);
      // find a exact match, erase from map and return
      free_.erase(it);
      return e->id;
    }
    // then search for memory blocks smaller than requested space
    for (auto it = mid; it != begin;) {
      --it;
      StorageEntry *e = it->second;
      if (e->device_id != dev_id) continue;
      if (node_color_.size() != 0 &&
          node_color_[e->released_by_node] != node_color_[node_id]) continue;
      // Use exect matching strategy
      e->max_bytes = std::max(size, e->max_bytes);
      // erase from map and return
      free_.erase(it);
      return e->id;
    }
    // cannot find anything return a new one.
    return this->Alloc(dev_id, size);
  }
  // release a memory space.
  void Release(StorageID id, uint32_t node_id) {
    CHECK_NE(id, kBadStorageID);
    if (id == kExternalStorageID) return;
    StorageEntry *e = data_[id].get();
    e->released_by_node = node_id;
    free_.insert({e->max_bytes, e});
  }

  // totoal number of bytes allocated
  size_t TotalAllocBytes() const {
    size_t total = 0;
    for (auto &p : data_) {
      total += p->max_bytes;
    }
    return total;
  }

  // constructor
  explicit GraphAllocator(const IndexedGraph* idx, const size_t match_range) : idx_(idx) {
    this->Init(match_range, dmlc::GetEnv("NNVM_EXEC_NUM_TEMP", 1));
  }

 private:
  // initialize the graph allocator
  void Init(const size_t match_range, const uint32_t num_match_color) {
    match_range_ = match_range;
    num_match_color_ = num_match_color;
    if (num_match_color_ > 1) {
      std::vector<uint32_t> importance(idx_->num_nodes(), 0);
      for (uint32_t nid = 0; nid < idx_->num_nodes(); ++nid) {
        if ((*idx_)[nid].source->is_variable()) continue;
        importance[nid] = 1;
      }
      num_match_color_ = pass::ColorNodeGroup(
          *idx_, importance, num_match_color_, &node_color_);
    }
  }

  StorageID Alloc(int dev_id, size_t size) {
    StorageID id = static_cast<StorageID>(data_.size());
    std::unique_ptr<StorageEntry> ptr(new StorageEntry());
    ptr->id = id;
    ptr->device_id = dev_id;
    ptr->max_bytes = size;
    data_.emplace_back(std::move(ptr));
    return id;
  }
  // internal storage entry
  struct StorageEntry {
    // the id of the entry.
    StorageID id;
    // the device id of the storage.
    int device_id;
    // maximum size of storage requested.
    size_t max_bytes{0};
    // node index that released it last time
    uint32_t released_by_node{0};
  };
  // scale used for rough match
  size_t match_range_;
  // whether use color based match algorithm
  uint32_t num_match_color_{1};
  // the size of each dtype
  std::vector<size_t> dtype_size_dict_;
  // free list of storage entry
  std::multimap<size_t, StorageEntry*> free_;
  // all the storage resources available
  std::vector<std::unique_ptr<StorageEntry> > data_;
  // color of nodes in the graph, used for auxiliary policy making.
  std::vector<uint32_t> node_color_;
  // internal indexed graph
  const IndexedGraph* idx_;
};

/*
 * Internal method to perform the memory allocation for a graph
 * */
size_t AllocMemory(const Graph& ret, const IndexedGraph& idx, StorageVector* storage_ptr,
                   std::vector<int>* storage_inplace_index_ptr, std::vector<uint32_t> ref_count,
                   GraphAllocator* allocator) {
  // Get reference
  auto &storage = *storage_ptr;
  auto &storage_inplace_index = *storage_inplace_index_ptr;

  // Get attributes from the graph
  const ShapeVector& shape_vec = ret.GetAttr<ShapeVector>("shape");
  const DTypeVector& dtype_vec = ret.GetAttr<DTypeVector>("dtype");
  const DeviceVector* device_vec = nullptr;
  static auto& finplace_option = Op::GetAttr<FInplaceOption>("FInplaceOption");

  if (ret.attrs.count("device") != 0) {
    device_vec = &(ret.GetAttr<DeviceVector>("device"));
  }
  size_t num_not_allocated = 0;

  for (uint32_t nid = 0; nid < idx.num_nodes(); ++nid) {
    const auto& inode = idx[nid];
    if (inode.source->is_variable()) continue;
    // check inplace option
    if (finplace_option.count(inode.source->op()) != 0) {
      auto inplace_pairs = finplace_option[inode.source->op()](inode.source->attrs);
      for (auto& kv : inplace_pairs) {
        uint32_t eid_out = idx.entry_id(nid, kv.second);
        uint32_t eid_in = idx.entry_id(inode.inputs[kv.first]);
        if (ref_count[eid_in] == 1 &&
            ref_count[eid_out] != 0 &&
            storage[eid_out] == GraphAllocator::kBadStorageID &&
            storage[eid_in] >= 0 &&
            shape_vec[eid_out].Size() == shape_vec[eid_in].Size() &&
            dtype_vec[eid_out] == dtype_vec[eid_in]) {
          // inplace optimization
          storage[eid_out] = storage[eid_in];
          ref_count[eid_in] = 0;
          storage_inplace_index[eid_out] = kv.first;
        }
      }
    }
    // normal allocation
    const int dev_id = (device_vec != nullptr) ? device_vec->at(nid) : 0;
    // sort output nodes based on size before allocating output
    std::multimap<size_t, uint32_t> eids;
    for (uint32_t index = 0; index < inode.source->num_outputs(); ++index) {
      uint32_t eid = idx.entry_id(nid, index);
      if (storage[eid] == GraphAllocator::kBadStorageID) {
        auto &eshape = shape_vec[eid];
        size_t esize = 0;
        if (eshape.ndim() != 0) esize = eshape.Size();
        eids.insert(std::make_pair(esize, eid));
      }
    }
    for (auto rit = eids.rbegin(); rit != eids.rend(); ++rit) {
        uint32_t eid = rit->second;
        storage[eid] = allocator->Request(dev_id, dtype_vec[eid], shape_vec[eid], nid);
    }

    // check if certain inputs is ignored.
    static auto& fignore_inputs = Op::GetAttr<FIgnoreInputs>("FIgnoreInputs");
    std::vector<uint32_t> ignore_inputs;
    if (fignore_inputs.count(inode.source->op()) != 0) {
      ignore_inputs = fignore_inputs[inode.source->op()](inode.source->attrs);
      std::sort(ignore_inputs.begin(), ignore_inputs.end());
    }
    // then free inputs
    for (size_t i = 0; i < inode.inputs.size(); ++i) {
      // ref counter of ignored input is already decreased.
      if (std::binary_search(ignore_inputs.begin(), ignore_inputs.end(), i)) continue;
      const auto& e = inode.inputs[i];
      uint32_t eid = idx.entry_id(e);
      // temp_ref_count == 0 means it is taken by inplace op
      if (ref_count[eid] == 0) continue;
      // if we decrease it to zero, means we are ready to relase
      --ref_count[eid];
      if (ref_count[eid] == 0 && storage[eid] != GraphAllocator::kBadStorageID) {
        allocator->Release(storage[eid], nid);
      }
    }
    // check if there are outputs that can be freeded immediately
    // these output are not referenced by any operator.
    for (uint32_t index = 0; index < inode.source->num_outputs(); ++index) {
      uint32_t eid = idx.entry_id(nid, index);
      if (ref_count[eid] == 0 && storage[eid] != GraphAllocator::kBadStorageID) {
        allocator->Release(storage[eid], nid);
        // use -2 to indicate that the node was never touched.
        storage_inplace_index[eid] = -2;
      }
      if (storage[eid] == GraphAllocator::kBadStorageID) {
        ++num_not_allocated;
      }
    }
  }
  return num_not_allocated;
}

// function to plan memory
Graph PlanMemory(Graph ret) {
  // setup ref counter
  const IndexedGraph& idx = ret.indexed_graph();
  static auto& fignore_inputs = Op::GetAttr<FIgnoreInputs>("FIgnoreInputs");
  // reference counter of each node
  std::vector<uint32_t> ref_count(idx.num_node_entries(), 0);
  // step 1: initialize reference count
  for (uint32_t nid = 0; nid < idx.num_nodes(); ++nid) {
    const auto& inode = idx[nid];
    if (inode.source->is_variable()) continue;
    for (const auto& e : inode.inputs) {
      ++ref_count[idx.entry_id(e)];
    }
    // no dataflow dependency is needed for those are ignored.
    // revoke the dependency counter.
    if (fignore_inputs.count(inode.source->op()) != 0) {
      auto ignore_inputs = fignore_inputs[inode.source->op()](inode.source->attrs);
      for (uint32_t i : ignore_inputs) {
        --ref_count[idx.entry_id(inode.inputs[i])];
      }
    }
  }
  for (const auto& e : idx.outputs()) {
    ++ref_count[idx.entry_id(e)];
  }
  // step 2: allocate memory.
  StorageVector storage;
  if (ret.attrs.count("storage") != 0) {
    storage = ret.MoveCopyAttr<StorageVector>("storage");
  } else {
    storage.resize(idx.num_node_entries(), -1);
  }

  // Search the best NNVM_EXEC_MATCH_RANGE parameter. This is turned off by default
  size_t min_allocated_bytes = -1;
  size_t max_match_range = dmlc::GetEnv("NNVM_EXEC_MATCH_RANGE", 16);
  size_t min_match_range =
         dmlc::GetEnv("NNVM_AUTO_SEARCH_MATCH_RANGE", false) ? 1 : max_match_range;
  for (size_t match_range = min_match_range; match_range <= max_match_range; match_range *= 2) {
    // Make a copy of related fields
    StorageVector storage_vec(storage);
    std::vector<int> storage_inplace_index(idx.num_node_entries(), -1);

    // the allocator
    GraphAllocator allocator(&idx, match_range);

    // number of entries that are not statically allocated.
    size_t storage_num_not_allocated =
      AllocMemory(ret, idx, &storage_vec, &storage_inplace_index, ref_count, &allocator);
    size_t storage_allocated_bytes = allocator.TotalAllocBytes();
    // Choose the plan which leads to minimal memory usage
    if (min_allocated_bytes > storage_allocated_bytes) {
      ret.attrs["storage_id"] = std::make_shared<any>(std::move(storage_vec));
      ret.attrs["storage_inplace_index"] = std::make_shared<any>(std::move(storage_inplace_index));
      ret.attrs["storage_allocated_bytes"] = std::make_shared<any>(storage_allocated_bytes);
      ret.attrs["storage_num_not_allocated"] = std::make_shared<any>(storage_num_not_allocated);
      min_allocated_bytes = storage_allocated_bytes;
    }
  }
  return ret;
}

NNVM_REGISTER_PASS(PlanMemory)
.describe("Plan the memory allocation of each node entries.")
.set_body(PlanMemory)
.set_change_graph(false)
.depend_graph_attr("dtype")
.depend_graph_attr("shape")
.provide_graph_attr("storage_id")
.provide_graph_attr("storage_inplace_index");

}  // namespace
}  // namespace pass
}  // namespace nnvm
<|endoftext|>


<commit_before>#include <node.h>
#include <v8.h>
#include <uv.h>

#include "../INCHI-1-API/INCHI_API/inchi_dll/inchi_api.h"

using namespace v8;

Handle<Value> Method(const Arguments& args) {
  HandleScope scope;
  return scope.Close(String::New("world"));
}

Handle<Value> StructureToInChI(const Arguments& args) {
  HandleScope scope;
  return scope.Close(String::New("world"));

  // build INCHI_Input structure from args

  //

}

void init(Handle<Object> exports) {
  exports->Set(String::NewSymbol("hello"),
               FunctionTemplate::New(Method)->GetFunction());

}

NODE_MODULE(libinchi, init)
<commit_msg>add getAlgorithmVersion<commit_after>#include <node.h>
#include <v8.h>
#include <uv.h>

#include "../INCHI-1-API/INCHI_API/inchi_dll/inchi_api.h"
#include "../INCHI-1-API/INCHI_API/inchi_dll/mode.h"

using namespace v8;

Handle<Value> Method(const Arguments& args) {
  HandleScope scope;
  return scope.Close(String::New("world"));
}

Handle<Value> StructureToInChI(const Arguments& args) {
  HandleScope scope;
  return scope.Close(String::New("world"));

  // build INCHI_Input structure from args

  //

}

Handle<Value> getAlgorithmVersion(const Arguments& args) {
  HandleScope scope;
  return scope.Close(String::New(INCHI_VERSION));
}

void init(Handle<Object> exports) {
  exports->Set(String::NewSymbol("hello"),
               FunctionTemplate::New(Method)->GetFunction());
  exports->Set(String::NewSymbol("getAlgorithmVersion"),
               FunctionTemplate::New(getAlgorithmVersion)->GetFunction());
}

NODE_MODULE(libinchi, init)
<|endoftext|>


<commit_before>//
//  RealTimeClock.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 07/05/2019.
//  Copyright © 2019 Thomas Harte. All rights reserved.
//

#ifndef Apple_RealTimeClock_hpp
#define Apple_RealTimeClock_hpp

namespace Apple {
namespace Clock {

/*!
	Models Apple's real-time clocks, as contained in the Macintosh and IIgs.

	Since tracking of time is pushed to this class, it is assumed
	that whomever is translating real time into emulated time
	will also signal interrupts — this is just the storage and time counting.
*/
class ClockStorage {
	public:
		ClockStorage() {
			// TODO: this should persist, if possible, rather than
			// being default initialised.
			constexpr uint8_t default_data[] = {
				0xa8, 0x00, 0x00, 0x00,
				0xcc, 0x0a, 0xcc, 0x0a,
				0x00, 0x00, 0x00, 0x00,
				0x00, 0x02, 0x63, 0x00,
				0x03, 0x88, 0x00, 0x4c
			};
			memcpy(data_, default_data, sizeof(default_data));
			memset(&data_[sizeof(default_data)], 0xff, sizeof(data_) - sizeof(default_data));
		}

		/*!
			Advances the clock by 1 second.

			The caller should also signal an interrupt.
		*/
		void update() {
			for(int c = 0; c < 4; ++c) {
				++seconds_[c];
				if(seconds_[c]) break;
			}
		}

	protected:
		static constexpr uint16_t NoResult = 0x100;
		static constexpr uint16_t DidComplete = 0x101;
		uint16_t perform(uint8_t command) {
			/*
				Documented commands:

					z0000001		Seconds register 0 (lowest order byte)
					z0000101		Seconds register 1
					z0001001		Seconds register 2
					z0001101		Seconds register 3
					00110001		Test register (write only)
					00110101		Write-protect register (write only)
					z010aa01		RAM addresses 0x10 - 0x13
					z1aaaa01		RAM addresses 0x00 – 0x0f

					z0111abc, followed by 0defgh00
									RAM address abcdefgh

					z = 1 => a read; z = 0 => a write.

				The top bit of the write-protect register enables (0) or disables (1)
				writes to other locations.

				All the documentation says about the test register is to set the top
				two bits to 0 for normal operation. Abnormal operation is undefined.
			*/
			switch(phase_) {
				case Phase::Command:
					// Decode an address.
					switch(command & 0x70) {
						default:
							if(command & 0x40) {
								// RAM addresses 0x00 – 0x0f.
								address_ = (command >> 2) & 0xf;
							} else return DidComplete;	// Unrecognised.
						break;

						case 0x00:
							// A time access.
							address_ = SecondsBuffer + ((command >> 2)&3);
						break;
						case 0x30:
							// Either a register access or an extended instruction.
							if(command & 0x08) {
								address_ = (command & 0x7) << 5;
								phase_ = (command & 0x80) ? Phase::SecondAddressByteRead : Phase::SecondAddressByteWrite;
								return NoResult;
							} else {
								address_ = (command & 4) ? RegisterWriteProtect : RegisterTest;
							}
						break;
						case 0x20:
							// RAM addresses 0x10 – 0x13.
							address_ = 0x10 + ((command >> 2) & 0x3);
						break;
					}

					// If this is a read, return a result; otherwise prepare to write.
					if(command & 0x80) {
						// The two registers are write-only.
						if(address_ == RegisterTest || address_ == RegisterWriteProtect) {
							return DidComplete;
						}
						return (address_ >= SecondsBuffer) ? seconds_[address_ & 0xff] : data_[address_];
					}
					phase_ = Phase::WriteData;
				return NoResult;

				case Phase::SecondAddressByteRead:
				case Phase::SecondAddressByteWrite:
					if(command & 0x83) {
						return DidComplete;
					}
					address_ |= command >> 2;

					if(phase_ == Phase::SecondAddressByteRead) {
						phase_ = Phase::Command;
						return data_[address_];	// Only RAM accesses can get this far.
					} else {
						phase_ = Phase::WriteData;
					}
				return NoResult;

				case Phase::WriteData:
					// First test: is this to the write-protect register?
					if(address_ == RegisterWriteProtect) {
						write_protect_ = command;
						return DidComplete;
					}

					if(address_ == RegisterTest) {
						// No documentation here.
						return DidComplete;
					}

					// No other writing is permitted if the write protect
					// register won't allow it.
					if(!(write_protect_ & 0x80)) {
						if(address_ >= SecondsBuffer) {
							seconds_[address_ & 0xff] = command;
						} else {
							data_[address_] = command;
						}
					}

					phase_ = Phase::Command;
				return DidComplete;
			}

			return NoResult;
		}

	private:
		uint8_t data_[256];
		uint8_t seconds_[4];
		uint8_t write_protect_;
		int address_;

		static constexpr int SecondsBuffer = 0x100;
		static constexpr int RegisterTest = 0x200;
		static constexpr int RegisterWriteProtect = 0x201;

		enum class Phase {
			Command,
			SecondAddressByteRead,
			SecondAddressByteWrite,
			WriteData
		};
		Phase phase_ = Phase::Command;

};

/*!
	Provides the serial interface implemented by the Macintosh.
*/
class SerialClock: public ClockStorage {
	public:
		/*!
			Sets the current clock and data inputs to the clock.
		*/
		void set_input(bool clock, bool data) {
			// 	The data line is valid when the clock transitions to level 0.
			if(clock && !previous_clock_) {
				// Shift into the command_ register, no matter what.
				command_ = uint16_t((command_ << 1) | (data ? 1 : 0));
				result_ <<= 1;

				// Increment phase.
				++phase_;

				// If a whole byte has been collected, push it onwards.
				if(!(phase_&7)) {
					// Begin pessimistically.
					const auto effect = perform(uint8_t(command_));

					switch(effect) {
						case ClockStorage::NoResult:
						break;
						default:
							result_ = uint8_t(effect);
						break;
						case ClockStorage::DidComplete:
							abort();
						break;
					}
				}
			}

			previous_clock_ = clock;
		}

		/*!
			Reads the current data output level from the clock.
		*/
		bool get_data() {
			return !!(result_ & 0x80);
		}

		/*!
			Announces that a serial command has been aborted.
		*/
		void abort() {
			result_ = 0;
			phase_ = 0;
			command_ = 0;
		}

	private:
		int phase_ = 0;
		uint16_t command_;
		uint8_t result_ = 0;

		bool previous_clock_ = false;
};

/*!
	Provides the parallel interface implemented by the IIgs.
*/
class ParallelClock: public ClockStorage {
	public:
		void set_control(uint8_t control) {
			if(!(control&0x80)) return;

			if(control & 0x40) {
				// Read from the RTC.
				// A no-op for now.
			} else {
				// Write to the RTC. Which in this implementation also sets up a future read.
				const auto result = perform(data_);
				if(result != NoResult) {
					data_ = uint8_t(result);
				}
			}

			// MAGIC! The transaction took 0 seconds.
			// TODO: no magic.
			control_ = control & 0x7f;

			// Bit 5 is also meant to be 1 or 0 to indicate the final byte.
		}

		uint8_t get_control() {
			return control_;
		}

		void set_data(uint8_t data) {
			data_ = data;
		}

		uint8_t get_data() {
			return data_;
		}

	private:
		uint8_t data_;
		uint8_t control_;
};

}
}

#endif /* Apple_RealTimeClock_hpp */
<commit_msg>Switch to zero-initialised state; be more careful about resetting data.<commit_after>//
//  RealTimeClock.hpp
//  Clock Signal
//
//  Created by Thomas Harte on 07/05/2019.
//  Copyright © 2019 Thomas Harte. All rights reserved.
//

#ifndef Apple_RealTimeClock_hpp
#define Apple_RealTimeClock_hpp

namespace Apple {
namespace Clock {

/*!
	Models Apple's real-time clocks, as contained in the Macintosh and IIgs.

	Since tracking of time is pushed to this class, it is assumed
	that whomever is translating real time into emulated time
	will also signal interrupts — this is just the storage and time counting.
*/
class ClockStorage {
	public:
		ClockStorage() {
			// TODO: this should persist, if possible, rather than
			// being default initialised.
//			constexpr uint8_t default_data[] = {
//				0xa8, 0x00, 0x00, 0x00,
//				0xcc, 0x0a, 0xcc, 0x0a,
//				0x00, 0x00, 0x00, 0x00,
//				0x00, 0x02, 0x63, 0x00,
//				0x03, 0x88, 0x00, 0x4c
//			};
//			memcpy(data_, default_data, sizeof(default_data));
//			memset(&data_[sizeof(default_data)], 0xff, sizeof(data_) - sizeof(default_data));
		}

		/*!
			Advances the clock by 1 second.

			The caller should also signal an interrupt.
		*/
		void update() {
			for(int c = 0; c < 4; ++c) {
				++seconds_[c];
				if(seconds_[c]) break;
			}
		}

	protected:
		static constexpr uint16_t NoResult = 0x100;
		static constexpr uint16_t DidComplete = 0x101;
		uint16_t perform(uint8_t command) {
			/*
				Documented commands:

					z0000001		Seconds register 0 (lowest order byte)
					z0000101		Seconds register 1
					z0001001		Seconds register 2
					z0001101		Seconds register 3
					00110001		Test register (write only)
					00110101		Write-protect register (write only)
					z010aa01		RAM addresses 0x10 - 0x13
					z1aaaa01		RAM addresses 0x00 – 0x0f

					z0111abc, followed by 0defgh00
									RAM address abcdefgh

					z = 1 => a read; z = 0 => a write.

				The top bit of the write-protect register enables (0) or disables (1)
				writes to other locations.

				All the documentation says about the test register is to set the top
				two bits to 0 for normal operation. Abnormal operation is undefined.
			*/
			switch(phase_) {
				case Phase::Command:
					// Decode an address.
					switch(command & 0x70) {
						default:
							if(command & 0x40) {
								// RAM addresses 0x00 – 0x0f.
								address_ = (command >> 2) & 0xf;
							} else return DidComplete;	// Unrecognised.
						break;

						case 0x00:
							// A time access.
							address_ = SecondsBuffer + ((command >> 2)&3);
						break;
						case 0x30:
							// Either a register access or an extended instruction.
							if(command & 0x08) {
								address_ = (command & 0x7) << 5;
								phase_ = (command & 0x80) ? Phase::SecondAddressByteRead : Phase::SecondAddressByteWrite;
								return NoResult;
							} else {
								address_ = (command & 4) ? RegisterWriteProtect : RegisterTest;
							}
						break;
						case 0x20:
							// RAM addresses 0x10 – 0x13.
							address_ = 0x10 + ((command >> 2) & 0x3);
						break;
					}

					// If this is a read, return a result; otherwise prepare to write.
					if(command & 0x80) {
						// The two registers are write-only.
						if(address_ == RegisterTest || address_ == RegisterWriteProtect) {
							return DidComplete;
						}
						return (address_ >= SecondsBuffer) ? seconds_[address_ & 0xff] : data_[address_];
					}
					phase_ = Phase::WriteData;
				return NoResult;

				case Phase::SecondAddressByteRead:
				case Phase::SecondAddressByteWrite:
					if(command & 0x83) {
						return DidComplete;
					}
					address_ |= command >> 2;

					if(phase_ == Phase::SecondAddressByteRead) {
						phase_ = Phase::Command;
						return data_[address_];	// Only RAM accesses can get this far.
					} else {
						phase_ = Phase::WriteData;
					}
				return NoResult;

				case Phase::WriteData:
					// First test: is this to the write-protect register?
					if(address_ == RegisterWriteProtect) {
						write_protect_ = command;
						return DidComplete;
					}

					if(address_ == RegisterTest) {
						// No documentation here.
						return DidComplete;
					}

					// No other writing is permitted if the write protect
					// register won't allow it.
					if(!(write_protect_ & 0x80)) {
						if(address_ >= SecondsBuffer) {
							seconds_[address_ & 0xff] = command;
						} else {
							data_[address_] = command;
						}
					}

					phase_ = Phase::Command;
				return DidComplete;
			}

			return NoResult;
		}

	private:
		uint8_t data_[256]{};
		uint8_t seconds_[4]{};
		uint8_t write_protect_ = 0;
		int address_ = 0;

		static constexpr int SecondsBuffer = 0x100;
		static constexpr int RegisterTest = 0x200;
		static constexpr int RegisterWriteProtect = 0x201;

		enum class Phase {
			Command,
			SecondAddressByteRead,
			SecondAddressByteWrite,
			WriteData
		};
		Phase phase_ = Phase::Command;

};

/*!
	Provides the serial interface implemented by the Macintosh.
*/
class SerialClock: public ClockStorage {
	public:
		/*!
			Sets the current clock and data inputs to the clock.
		*/
		void set_input(bool clock, bool data) {
			// 	The data line is valid when the clock transitions to level 0.
			if(clock && !previous_clock_) {
				// Shift into the command_ register, no matter what.
				command_ = uint16_t((command_ << 1) | (data ? 1 : 0));
				result_ <<= 1;

				// Increment phase.
				++phase_;

				// If a whole byte has been collected, push it onwards.
				if(!(phase_&7)) {
					// Begin pessimistically.
					const auto effect = perform(uint8_t(command_));

					switch(effect) {
						case ClockStorage::NoResult:
						break;
						default:
							result_ = uint8_t(effect);
						break;
						case ClockStorage::DidComplete:
							abort();
						break;
					}
				}
			}

			previous_clock_ = clock;
		}

		/*!
			Reads the current data output level from the clock.
		*/
		bool get_data() {
			return !!(result_ & 0x80);
		}

		/*!
			Announces that a serial command has been aborted.
		*/
		void abort() {
			result_ = 0;
			phase_ = 0;
			command_ = 0;
		}

	private:
		int phase_ = 0;
		uint16_t command_;
		uint8_t result_ = 0;

		bool previous_clock_ = false;
};

/*!
	Provides the parallel interface implemented by the IIgs.
*/
class ParallelClock: public ClockStorage {
	public:
		void set_control(uint8_t control) {
			if(!(control&0x80)) return;

			if(control & 0x40) {
				// Read from the RTC.
				// A no-op for now.
			} else {
				// Write to the RTC. Which in this implementation also sets up a future read.
				const auto result = perform(data_);
				if(result < 0x100) {
					data_ = uint8_t(result);
				}
			}

			// MAGIC! The transaction took 0 seconds.
			// TODO: no magic.
			control_ = control & 0x7f;

			// Bit 5 is also meant to be 1 or 0 to indicate the final byte.
		}

		uint8_t get_control() {
			return control_;
		}

		void set_data(uint8_t data) {
			data_ = data;
		}

		uint8_t get_data() {
			return data_;
		}

	private:
		uint8_t data_;
		uint8_t control_;
};

}
}

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