RoBoard魔人的機器人日誌

2012/2/29

[RoBoRC第三回] 介紹程式碼roborc.cpp

終於進入程式碼的部分囉
我會帶大家看程式碼的內容
以及功用~!!

roborc.cpp
主要是用於讀取檔案以及整體架構
下面依序會有註解

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef WINCE
#include <tchar.h>
#endif

#ifdef USE_RBDLL
 #define  USE_COMMON
 #include <roboard_dll.h>
#else
 #define  USE_COMMON
 #include <roboard.h>
#endif

#if defined(RB_LINUX)
    #define _stricmp  strcasecmp
    #define _strnicmp strncasecmp
#elif defined(RB_BC_DOS) || defined(RB_DJGPP)
    #define _stricmp  stricmp
    #define _strnicmp strnicmp
#endif

#include "const.h"
#include "userio.h"
#include "errcode.h"
#include "demo.h"
#include "parse.h"

//#if defined(RB_MSVC_WIN32) || defined(RB_MSVC_WINCE)
//    #include <windows.h>
//#endif

#if defined(RB_MSVC_WIN32)
    //#define USE_SOUND
#endif

#ifdef USE_SOUND                    //聲音用
 #include "fileio.h"
    #include <irrKlang.h>
    using namespace irrklang;

 class CMyFileFactory : public irrklang::IFileFactory
 {
 public:
  virtual irrklang::IFileReader* createFileReader(const ik_c8* filename)
  {
   FILEIO* file = fileio_FileOpen((char*)filename, "rb");
   if (!file) return 0;

   return new CMyReadFile(file, filename);
  }

 protected:
  class CMyReadFile : public irrklang::IFileReader
  {
  public:
   CMyReadFile(FILEIO* openedFile, const ik_c8* filename)
   {
    File = openedFile;
    strcpy(Filename, filename);
    FileSize = (ik_s32)fileio_GetSize(openedFile);
   }

   ~CMyReadFile()
   {
    fileio_FileClose(File);
   }

   ik_s32 read(void* buffer, ik_u32 sizeToRead)
   {
    return (ik_s32)fileio_Read(buffer, 1, sizeToRead, File);
   }

   bool seek(ik_s32 finalPos, bool relativeMovement)
   {
    return fileio_Seek(File, finalPos, relativeMovement ? SEEK_CUR : SEEK_SET) == 0;
   }

   ik_s32 getSize()
   {
    return FileSize;
   }

   ik_s32 getPos()
   {
    return fileio_GetPos(File);
   }

   const ik_c8* getFileName()
   {
    return Filename;
   }

   FILEIO* File;
   char Filename[1024];
   ik_s32 FileSize;

  }; //end class CMyReadFile
 }; //end class CMyFileFactory
#endif

#define MODE_CAPTURES (1)
#define MODE_REPLAYS  (2)
#define MODE_DEMO     (100)

static bool overwrite = false;
static bool realtime = false;
static bool showmessage = true;
static unsigned long replaytime = 1000L;

typedef struct _PLAY{
 int rbidx;
 int mode_idx;
 int frameno;
 char* filename;
 unsigned long usedchannels;
}PLAY;

static void showhelp(void);
static bool init_rcservo(CH_t *ch, unsigned long channels, int rbidx);
static void close_rcservo(void);
static const char* cmdtostr(unsigned cmd);
static unsigned long htol(char* str);

static void writefile_frame(FILE* fp, unsigned long* width, int frameno);
static void mode_captureframes(PLAY *play);

static void mode_replayframes(PLAY *play);

static void captureinitfrm(DEF_t *def, unsigned long *frm);
static bool FindHomeFRM(DEF_t *def, ACT_NODE *act, unsigned long *frm);
static void init_play(DEF_t *def, ACT_NODE *act);
static void mode_playdemo(char* dirname, unsigned long idletime);

/*================ function for capture frame =====================*/
static void writefile_frame(FILE* fp, unsigned long* width, int frameno)      //用於寫入檔案用
{
 int i;

 fprintf(fp, "[Frame %d]\n", frameno);              //寫入到fp指到的檔案
 for (i=0; i<32; i++)
  fprintf(fp, "channel%d = %lu\n", i, width[i]);
 fprintf(fp, "\n");
}

