software description of AVTOKYO 10th HACK BADGE


AVTOKYO 2017
http://ja.avtokyo.org/avtokyo2017
で配布されたバッジ。

![IMG_20171117_220158.jpg](https://qiita-image-store.s3.amazonaws.com/0/165002/e8df529f-46ac-aed2-6b18-c7b9a6fc1e9b.jpeg)
左：フル版（個人スポンサーなど向け用）　　右：ボタン３つ版（一般参加者頒布用）


# 内蔵プログラムの機能

- Drink Ticket Request
- clicker（ミニゲーム）
- mini CTF（ミニゲーム）
- username edit
- credit
- factory reset



# errata

以下は11/11に頒布したバージョンのエラーです。


## mini CTF得点計算のマチガイ

正解が多いほど得点が下がるようになっています。


## スペルミス
起動画面のAV値表示「you has 」→「you have」

# プログラム解説

Arduino IDEで記述しています。

内部にAV値とユーザネームを記録しています。

AV値は初期値500AV。AV値はイベント中の仮想通貨として機能し、ドリンクチケットに引き換えできます。またミニゲームで遊んだスコアはAV値に変換されて貯めることができます。

起動時には、最初にAV値とユーザネームを赤外線通信で送信し、チケット発行リクエストを送ります。
リクエストが成功すれば500AVをマイナスします。

その後メニューを表示し、ユーザ操作を待ちます。

## 赤外線通信の扱い

送信は、UART3に2400bpsで信号を出力し、38KhzのPWM変調して赤外線LEDを駆動しています。
受信は赤外線リモコン受光素子で受けたものをそのままUART3で受けています。
信号化けのレートが多いので、バッジからの信号を受信する側はチェックサムでの誤りチェックが必須です。

## 画面出力

SPIのOLED、SSD1306コントローラを使用しています。Adafruitのライブラリを使っていますがスプラッシュ画面に手を加えるため、ライブラリを書き換えています。

## EEPROM の扱い

内部でEEPROMに保存していますが、実際にはバッジに使っているマイコン、STM32F103C8T6 にはEEPROMは搭載されておらず、プログラムなどを保存する Flash メモリを使ってEEPROMをエミュレーションしています。

また、STM32F103C8T6のFlashサイズは、スペック上は64KBytesですが、実際には128KBytesが搭載されています。

Flashメモリは1KBytesごとのページで管理されており、
この128KBytesのサイズを前提に、Flashの
Page125にユーザネーム
Page126にAV値
をストアしています。

それぞれにチェックサムを付加し、起動時のパラメータ読み込みにチェックサムが一致しなければファクトリーリセットがかかるようになっています。


```


#include "EEPROM.h"

#include <SPI.h>
#include <Wire.h>
// #include <Adafruit_GFX.h>
#include <Adafruit_SSD1306_STM32.h>

#define PAGE_SIZE 0x400
#define MEM_START 0x8000000

#define OLED_MOSI  PA7
#define OLED_CLK   PA5
#define OLED_DC    PA6
#define OLED_CS    PA4
#define OLED_RESET PA3 
Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);


#define BUTTONA PA0
#define BUTTONB PC14
#define BUTTONUP PB5
#define BUTTONDOWN PB6


#define NUMFLAKES 10
#define XPOS 0
#define YPOS 1
#define DELTAY 2

#define LOGO16_GLCD_HEIGHT 16 
#define LOGO16_GLCD_WIDTH  16


 int i,counter=0;
#define LED  PC13
#define BOARD_BUTTON_PIN PB10 
#define COPY_PIN PA8
#define PWM_PIN0  PB0  // TIMER3
#define PWM_PIN1  PB1  // TIMER3


static const unsigned char PROGMEM logo16_glcd_bmp[] =
{ B00000000, B0000000,
  B00000011, B11100000,
  B00001101, B11110000,
  B00011011, B11111000,
  B00110011, B11111100,
  B01111110, B11111110,
  B11111110, B11111111,
  B11110011, B10011111,
  B11111111, B11111111,
  B11001101, B01110011,
  B01111011, B10100110,
  B00111111, B11111100,
  B00011111, B11111000,
  B00001100, B11110000,
  B00000111, B01100000,
  B00000011, B11000000 };
  
#if (SSD1306_LCDHEIGHT != 64)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

char readbuffer[255];
char checksumstr[3]={'A','A',0};
char namestr[5]={'A','A','A',0};
String temp;
char menustr[5][20] = { 
  "   clicker    ",
  "   mini CTF   ",
  "username edit ",
  "    credit    ",
  "factory reset "
  };
int ctfitem=16;
char ctfstr[16][5][60] = {
  { 
"Which file type executable in MS-Windows?",
".pif",
".jpg",
".com",
3
  },{
"Sarin?",
"CH3CH2OH",
"C4H10FO2P",
"CH3COOH",
2
  },{
"Which Is no radiation?",
"Cs137",
"Pu239",
"Pb",
3
  },{
" 0x89 0x50 0x4E 0x47...what filetype?",
"Excel file",
"PNG file",
"Text file",
2
  },{
"Which is harddisk rescue tool?",
"dd",
"od",
"cd",
1
  },{
"How much of registers attandard LED on 12V?",
"470 ohm",
"5.8k ohm",
"2.2M ohm",
1
  },{
"E=mc^2 , E?",
"Energy",
"Enzyme",
"Entropy",
1
  },{
"Select pass from user where name=\"$1\":Whitch $1?",
"Your name",
"Delete -rf \\*",
"\" ;update pass =\" evil\" from user;",
3
  },{
"Whats mean SCADA?",
"Industrial contorol",
"RDBMS language",
"Bluescreen error code",
1
  },{
"CachDrawer Open on ESC/POS?",
"ESC p m t1 t2",
"ESC $ B",
"ESC [ 32 m",
1
  },{
"Which is p53 code?",
"code by ATGC",
"code by 26 calacters",
"code by A–Z,a–z,0–9,+,/,=",
1
  },{
"Which is safety data in Win?",
"Inquity.pdf        .exe",
"Clickme.scr",
"help.txt",
3
  },{
"Port 21,22,23,25?",
"SMTP,telnet,ssh,FTP",
"FTP,ssh,telnet,SMTP",
"FTP,Telnet,ssh,SMTP",
2
  },{
"2^32?",
"255",
"32768",
"4294967296",
3
  },{
"INT21H?",
"21th 16bit integer",
"DOS API",
"thailand domain",
2
  },{
"What is ARM?",
"ESP32",
"Arduino",
"iPhone",
3
  }};
long av=500;

void testdrawchar(void) {
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0,0);

  for (uint8_t i=0; i < 168; i++) {
    if (i == '\n') continue;
    display.write(i);
    if ((i > 0) && (i % 21 == 0))
      display.println();
  }    
  display.display();
}

void testdrawcircle(void) {
  for (int16_t i=0; i<display.height(); i+=2) {
    display.drawCircle(display.width()/2, display.height()/2, i, WHITE);
    display.display();
  }
}
int clicker(void){  
int i=100,j;
long starttime = millis();
long nowtime;
long beforetime = millis();
long totaltime=0;
int avget;
int beforestate;
  display.clearDisplay();
  while ( i > 0 ){
    display.setTextSize(1);
    display.setCursor(0,0);  
    display.setTextColor(WHITE,BLACK);
    nowtime = millis();
//    display.print(int((nowtime-starttime)/(1000*60*60)));
//    display.print(":");
//    display.print(int((nowtime-starttime)/(1000*60)));
//    display.print(":");
    display.print(int((totaltime)/1000));
    display.print(".");
    display.print(((totaltime) % 1000));
    display.drawBitmap(3, 26,  logo16_glcd_bmp, 16, 16, 1);
    display.display();
    display.setTextSize(2);
    display.setTextColor(WHITE,BLACK);
    display.setCursor(20,30);  
    display.println(" = ");
    display.setTextSize(4);
    display.setTextColor(WHITE,BLACK);
    display.setCursor(45,20);  
    display.print("    ");
    display.setCursor(45,20);
    display.print(i);
    display.display();
    for ( j = 0; j < 1 ; j++ ){ 
      delay(15);
      if (1==digitalRead(BUTTONB))
        {
        if (  0 == beforestate )
          {
            i=i+5;
            beforestate = 1;
          }
        } else {
        if (  1 == beforestate )
          {
            beforetime = millis();
          }
          i=i-1;
          beforestate = 0;
          totaltime=millis()-beforetime+totaltime;
          beforetime=millis();
        }
      }
    }
    display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.setCursor(3,1);  
    display.println("");
    display.println("GAME OVER");
    display.println("");
    display.setTextSize(1);
    display.print("  YOUR TIME:");
    display.print(int((totaltime)/1000));
    display.print(".");
    display.println(((totaltime) % 1000));
    display.print("  GET ");
    avget = int((totaltime)/1000);
    avget = avget * avget*5;
    display.print(avget);
    display.print(" AV ");


    display.display();
    av=av+avget;
    avsave();
    delay(2000);
    for ( j = 100; j> 0 ; j-- ){
        delay(40);
      if ( 1==digitalRead(BUTTONDOWN))
        {
          j = 0;
        }
      if ( 1==digitalRead(BUTTONUP))
        {
          j = 0;
        }
     if ( 1==digitalRead(BUTTONB))
        {
          j = 0;
        }

  }
}

int menu(void){
    int menuitem,j;
    int exitflag=0;
    int namey=30;
    int maxitem=5;
    display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.setCursor(0,10);  
    display.print("AV");
    display.setTextSize(1);
    display.print(" = ");
    display.print(av);
    
    while ( exitflag != 1 ){
  
      delay(200);
      if ( 1==digitalRead(BUTTONDOWN))
        {
          menuitem=menuitem+1;
        }
      if ( 1==digitalRead(BUTTONUP))
        {
          menuitem=menuitem-1;
        }
      if ( 1==digitalRead(BUTTONB))
        {
          exitflag=1;
        }
      if ( maxitem < menuitem  ) { menuitem = 0; }
      if ( 0 > menuitem  ) { menuitem =maxitem; }
      display.setCursor(0,30);  
      display.setTextSize(1);
      for ( j = 0; j<maxitem+1 ; j++ ){
        display.setCursor(24,20+j*(8*1+1));  
        if ( j == menuitem ) {
           display.setTextColor(BLACK,WHITE);
        } else {
           display.setTextColor(WHITE,BLACK);       
        }
        display.println(menustr[j]);
      }
      display.display();
    }
  return(menuitem);
}



int credit(void){
    int menuitem,j;
    int exitflag=0;
    int namey=30;
    int maxitem=5;
    display.clearDisplay();
    display.setTextSize(1);
    display.setTextColor(WHITE);
    display.setCursor(0,0);  
    display.println("    -   credit   -");
    display.display();
    while ( exitflag != 1 ){
  
      delay(200);
      if ( 1==digitalRead(BUTTONB))
        {
          exitflag=1;
        }
      display.setCursor(0,10);  
      display.setTextSize(1);
      display.println("This is OSHW.");
      display.println("License:Public Domain");
      display.println("Powered By AVTOKYO");
      display.println("        &");
      display.println("LowLevelStudySociety");
      display.println("nodrinknohack proj.");
      display.display();
    }
  return(menuitem);
}



void nameentry(void){
    int i=0,j;
    int avget=0;
    int namex=20;
    int namey=30;
    display.clearDisplay();
    display.setTextSize(2);
    display.setTextColor(WHITE);
    display.setCursor(0,10);  
    display.println("name?");
    display.display();
    while ( i != 4 ){
  
      delay(200);
      if ( 1==digitalRead(BUTTONDOWN))
        {
          namestr[i]=namestr[i]-1;
        }
      if ( 1==digitalRead(BUTTONUP))
        {
          namestr[i]=namestr[i]+1;
        }
      if ( 1==digitalRead(BUTTONB))
        {
          i=i+1;
        }
      if ( 126 < namestr[i]  ) { namestr[i] =32; }
      if ( 32 > namestr[i]  ) { namestr[i] =126; }
      if (( i > 3 )&& ( 0 == namestr[3] %2 )) { i = 0;namestr[3]=0; }
      display.setTextSize(4);
      for ( j = 0; j<3 ; j++ ){
        if ( j == i ) {
           display.setTextColor(BLACK,WHITE);
        } else {
           display.setTextColor(WHITE,BLACK);       
        }
         display.setCursor(namex+6*4*j,namey);  
         display.print(namestr[j]);
      } 
//       display.print(namestr);
      display.setTextSize(1);
      if ( i == 3 ) {
          display.setTextColor(BLACK,WHITE);       
          display.setCursor(namex+6*4*3+3,namey+3);  
         if ( 1 == namestr[i] %2 ) {
            display.print("end."); 
         } else {
            display.print("edit"); 
         }
      } else {
          display.setCursor(namex+6*4*3+3,namey+3);  
          display.setTextColor(WHITE,BLACK);       
          display.print("    ");         
      }
      //   display.setCursor(namex+6*4*j,namey);  
      //   display.print(namestr[j]);
       
      
      display.display();
    }
    namestr[3]=0;
    display.setCursor(namex,20);  
    display.clearDisplay();
    display.print("your name:");
    display.setTextSize(1);
    display.println(namestr);
    display.println("");
    display.print(" av=  ");
    display.println(av);
    display.display();
    delay(1000);
    namesave();
    delay(1000);
    display.clearDisplay();
}
void miniCTF(){
  int exitflag=0,answerflag=0,i=0,j,selecteditem=1,avget=0;
  while ( exitflag == 0) {
    
   answerflag = 0;
   while ( answerflag == 0 && exitflag == 0){      
      display.clearDisplay();
      display.setTextColor(WHITE,BLACK);
      display.setCursor(0,0);
      display.println(ctfstr[i][0]);
      display.setCursor(0,30);
      for ( j = 1; j< 5; j++){
        if ( j==4 ) {   // quit button
          if ( j==selecteditem ) {
            display.setTextColor(BLACK,WHITE);
            display.setCursor(60,57);
            display.print( "cansel(quit)");
          }
        } else {
        if ( j==selecteditem ) {
              display.setTextColor(BLACK,WHITE);
          } else {
              display.setTextColor(WHITE,BLACK);

          }
          display.println(ctfstr[i][j]);
        }
      }
      delay(200);
      if ( 1==digitalRead(BUTTONDOWN))
        {
          selecteditem=selecteditem+1;
        }
      if ( 1==digitalRead(BUTTONUP))
        {
          selecteditem=selecteditem-1;
        }
      if ( 1==digitalRead(BUTTONB))
        {
          answerflag=1;
          if ( selecteditem==4){
            exitflag=1;
          }
          if ( selecteditem==4){
            exitflag=1;
          }
        }
      if ( 4 < selecteditem  ) { selecteditem =1; }
      if ( 1 > selecteditem  ) { selecteditem =4; }

      display.display();
    }
    if ( 0 == exitflag ) {
      avget=avget+ctfanswer(i,selecteditem);
      i=i+1; 
      answerflag = 0;
    }
    if ( i >= ctfitem){
            exitflag=1;
    }
  }
  endctf(avget);
}
int endctf( int avget){
      display.clearDisplay();
      int returncode=0;
      display.setTextColor(WHITE,BLACK);
      display.setCursor(0,0);
      display.print("   score:");
      display.println(avget);
      
      display.print("  your get:");
      display.print(avget*avget*50);
      display.println(" AV");
      av=av+avget*avget*50;
      avsave();
      display.println("");
      display.println(" push any buttun ");
      display.display();
      
     buttunwait(5);
    return(returncode);
}
int ctfanswer( int i, int selecteditem){
      display.clearDisplay();
      int returncode=0;
      display.setTextColor(WHITE,BLACK);
      display.setCursor(30,30);
      // display.println(selecteditem);
      int j=(int) ctfstr[i][4][0];
      // display.println(j);
      if (j == selecteditem){
        display.println("Bingo!");
        returncode=1;  
      }else{
        display.println(" Boo! ");
        returncode=0;  
      }
      display.println("");
      display.println(" push any buttun ");
      display.display();
      
     buttunwait(5);
    return(returncode);
}
int buttunwait(int wait){
  
   int exitflag=0;
    for ( int  i= 0;( i < wait*10 )&&  (exitflag != 1); i++ ){
   // display.println(j);
     
      delay(100);
      if ( 1==digitalRead(BUTTONB)||1==digitalRead(BUTTONDOWN)||1==digitalRead(BUTTONUP) )
        {
          exitflag=1;
        }
    }    
    while ( 1==digitalRead(BUTTONB)||1==digitalRead(BUTTONDOWN)||1==digitalRead(BUTTONUP) )
        {
          delay(100);
        }
    
}
void write_data_to_rom(uint8_t page,String String_data) {
  EEPROM.PageBase0 = MEM_START + page * PAGE_SIZE;
  EEPROM.PageSize = PAGE_SIZE;
  byte Byte_data[30];
  String_data.getBytes(Byte_data, 30);
  int k;
  for (k = 0; k < 30 && Byte_data[k] != '\0'; k++) {
    EEPROM.write(k, Byte_data[k]);
  }
  EEPROM.write(k, '\0');
}


String read_data_from_rom(uint8_t page) {
  EEPROM.PageBase0 = MEM_START + page * PAGE_SIZE;
  EEPROM.PageSize = PAGE_SIZE;
  String data_from_rom;
  for (int i = 0; i < 30 && EEPROM.read(i) != '\0' ; i++) {
    char c = EEPROM.read(i);
    data_from_rom = data_from_rom + String(c);
  }
  return data_from_rom;
}

void EEPROMWritelong2(uint8_t page, long value,long value2){
      byte one,two,three,four;
      EEPROM.PageBase0 = MEM_START + page * PAGE_SIZE;
      EEPROM.PageSize = PAGE_SIZE;
      four = (value & 0xFF);
      three = ((value >> 8) & 0xFF);
      two = ((value >> 16) & 0xFF);
      one = ((value >> 24) & 0xFF);
      EEPROM.write(0, four);
      EEPROM.write(1, three);
      EEPROM.write(2, two);
      EEPROM.write(3, one);
      four = (value2 & 0xFF);
      three = ((value2 >> 8) & 0xFF);
      two = ((value2 >> 16) & 0xFF);
      one = ((value2 >> 24) & 0xFF);
      EEPROM.write(4, four);
      EEPROM.write(5, three);
      EEPROM.write(6, two);
      EEPROM.write(7, one);
}
long EEPROMReadAV(uint8_t page)
      {
      unsigned char one,two,three,four;
      unsigned long avcheck,avchecksum1,avchecksum2;
      EEPROM.PageBase0 = MEM_START + page * PAGE_SIZE;
      EEPROM.PageSize = PAGE_SIZE;

      four = EEPROM.read(0);
      three = EEPROM.read(1);
      two = EEPROM.read(2);
      one = EEPROM.read(3);
      display.clearDisplay();
      display.setTextColor(WHITE,BLACK);
      display.setCursor(30,10);
//           display.print(four);
//           display.print(" ");
//           display.print(three);
//           display.print(" ");
//           display.print(two);
//           display.print(" ");
//           display.print(one);
//           display.print(" ");
//           display.display();
//           delay(10000);

      avcheck= ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
      avchecksum1 = 255-(((avcheck & 0xFF) +  ((avcheck >> 8) & 0xFF)+ ((avcheck >> 16) & 0xFF)+((avcheck >> 24) & 0xFF))%256);
      four = EEPROM.read(4);
      three = EEPROM.read(5);
      two = EEPROM.read(6);
      one = EEPROM.read(7);
      avchecksum2= ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF);
      display.clearDisplay();
      int returncode=0;
      display.setTextColor(WHITE,BLACK);
      display.setCursor(30,10);

      if ( avchecksum1 != avchecksum2 ){
           display.println("oh,flash is non-init.");
           display.println("formating...");
           display.display();
           delay(2000);
           factoryreset();
        } else {
           av=avcheck;
           display.print("You has ");
           display.print(av);
           display.print(" AV");
           display.display();
           delay(1000);
        }
}
      


void formatPage( uint8_t page ) {
  EEPROM.PageBase0 = MEM_START + page * PAGE_SIZE;
  EEPROM.PageSize = PAGE_SIZE;
  EEPROM.format();
}

void avsave(void){
    // format and write Hi-Score to page 125
  unsigned char one,two,three,four;
  unsigned long avchecksum1;
  char bufferstr[10]={0,0,0,0,0,0,0,0,0,0};
  int page;
  Serial.println( "format start" );
  page = 125;
  formatPage( page );
  Serial.println( "format done" );
  formatPage( page );
  Serial.println( "format done" );
//  write_data_to_rom(125,"500");
//One = Most significant -> Four = Least significant byte
  EEPROM.PageBase0 = MEM_START + page * PAGE_SIZE;
  EEPROM.PageSize = PAGE_SIZE;
  unsigned long value=av;
  four = (value & 0xFF);
  three = ((value >> 8) & 0xFF);
  two = ((value >> 16) & 0xFF);
  one = ((value >> 24) & 0xFF);
  avchecksum1 = 255-((four + three + two + one )%256);
  value=avchecksum1;
  //Write the 4 bytes into the eeprom memory.
  EEPROM.write(0, four);
  EEPROM.write(1, three);
  EEPROM.write(2, two);
  EEPROM.write(3, one);
  four = (value & 0xFF);
  three = ((value >> 8) & 0xFF);
  two = ((value >> 16) & 0xFF);
  one = ((value >> 24) & 0xFF);

  //Write the 4 bytes into the eeprom memory.
  EEPROM.write(4, four);
  EEPROM.write(5, three);
  EEPROM.write(6, two);
  EEPROM.write(7, one);
      
  // format and write Username to page 126
}
void factoryreset(){
    // format and write Hi-Score to page 125
  unsigned char one,two,three,four;
  unsigned long avchecksum1;
  char bufferstr[10]={0,0,0,0,0,0,0,0,0,0};
  int page;
  av=500;
  avsave();
  // format and write Username to page 126
  page = 126;
  namestr[0]='A';
  namestr[1]='A';
  namestr[2]='A';
  namestr[3]=0;
  namesave();
  nameentry();

   

}
int EEPROMReadname(uint8_t page)
      {
      unsigned char one,two,three,four;
      unsigned long avcheck,avchecksum1,avchecksum2;
      EEPROM.PageBase0 = MEM_START + page * PAGE_SIZE;
      EEPROM.PageSize = PAGE_SIZE;

      four = EEPROM.read(0);
      three = EEPROM.read(1);
      two = EEPROM.read(2);
      one = EEPROM.read(3);
      display.clearDisplay();
    // format and write Hi-Score to page 125
  char bufferstr[10]={0,0,0,0,0,0,0,0,0,0};
  char checksumstr[10]={0,0,0,0,0,0,0,0,0,0};

  bufferstr[0]=EEPROM.read(0);
  bufferstr[1]=EEPROM.read(1);
  bufferstr[2]=EEPROM.read(2);
  checksumstr[0]=EEPROM.read(3);
  checksumstr[1]=EEPROM.read(4);
  
  long n = strtol(checksumstr, NULL, 16);
  long checksum = 255-((bufferstr[0]+bufferstr[1]+bufferstr[2])%256);

   display.clearDisplay();
   display.setTextSize(1);
   display.setCursor(0,0);  
   display.setTextColor(WHITE,BLACK);
//   sprintf(checksumstr,"%02X",int(checksum/256));
//   display.println(bufferstr);
//   display.println(checksumstr);
//   display.println(n);
//   display.println(checksum);
//   display.display();
//   delay(5000);

   if ( n == checksum ){
      namestr[0]=bufferstr[0];
      namestr[1]=bufferstr[1];
      namestr[2]=bufferstr[2];
      namestr[3]=0;
       
    } else {
      factoryreset();       
    }

}
void namesave(void){
  unsigned char one,two,three,four;
  unsigned long avchecksum1;
  char bufferstr[10]={0,0,0,0,0,0,0,0,0,0};
  int page;
  // format and write Username to page 126
  page = 126;
  formatPage( page );
  Serial.println( "format done" );
  formatPage( page );
  Serial.println( "format done" );
  EEPROM.PageBase0 = MEM_START + page * PAGE_SIZE;
  EEPROM.PageSize = PAGE_SIZE;
  long checksum = 255-((namestr[0]+namestr[1]+namestr[2])%256);
  sprintf(checksumstr,"%02X",checksum);
  bufferstr[0]=namestr[0];
  bufferstr[1]=namestr[1];
  bufferstr[2]=namestr[2];
  bufferstr[3]=checksumstr[0];
  bufferstr[4]=checksumstr[1];
  write_data_to_rom(126,bufferstr);

//   display.clearDisplay();
//   display.setTextSize(1);
//   display.setCursor(0,0);  
//   display.setTextColor(WHITE,BLACK);
//   display.println(checksumstr);
//   display.print(bufferstr);
//   display.print(" ");
//   display.println(namestr);
//   display.print(" ");
//   display.print(checksumstr[0]);
//   display.print(" ");
//   display.print(checksumstr[1]);
//   display.drawBitmap(3, 26,  logo16_glcd_bmp, 16, 16, 1);
//   display.display();
//   delay(5000);


}


void sendAV() { 
//  sleepAndWakeUp(STANDBY, &rt, alarmDelay);  
  delay(100);  
  String s = "";
  unsigned char c;
  unsigned long n=0;
  s.concat(namestr);
  s.concat(",");
  s.concat(av);
  s.concat(",");
  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0,0);  
  display.setTextColor(WHITE,BLACK);
//  display.println(s);


  for ( i = 0; i < s.length(); i++ ){
    c = s.charAt(i);
    n = n + c;
//    display.print(c);
//    display.print(":");
//    display.print(n);
//    display.print(" ");
  }
  s.concat(n);
//  display.print(s);
  display.print("sending ticket...");
  display.display();
  delay(100);
  for ( i=0;i<25;i++){
    Serial.println("");
    Serial.println("");
    Serial.println(s);
    Serial3.println(s);
    digitalWrite(LED,HIGH);
    delay(40);
    digitalWrite(LED,LOW);
    delay(40);
    
  }
   while( Serial.available()) {
    unsigned int inByte = Serial.read();
    if ( ( 10 != inByte) || i > 250 ) {
      readbuffer[i]=inByte;
      i++;
    } else {
      i=0;
      if ( readbuffer[0] == 'o' && readbuffer[1]=='k' ){
         av= av-500;
      }
    }
  }
  counter=counter+1;
  delay(360);  
}  
  
void action()
{
  int state=  digitalRead(BOARD_BUTTON_PIN);
  // digitalWrite(PWM_PIN0,state);
  if (HIGH == state ){
   Timer3.pause();
  Timer3.setCount(0);
  Timer3.refresh();
   } else {
    Timer3.resume();
  }
}

void setup()   {                

  
  // by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
  display.begin(SSD1306_SWITCHCAPVCC);
  // init done
  
  // Show image buffer on the display hardware.
  // Since the buffer is intialized with an Adafruit splashscreen
  // internally, this will display the splashscreen.
  display.display();
  delay(1000);

  pinMode(BUTTONUP,INPUT_PULLDOWN);
  pinMode(BUTTONDOWN,INPUT_PULLDOWN);
  pinMode(BUTTONB,INPUT_PULLDOWN);
  pinMode(BUTTONA,INPUT_PULLDOWN);

  EEPROMReadAV(125);
  EEPROMReadname(126);

  Serial.begin(2400);
  Serial3.begin(2400);
  delay(100);
  pinMode(LED,OUTPUT);
  pinMode(COPY_PIN,OUTPUT);
  for ( i=0;i<5;i++){
    digitalWrite(LED,HIGH);
    delay(40);
    digitalWrite(LED,LOW);
    delay(40);
  }
  pinMode(PWM_PIN0, PWM);            // LED_PINをPWMに設定
  pinMode(PWM_PIN1, PWM);            // LED_PINをPWMに設定
  Timer3.pause();
  Timer3.setPrescaleFactor(947);   // システムクロック 72MHzを10ｋHzに分周
  Timer3.setOverflow(2);      // wave width = 2 ( 2 * 72MHz / 947 = 38Khz)
  pwmWrite(PWM_PIN0, 1);       // pulse width = 1 (1/2 duty 50%)
  pwmWrite(PWM_PIN1, 1);      // pulse width = 1 (1/2 duty 50%)
  
  Timer3.setCount(1);
  Timer3.refresh();
    Timer3.resume();
 //   Timer3.resume();
 delay(100);
  Timer3.pause();
  Timer3.setCount(0);
  Timer3.refresh();
    
    Serial.println("start ...");
  delay(100); 
  attachInterrupt(BOARD_BUTTON_PIN, action, CHANGE);
  delay(100);  

  display.clearDisplay();
  display.setTextSize(1);
  display.setCursor(0,0);  
  display.setTextColor(WHITE,BLACK);
  display.println("Never came here");
  delay(2000);
  sendAV();
  
}

void loop() {
    // text display tests
  int menucode=0;
  // nameentry();
  menucode=menu();
  if ( 0 == menucode ){
    clicker();
  }
  if ( 1 == menucode ){
    miniCTF();
  }
  if ( 2 == menucode ){
    nameentry();
  }
  if ( 3 == menucode ){
    credit();
  }
  if ( 4 == menucode ){
    factoryreset();
  }
  

}



```
# mini CTF 問題解説

## Which file type executable in MS-Windows?
".pif",
".jpg",
".com",

MS-Windowsはファイル拡張子で実行可能かどうかを判別しています。この問題の回答以外に、.exe .scr .bat .vbs .vbe .wsf .wshなどなどがあります。

### Sarin?
"CH3CH2OH",
"C4H10FO2P",
"CH3COOH",

Fというのが入っているだけでやばそうですね。

### Which Is no radiation?
"Cs137",
"Pu239",
"Pb",

スミマセン、厳密には現代の一般的なPbは放射性があります。

### 0x89 0x50 0x4E 0x47...what filetype?
"Excel file",
"PNG file",
"Text file",

0x50 0x4E 0x47をASCIIコードに直してみると・・・

### Which is harddisk rescue tool?
"dd",
"od",
"cd",

個人的にはddrescueを使いたいところですが、あまり一般的ではないので。

### How much of registers attandard LED on 12V?
"470 ohm",
"5.8k ohm",
"2.2M ohm",

電流制限抵抗をつけなければ煙と共に焼けきれます！・・・というのは本当は少ないです。

### E=mc^2 , E?"
"Energy",
"Enzyme",
"Entropy",

物理の問題です。ヤバメの知識を仕入れておくのはハッカーの嗜み。

### Select pass from user where name="$1":Whitch $1?

"Your name",
"Delete -rf \\*",
"\" ;update pass =\" evil\" from user;",

AVTOKYOとしてはどれが正解？

### Whats mean SCADA?
"Industrial contorol",
"RDBMS language",
"Bluescreen error code",

AVTOKYOでもSCADAはよく話題になります。

### CachDrawer Open on ESC/POS?
"ESC p m t1 t2",
"ESC $ B",
"ESC [ 32 m",

今回稼働予定だったチケット発行システムはESC/POSで動いていました。機材の都合でキャッシュドロワ−は用意できませんでしたが、これを開閉するデモができればよかったかもですね。

### Which is p53 code?
"code by ATGC",
"code by 26 calacters",
"code by A–Z,a–z,0–9,+,/,=",

バグって選択肢3が文字化けしてました。p53はエラー修正コードです。

### Which is safety data in Win?
"Inquity.pdf        .exe",
"Clickme.scr",
"help.txt",

Windowsでは拡張子を非表示にしたりまぎらわしくしたりして誤クリックを誘う攻撃が蔓延しています。

### Port 21,22,23,25?
"SMTP,telnet,ssh,FTP",
"FTP,ssh,telnet,SMTP",
"FTP,Telnet,ssh,SMTP",

最近余り使わなくなったプロトコルもあって、思い出すのに苦労するかも。

### 2^32?
"255",
"32768",
"4294967296",

キリのいい数字です。

### INT21H?
"21th 16bit integer",
"DOS API",
"thailand domain",

もうそろそろここらへんの知識は忘れてもいい頃。

### What is ARM?
"ESP32",
"Arduino",
"iPhone",

バッジのMPUもARMです