static void mode_captureframes(PLAY *play)
{
 unsigned long width[32], nowtime;
 unsigned c = 0;
 int i;
 FILE* fp;
 CH_t ch[32];

 showmsg("Open %s to write...", play->filename);
 if (overwrite == false) //&&                //如果option複寫模式開啟 若是沒開啟
 if ((fp = fopen(play->filename, "r")) != NULL)            //判斷能否讀取fp指到的檔案  可以的話
 {
  fclose(fp);                    //關閉剛剛開啟的檔
  showmsg(" file already exists. overwirte? (Y/N) ");
  c = keyboard_waitkey();                 //決定是否要複寫已存在的檔案
  if ((c != 'y') && (c != 'Y'))               //如果回答不是Y  則結束程式
  {
   showmsg("...abort!\n");
   return;
  }
 }

 if ((fp = fopen(play->filename, "w")) == NULL)            //判斷寫入檔案失敗的話
 {
  showmsg("...fail!\n");
  return;
 }

 showmsg("...success\n");                
 if(tool_InitCapture(ch, play->usedchannels, play->mode_idx) != true)      //判斷tool_InitCapture()是否成立  主要是將ch的結構初始化  在demo.cpp
  return;                     //不成立就結束

 if (init_rcservo(ch, play->usedchannels, play->rbidx) == false) return; else showmsg("\n"); //init rcservo

 for (i=0; i<32; i++)
  rcservo_SetServoType(i, RCSERVO_SV_FEEDBACK, RCSERVO_FB_FASTMODE + RCSERVO_FB_DENOISE); //設定Servo的型態

 rcservo_EnterCaptureMode();                 //設定為CaptureMode
 nowtime = timer_nowtime();                 //將時間紀錄至nowtime
 showmsg("Start Frame number : %d\n", play->frameno);

 while (1)
 {
//  if ((realtime != true) || (showmessage == true))
//   showmsg("Pose the KONDO robot, and press any key to capture [ESC to quit] ...\n");
  
  if(showmessage == true){                //判斷是否要顯示訊息
   if(realtime == true)
    showmsg("Pose the KONDO robot, or press ESC to quit ...\n");
   else
    showmsg("Pose the KONDO robot, and press any key to capture [ESC to quit] ...\n");
  }

  if (realtime == true)                 //如果有realtime的話
  {
      do
            {
                c = keyboard_getkey();               
            } while (((timer_nowtime() - nowtime) < replaytime) && (c != KBESC));    //執行到按ESC或時間超過replaytime為止
   nowtime = timer_nowtime();
  }
  else                     //沒有realtime的話
   c = keyboard_waitkey();                //等待按鍵

  if (c == KBESC) break;                 //當按鍵為ESC時離開這while迴圈

  rcservo_ReadPositions(play->usedchannels, RCSERVO_CMD_POWEROFF, width);     //讀取馬達的值   放入width[32]內

  for (i=0; i<32; i++)                 //跑所有的pin腳   1~32
  {
   if (width[i] == 0xffffffffL)              //如果讀取到0xffffffff  即為讀取失敗
   {
    showmsg("ERROR: fail to read the position of channel %d (PIN S%d) !\n", i, i + 1);
    width[i] = 0L;                 //將值改為0
   }
   else                    //如果讀取成功
   {
          if ((realtime == false) || (showmessage == true))        //依設定決定是否輸出
        showmsg("The position of channel %d (PIN S%d) is %lu\n", i, i + 1, width[i]);
   }
  }//end for i...

  writefile_frame(fp, width, play->frameno);            //呼叫writefile_frame()   即為寫入檔案

  if ((realtime != true) || (showmessage == true))
   showmsg("[Frame %d] captured\n\n", play->frameno);
  play->frameno += 1;                  //當前frame編號累加1
 }

 fclose(fp);                     //結束時關閉開啟的檔案
 close_rcservo();                   //關閉rcservo
}

/*================ function for replay frame =====================*/
static void mode_replayframes(PLAY *play)              //為第二個模式  重播模式
{
 DEF_t def;
 ACT_NODE *act;
 int actno = 0;
 
 if(tool_InitReplay(&def, play->filename, replaytime, play->mode_idx, actno, play->usedchannels) != true){ //主要是初始化設定  在demo.cpp
  showmsg("...fail to replay file : %s\n", play->filename);
  return;
 }
 showmsg("Open %s to load...\n", play->filename);
 if(init_rcservo(def.channel, play->usedchannels, play->rbidx) != true)      //init rcservo
  return;

 act = tool_FindACTNode(def.acttable, actno, def.actsize);         //用actno尋找act的節點  在demo.cpp
 if(act == NULL){                   //如果沒找到   即為actno有誤
  showmsg("...fail to find act number: %d\n", actno);
  return;
 }

 if(Servo[play->mode_idx].feedback == true)             //如果是有feedback功能的馬達
  rcservo_EnterPlayMode();                //那就可以直接進入PlayMode
 else{                      //如果無此功能
  showmsg("Move to Home : [Frame %d]...", act->data.frmno);        //就必須要設定起始frame
  rcservo_EnterPlayMode_HOME(act->frm);
  if ((realtime != true) || (showmessage == true))          //依設定決定是否輸出
   showmsg("...finish\n");
  act += 1;                    
 }
 for(; act->type != ACT_START; act += 1){
  if ((realtime != true) || (showmessage == true))          //依設定決定是否輸出
   showmsg("Playing [Frame %d]...", act->data.frmno);
  rcservo_MoveTo(act->frm, act->time);             //移動馬達

  if ((realtime != true) || (showmessage == true))          //依設定決定是否輸出
   showmsg("...finish\n");

  if(showmessage == true){                //依設定決定是否輸出
   if(realtime == true)
    showmsg("press ESC to quit\n\n");
   else
    showmsg("press any key to continue [ESC to quit]\n\n");
  }
//  if ((realtime != true) || (showmessage == true))
//   showmsg("press any key to continue [ESC to quit]\n\n");
  if (realtime == true){
   if (keyboard_getkey() == KBESC) break;            //ESC離開程式
  }
  else{
   if (keyboard_waitkey() == KBESC) break;            //ESC離開程式
  }
 }

 showmsg("Finish the replay process.\n");
 tool_FreeDEF(&def);                   //將新建的空間還回去

 close_rcservo();                   //關閉rcservo
}

/*================ function for play demo =====================*/
static void captureinitfrm(DEF_t *def, unsigned long *frm)          //讀取起始位置用
{
 rcservo_EnterCaptureMode();                 //到CaptureMode
 unsigned long usech = 0;
 int i;
 for(i = 0; i < 32; i++){
  frm[i] = 0;                    //預設frm為0
  if(def->channel[i].pin != -1)
   usech += (1 << def->channel[i].pin);            //有用到的channel加進去
 }
 rcservo_ReadPositions(usech,  RCSERVO_CMD_POWEROFF, frm);         //讀取馬達位置
}

static bool FindHomeFRM(DEF_t *def, ACT_NODE *act, unsigned long *frm)       //尋找HomeFrame用
{
 int i;
 if(def->initfrm != -1){                  //如果有起始位置
  for(i = 0; i < 32; i++)
   frm[i] = def->inithome[i];               //將PWM腳位設定為起始位置
 }
 else{                      //如果沒有起始位置
  while((act->type != -1) && (act->type != ACT_PLAYFRAMENO))        //判斷是否為可用的動作
   act += 1;                   //累加動作
  if(act->type == -1){                 //如果無可用之動作
   for(i = 0; i < def->actidx; i++){             //尋找所有可用之動作
    if(def->actpool[i].type == ACT_PLAYFRAMENO)          //如果有可以用的就跳出
     break;
   }
   if(i == def->actidx)                //如果沒有找到替代的起始動作就回傳false
    return false;
   act = &def->actpool[i];                //有找到就使用找到的
  }
  for(i = 0; i < 32; i++)                 //跑32根腳位
   frm[i] = act->frm[i];                //將起始位置存到frm內
 }
 return true;
}

static void init_play(DEF_t *def, ACT_NODE *act)
{
 bool feedback = true;                  //預設feedback為True
 unsigned long frm[32], read[32];
 int i;
 for(i = 0; i < 32; i++){                 //執行32次 即32個PWM
  if(def->channel[i].pin == -1)               //沒有用到的pin就不理他
   continue;
  if(Servo[def->channel[i].mode_idx].feedback != true){         //如果不是有feedback功能的
   feedback = false;                 //有一個不是就改為false
   break;                    //有一個不是就跳出
  }
 }
 if((feedback == true) && (def->initfrm == -1))            //若有feedback功能 且 沒有起始位置
  rcservo_EnterPlayMode();                //可以直接進入PlayMode
 else{
  if(FindHomeFRM(def, act, frm) != true){             //如果是沒有feedback功能的   那就必須要尋找起始位置
            showmsg("...WARNING: no frame in this demo!\n");
   return;
  }
  if(def->initfrm_mode == INIT_FRM_FALSE){            //若initfrm_mode為false
   captureinitfrm(def, read);               //捕捉目前所在位置
   for(i = 0; i < 32; i++){
    if(read[i] != 0)
     frm[i] = read[i];               //覆蓋過去
   }
  }
  rcservo_EnterPlayMode_HOME(frm);              //rcservo起始位置
 }
 return;
}

static void mode_playdemo(char* dirname, unsigned long idletime)
{
 #define NOPLAY  (0)
 #define PLAYNEXT (1)                  
 #define PLAYING  (2)                  
 int   i;
 unsigned c;
 DEF_t  def;
 CMD_NODE *cmd;
 ACT_NODE *act;
 unsigned long playframe[32];
 int  playing = NOPLAY;
 bool playpause;
 bool playmode = false;
 unsigned long idleTimeOut = timer_nowtime();

    showmsg("Loading %s folder\n", dirname);//show filaname
    if(tool_InitDemo(&def, dirname) != true)             //把值設定為預設值    在demo.cpp
        return;
 showmsg("-----------------------------------> completed\n");

 if (init_rcservo(def.channel, def.usedChannels, def.rbidx) == false) return;    //init rcservo

    #ifdef USE_SOUND
    showmsg("Initializing Audio...");
    ISoundEngine* audioEngine = createIrrKlangDevice(ESOD_AUTO_DETECT, ESEO_MULTI_THREADED | ESEO_LOAD_PLUGINS);
    if (!audioEngine)
     showmsg("...fail to initialize audio!\n");
    else
    {
     showmsg("...success\n\n");

     //allow the audioEngine to read audio files in a zipped file
     CMyFileFactory* demofileFactory = new CMyFileFactory();
     audioEngine->addFileFactory(demofileFactory);
     demofileFactory->drop();
    }
 #endif

 showmsg("\nCommand List\n=============\n");
 for(i = 0; i < def.cmdidx; i++)                //判斷有多少cmd指令就跑幾次迴圈
  showmsg("key: %5s  (%s)\n", cmdtostr(def.cmdpool[i].command), def.cmdpool[i].name);//show command

 showmsg("\nPress one command to play the action ([ESC] to quit)...\n");
 while ((c = keyboard_getkey()) != KBESC)             //執行到按鍵得到ESC為止
 {
  switch (playing)                  //用switch判斷目前所在的模式
  {
   case NOPLAY:
    if (timer_nowtime() >= idleTimeOut){           //當目前時間大於先前紀錄之時間時成立  會在按END鍵時成立
     rcservo_EnterCaptureMode();  //stop PWM output        //rcservo進入capture mode  可以停止PWM繼續輸出
     playmode = false;               //將playmode改為false   沒在做事
    }
    if((cmd = tool_FindCMDNode(def.cmdtable, c, def.cmdsize)) == NULL)    //把輸入的字拿去尋找相對應的節點 回傳回來    在demo.cpp
                    break;
                if(playmode == false){               //若是playmode為false   沒在做事
                    if(def.initact != -1){
                        showmsg("Playing init ACT: %d\n", def.initact);
                        act = def.initactnode;             //預設動作
                    }
                    else
                        act = cmd->act;               //執行下一個動作
     init_play(&def, act);              
     playmode = true;               //playmode為true    有執行動作了
     playing = PLAYNEXT;               //playing改為PLAYNEXT
     playpause = false;               //將playmode改為false
                }
                else{                   //若playmode不為false
                    act = cmd->act;                //執行下一個動作
                    playing   = PLAYNEXT;              //playing改為PLAYNEXT
                    playpause = false;               //將playpause改為false    改為沒在做事
                }
    break;
   case PLAYNEXT:
    if ((act == NULL) || (act->type == ACT_START)){         //如果動作為無   或動作動作型態在起點
     showmsg("Finish the action.\n");
     showmsg("\nPress a command to play an action ([ESC] to quit)...\n");
     playing = NOPLAY;               //將playing改為NOPLAY
     idleTimeOut = timer_nowtime() + idletime;         //將idleTimeOut改為目前時間加上delay的時間
                   #ifdef USE_SOUND
      if (audioEngine) audioEngine->removeAllSoundSources();
     #endif
     break;
    }

    switch (act->type)
    {
     case ACT_PLAYFRAMENO:              //如果ACTION為移動馬達           
      showmsg("  Move to [Frame %d]...", act->data.frmno);
      rcservo_SetAction(act->frm, act->time);         //rcservo設定動作為act的frame間格為act的time
      playing = PLAYING;              //playing改為PLAYING
      break;
     case ACT_PAUSE:                //如果ACTION為停止動作
      showmsg("  Pause %d ms...", act->time); 
                     for (i=0; i<32; i++) playframe[i] = 0L;         //將playframe改為0  基本上是會在原位置不動
      rcservo_SetAction(playframe, act->time);        //rcservo設定動作為act的frame間格為act的time
      playing = PLAYING;              //playing改為PLAYING
      break;
     case ACT_PLAYSND:
      showmsg("  Play Audio %s...", act->data.filename);
                        #ifdef USE_SOUND
        if (!audioEngine)
        showmsg("no audio device!");
        else
        audioEngine->play2D(curact->data.filename, false, false, true);
      #else
                             showmsg("no audio support!");
      #endif
      showmsg("\n");
      break;
    }//end switch (curact->type)
    act += 1;
    break;
   case PLAYING:
    if (c == KBEND)                 //如果按下END鍵
    {
     showmsg("Stop\n");
     rcservo_StopAction();              //rcservo停止動作
     act  = NULL;                //將目前動作改為NULL  即為直接變為無剩餘動作
     break;
    }
    else if (c == KBSPACE){               //如果按下空白鍵
     playpause = (playpause == false)? true : false;        //判斷應該要暫停   還是繼續
     if (playpause == false){             //如果應該要繼續
      showmsg("Play.");
      rcservo_ReleaseAction();            //rcservo繼續動作
     }
     else{                  //其他的  代表應該要暫停
      showmsg("Paused.");
      rcservo_PauseAction();             //rcservo暫時停止動作
     }
    }
    else if(c == KBPGUP){               //如果按下PAGE UP
     act -= 1;                 //把動作多扣一個    即為退到目前所在動作的前面
     if((act-1)->type != ACT_START)            //如果再減一個 (即為回到上一個動作) 不是起頭的話
      act -= 1;                //就回到上一個的前面   這樣就達到回到上個動作的效果
     rcservo_StopAction();              //rcservo停止動作  即目前動作結束
    }
    else if(c == KBPGDN){               //如果按下PAGE DONE
     showmsg("Skip.");
     rcservo_StopAction();              //rcservo停止動作  即目前動作結束
    }
                else if((cmd = tool_FindCMDNode(def.cmdtable, c, def.cmdsize)) != NULL){  //判斷其他輸入字元 若為有效指令則執行
                    showmsg("Playing command: %s\n", cmd->name);
                    act = cmd->act;                //將動作改至新指令的第一個個動作
                    rcservo_StopAction();              //rcservo停止動作  即目前動作結束
                }

    if (rcservo_PlayAction() == RCSERVO_PLAYEND){         //若動作已到結尾
     showmsg("\n");
     playing = PLAYNEXT;               //將playing改為PLAYNEXT
    }
    break;
  }//end switch (playing)
 }//end while ((c = keyboard_getkey()...
 if (playing == PLAYING) showmsg("\n");

 tool_FreeDEF(&def);
    #ifdef USE_SOUND
  if (audioEngine) audioEngine->drop();
 #endif
 close_rcservo();
}

#ifdef WINCE                    //winCE用
int _tmain(int argc, _TCHAR* _argv[])              //winCE的main function    _tmain
{
 char  argvbuf[50][100] = {'\0'};              
 char* argv[50];

 if (argc > 50) argc = 50; //lazy code:p
 for (int _argc=0; _argc<argc; _argc++)             //將winCE的argv轉換為1個byte    winCE的argv會是兩個byte
 {
  argv[_argc] = &(argvbuf[_argc][0]);
  wcstombs(argv[_argc], _argv[_argc], 100);
 }
#else                      //非winCE時用
int main(int argc, char* argv[])
{
#endif                      //讓兩個main function共用一個內容
 int mode;                    //宣告變數mode 用於儲存輸入的模式
 PLAY play = {                   //options用    用來存指令內容的
  2, // rbidx
  0, // mode_idx
  0, // frameno
  "000.frm", // filename
  0x000000ffL //usedchannel
 };
/*
 #if defined(RB_MSVC_WIN32) || defined(RB_MSVC_WINCE)
  DWORD Error; //, priClass;

  //priClass = GetPriorityClass(GetCurrentProcess());
  if (!SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS)) //REALTIME_PRIORITY_CLASS or HIGH_PRIORITY_CLASS
  {
   Error = GetLastError();
   errmsg("Error: failed to enter HIGH_PRIORITY mode (%d)!\n", Error);
   goto End;
  }
 #endif
*/

 //parse user's arguments
 int i, argc_all = argc;                  //將argc_all 直接放入argc的值   就可以得到輸入的個數
 for (i=1, argc=1; i<argc_all; i++){               //將argc從1開始  最大到argc_all
  if (argv[i][0] != '-')                 //若輸入的內容無包含'-'  即不是option
   argc++;                    //就讓argc累加1  這樣就可以知道option以外的東西共有幾個
  else
   break;                    //若進入option區域則直接跳出迴圈
 }
 if (argc <= 1){                    //如果最後得到的argc沒有超過1的話   代表輸入有誤
  showhelp();                    //呼叫showhelp()函式
  return 0;                    //結束程式
 }
 //for argv[1]
 if ((_stricmp(argv[1], "0") == 0) || (_stricmp(argv[1], "CAPTURE") == 0)){     //判斷當第一個輸入為"0"或"CAPTURE"
  mode = MODE_CAPTURES;                 //將mode改為MODE_CAPTURES 即為(1)
  if (argc > 2) play.filename = argv[2];             //將第二個輸入放入play結構的filename裡   (儲存檔案名稱)
  if (argc > 3) play.frameno = atoi(argv[3]);            //將第三個輸入放入play結構的frameno裡   (起始影格編號)
 }

 else if ((_stricmp(argv[1], "1") == 0) || (_stricmp(argv[1], "REPLAY") == 0)){    //判斷當第二個輸入為"1"或"REPLAY"
  mode = MODE_REPLAYS;                 //將mode改為MODE_REPLAYS 即為(2)
  if (argc > 2) play.filename = argv[2];             //將第二個輸入放入play結構的filename裡   (儲存檔案名稱)
 }

 else if ((_stricmp(argv[1], "2") == 0) || (_stricmp(argv[1], "DEMO") == 0)){    //判斷當第二個輸入為"2"或"DEMO"
  mode = MODE_DEMO;                  //將mode改為MODE_DEMO 即為(100)
  if (argc > 2)
   play.filename = argv[2];               //將第二個輸入放入play結構的filename裡   (儲存檔案名稱)
  else{                     //如果沒有兩個以上的輸入代表沒有給予主要的檔案
   showmsg("Error : Missing script directory !\n");
   return 0;                   //結束程式
  }   
  replaytime = 15000L;                 //DEMO MODE預設的replaytime
 } 
 else{
  showhelp();                     //如果有其他的  表示模式輸入錯誤    呼叫showhelp()
  return 0;                    //結束程式
 }

 for (i=argc; i<argc_all; i++){                //繼續將argc的值給i  做到argc_all為止   也就包括了所有的options
  if ((_stricmp(argv[i], "-OW") == 0) || (_stricmp(argv[i], "--overwrite") == 0)){  //判斷option    "-OW"  "--overwrite"
   overwrite = true;                 //成立就將靜態變數overwrite改為true   以便事後判斷
   continue;                   //繼續下一輪迴圈
  }
  else if ((_stricmp(argv[i], "-RT") == 0) || (_stricmp(argv[i], "--realtime") == 0)){ //判斷option    "-RT"  "--realtime"
   realtime = true;                 //成立就將靜態變數realtime改為true   以便事後判斷
   continue;                   //繼續下一輪迴圈
  }
  if ((_stricmp(argv[i], "-NM") == 0) || (_stricmp(argv[i], "--nomessage") == 0)){  //判斷option    "-NM"  "--nomessage"
   showmessage = false;                //成立就將靜態變數showmessage改為false   以便事後判斷
   continue;                   //繼續下一輪迴圈
  }

        if (i == argc_all-1) continue; // ignore last parameters        //忽略最後一個參數   抓到的可能為值  而非選項
  if ((argv[i][0] != '-') || (argv[i+1][0] == '-')) continue; // ignore -XX -YY   //當目前的數為值   而非選項時跳過

  if ((_stricmp(argv[i], "-CH") == 0) || (_stricmp(argv[i], "--channels") == 0)){   //判斷option    "-CH"  "--channels"
   play.usedchannels = htol(argv[i+1]);            //成立就將值 用htol改為long型態 存入play結構中的usedchannels
   }
  else if ((_stricmp(argv[i], "-t") == 0) || (_stricmp(argv[i], "--time") == 0)){   //判斷option    "-t"  "--time"
   replaytime = atol(argv[i+1]);              //成立就將值 用atol改為long型態 存入靜態變數replaytime
  }
  else if ((_stricmp(argv[i], "-SV") == 0) || (_stricmp(argv[i], "--servo") == 0)){  //判斷option    "-SV"  "--servo"
   if(tool_GetMode(argv[i+1], &play.mode_idx) != SUCCESS){        //判斷-SV的輸入是否符合規格
    showmsg("Error : unknown servo : %s\n", argv[i+1]);
    return 0;                  //結束程式
   }
  }
  else if ((_stricmp(argv[i], "-RB") == 0) || (_stricmp(argv[i], "--RoBoard") == 0)){  //判斷option    "-RB"  "--RoBoard"
   if(tool_GetItemRBVer(argv[i+1], &play.rbidx) != SUCCESS){       //判斷-RB的輸入是否符合規格
    showmsg("Error : unknown roboard : %s\n", argv[i+1]);
    return 0;                  //結束程式
   }
  }
 }//end for (i=argc...

 //setup log file
 if (err_SetLogFile("roboard.log") == false)
  showmsg("WARNING: can't open roboard.log for logging error messages!\n");

 keyboard_init(KEYBOARD_STD);                //呼叫函式keyboard_init()   在userio.cpp  引數KEYBOARD_STD為1 在userio.h
 switch (mode)                    //判斷模式
 {
  case MODE_CAPTURES:                  //模式為MODE_CAPTURES = 1
   mode_captureframes(&play);               //呼叫函式mode_captureframes
   break;
  case MODE_REPLAYS:                  //模式為MODE_REPLAYS = 2
   mode_replayframes(&play);               //呼叫函式mode_replayframes
   break;
  case MODE_DEMO:                   //模式為MODE_DEMO = 100
   mode_playdemo(play.filename, replaytime);           //呼叫函式mode_playdeme
   break;
 }

 err_CloseLogFile();
 keyboard_close();
 return 0;
}

/*================  general function =====================*/
static void showhelp(void)                  //此函式用於要讓使用者知道該如何正確輸入用
{
 keyboard_init(KEYBOARD_STD);
 showmsg("Parameters\n");
 showmsg("===========\n");
 showmsg("-CH xxxxxxxx or --channels xxxxxxxx:\n");
    showmsg("    Specify the PWM channels to use\n");
 showmsg("    \n");
 showmsg("-t xxxx or --time xxxx:\n");
    showmsg("    Specify the time for realtime frame capture,\n");
    showmsg("    frame replay, and demo play\n");
 showmsg("    \n");
 showmsg("-SV [DEFAULT, DEFAULT_NOFB, ...] or --servo [DEFAULT, DEFAULT_NOFB, ...]:\n");
    showmsg("    Specify servo motors\n");
 showmsg("    \n");

 showmsg("[press any key to continue...]\n"); keyboard_waitkey();
 showmsg("\n");
 showmsg("Parameters (cont.)\n");
 showmsg("===========\n");
 showmsg("-RB [RB_100, RB_110, ....] or --servo [RB_100, RB_110, ....]:\n");
    showmsg("    Specify servo motors\n");
 showmsg("    \n");
 showmsg("-OW or --overwrite:\n");
    showmsg("    Always overwrite the file of storing captured frames\n");
 showmsg("    \n");
 showmsg("-NM or --nomessage:\n");
    showmsg("    Not display messages when capturing or replaying frames,\n");
    showmsg("    being useful to speed up in Realtime modes\n");

 showmsg("\n");
 showmsg("[press any key to continue...]\n"); keyboard_waitkey();
 showmsg("\n");

 showmsg("Usage examples\n");
 showmsg("===============\n");
 showmsg("RoBoRC.exe CAPTURES(or 0) 0000.frm -CH 0000ffff:\n");
    showmsg("    Capture multiple frames of servo positions on channels 0~15.\n");
    showmsg("    The frames are saved to 0000.frm.\n");
 showmsg("    \n");
 showmsg("RoBoRC.exe REPLAYS(or 1) 0000.frm -CH 0000ffff -t 500:\n");
    showmsg("    Replay the multiple frames of servo positions in 0000.frm.\n");
    showmsg("    Each frame is replayed on channels 0~15 by 500ms.\n");
 showmsg("    \n");
 showmsg("RoBoRC.exe DEMO(or 2) demo_directory -t 10000:\n");
    showmsg("    Load the Demo in demo_directory and\n");
    showmsg("    set the action idle time to 10000ms (which means that\n");
    showmsg("    the servo power will be turned off if the robot\n");
    showmsg("    idles over 10s after finishing an action).\n");
 showmsg("\n");
 showmsg("[press any key to continue...]\n");keyboard_waitkey();
 showmsg("\n");
 keyboard_close();
}

static bool init_rcservo(CH_t *ch, unsigned long channels, int rbidx)       //此函式用於將rcservo init
{
 int i;
 showmsg("Set roboard version (for %s)...\n", RBVer[rbidx].name);
 roboio_SetRBVer(RBVer[rbidx].value);              //設定RB的版本
 for(i = 0; i < 32; i++){                 //用迴圈跑所有的pin腳  共32根
  if(ch[i].pin != -1){                 //判斷ch[i]結構不為-1的pin
   rcservo_SetServo(ch[i].pin, Servo[ch[i].mode_idx].value);       //SetServo
   showmsg("Initializing RCSERVO lib channel %d (PIN S%d) : %s)...\n", i, ch[i].pin + 1, Servo[ch[i].mode_idx].name);
  }
 }

 if (rcservo_Initialize(channels) == true)             //如果Init成功
 {
  showmsg("...success\n");
  rcservo_EnableMPOS();
  rcservo_SetFPS(100);
  return true;
 }

 showmsg("...fail!\n");                  //如果Init不成功
 errmsg("ERROR: RCSERVO lib fails to initialize (%s)!\n", roboio_GetErrMsg());
 return false;
}

static void close_rcservo(void)                 //rcservo_Close  多加兩行輸出
{
 showmsg("Closing RCSERVO lib...");
 rcservo_Close();
 showmsg("...done\n");
}

static const char* cmdtostr(unsigned cmd) {              //用於將輸入的指令轉為字串
 static char cmdstr[2] = {'\0', '\0'};
 int i;

 for (i=0; i<(int)NUM_SKEY; i++)                //指令共有NUM_SKEY = (17)個  在const.h
  if (cmd == SKey[i].value) return SKey[i].name;           //對照  是否有那個key  若有就回傳那個key的名稱

 cmdstr[0] = (char)cmd;                  //若無  則直接回傳那個key轉為char    通常為英數字
 return cmdstr;
}

static unsigned long htol(char* str)               //用於轉換16進位為long型態
{
    unsigned long value = 0L;                

 for (int i=0; i<(int)strlen(str); i++)              //迴圈  從0~字串長度 然後依序計算數值
  value = (str[i]>'9')? value*16+(unsigned long)(str[i]-'a'+10): value*16+(unsigned long)(str[i]-'0');

 return value;
}





雖然看程式碼很乏味
不過多看多理解
可以助於增加自己的程式功力喔!
Share:

0 留言:

張貼留言

技術提供:Blogger.

追蹤者