⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 c_cmd.c

📁 乐高机器人的源码,开发平台是IAR_for_AVR.
💻 C
📖 第 1 页 / 共 5 页
字号:
  IOMapCmd.OffsetDS = 0xFFFF;

  //Initialize format string and clear out FileName string
  strncpy((PSZ)(IOMapCmd.FormatString), VM_FORMAT_STRING, VM_FORMAT_STRING_SIZE);
  memset(IOMapCmd.FileName, 0, sizeof(IOMapCmd.FileName));

  dTimerInit();
  IOMapCmd.Tick = dTimerRead();

  return;
}


void cCmdCtrl(void)
{
  UBYTE Continue = TRUE;
  NXT_STATUS Status = NO_ERR;
  ULONG i;
  CLUMP_ID CurrClumpID;

  switch (VarsCmd.VMState)
  {
    case VM_IDLE:
    {
      //If there's a new program to activate...
      if (IOMapCmd.ActivateFlag == TRUE)
      {
        //Clear flag so we only activate once per new file
        IOMapCmd.ActivateFlag = FALSE;

        Status = cCmdActivateProgram(IOMapCmd.FileName);

        //If we hit an activation error:
        //1. Set PROG_ERROR status
        //2. Proceed to VM_RESET1 (some unneeded work, yes, but preserves contract with UI
        if (IS_ERR(Status))
        {
          IOMapCmd.ProgStatus = PROG_ERROR;
          VarsCmd.VMState = VM_RESET1;
        }
        //Else start running program
        else
        {
          VarsCmd.VMState = VM_RUN_FREE;
          IOMapCmd.ProgStatus = PROG_RUNNING;
          VarsCmd.StartTick = IOMapCmd.Tick;

#if VM_BENCHMARK
          //Re-init benchmark
          VarsCmd.InstrCount         = 0;
          VarsCmd.Average            = 0;
          VarsCmd.OverTimeCount      = 0;
          VarsCmd.MaxOverTimeLength  = 0;
          VarsCmd.CmdCtrlCount       = 0;
          VarsCmd.CompactionCount    = 0;
          VarsCmd.LastCompactionTick = 0;
          VarsCmd.MaxCompactionTime  = 0;
          memset(VarsCmd.OpcodeBenchmarks, 0, sizeof(VarsCmd.OpcodeBenchmarks));
          memset(VarsCmd.SyscallBenchmarks, 0, sizeof(VarsCmd.SyscallBenchmarks));
#endif
          //Reset devices to a known state before we begin running
          cCmdResetDevices();

          pMapUi->Flags |= (UI_DISABLE_LEFT_RIGHT_ENTER | UI_DISABLE_EXIT);
        }
      }

      break;
    }

    //Initialize VM internal state data and devices which must respond immediately to program ending
    case VM_RESET1:
    {
      //If we aborted a program, reset devices (specifically, motors) immediately
      //Otherwise, wait for UI to put us into PROG_RESET (gives motors a chance to brake before setting to coast)
      //!!! This means cCmdResetDevices will get called twice on abort.  Should not be a big deal.
      if (IOMapCmd.ProgStatus == PROG_ABORT)
        cCmdResetDevices();

      //Reenable UI access to buttons
      pMapUi->Flags &= ~(UI_DISABLE_LEFT_RIGHT_ENTER | UI_DISABLE_EXIT);

#if VM_BENCHMARK
      if (IOMapCmd.Tick != VarsCmd.StartTick)
        VarsCmd.Average = VarsCmd.InstrCount / (IOMapCmd.Tick - VarsCmd.StartTick);
      else
        //It appears that we finished in 0 milliseconds.  Very unlikely on ARM, so set a flag value.
        VarsCmd.Average = 0xFFFFFFFF;

      cCmdWriteBenchmarkFile();
#endif

      //Re-initialize program state data (contents of memory pool preserved)
      //!!! Skip this step in simulator builds so helper access methods still work
#ifndef SIM_NXT
      cCmdDeactivateProgram();
#endif //SIM_NXT

      //If this program has taken over the display, reset it for the UI
      cCmdRestoreDefaultScreen();

      //Stop any currently playing sound and re-init volume according to UI prefs
      pMapSound->State = SOUND_STOP;
      pMapSound->Volume = pMapUi->Volume;

      //Artificially set CommStatReset to BTBUSY to force at least one SETCMDMODE call (see VM_RESET2 case)
      VarsCmd.CommStatReset = (SWORD)BTBUSY;

      VarsCmd.VMState = VM_RESET2;
    }
    break;

    case VM_RESET2:
    {
      //Reset BlueCore into "command mode" (close any open streams)
      //Since SETCMDMODE subject to BTBUSY, we may need to make multiple calls
      //Any CommStatReset value other than BTBUSY means our request was accepted
      //Assumptions:
      //Process should never take longer than UI timeout (see below), but if it does,
      // we could be left with the stream open to an NXT peer and block out the PC.
      //Also assuming that once SETCMDMODE request is accepted, it never fails.
      if (VarsCmd.CommStatReset == (SWORD)BTBUSY && VarsCmd.DirtyComm == TRUE)
        pMapComm->pFunc(SETCMDMODE, 0, 0, 0, NULL, (UWORD*)&(VarsCmd.CommStatReset));

      //If UI is done displaying ending program status, move on.
      if (IOMapCmd.ProgStatus == PROG_RESET)
      {
        //Reset devices whenever a program ends for any reason
        cCmdResetDevices();

        VarsCmd.DirtyComm = FALSE;

        //Go to VM_IDLE state
        VarsCmd.VMState = VM_IDLE;
        IOMapCmd.ProgStatus = PROG_IDLE;
      }
      break;
    }

    case VM_RUN_FREE:
    case VM_RUN_SINGLE:
    {

#if VM_BENCHMARK
      //IOMapCmd.Tick currently holds the tick from the end of last cCmdCtrl call.
      //If we don't come back here before dTimerRead() increments, the m_sched loop has taken *at least* 1 ms.
      if (IOMapCmd.Tick != dTimerRead())
      {
        VarsCmd.OverTimeCount++;
        //Record maximum magnitude of schedule loop overage, in millisecs
        if (dTimerRead() - IOMapCmd.Tick > VarsCmd.MaxOverTimeLength)
          VarsCmd.MaxOverTimeLength = dTimerRead() - IOMapCmd.Tick;
      }
      VarsCmd.CmdCtrlCount++;
#endif
      //Abort current program if cancel button is pressed
      if (IOMapCmd.DeactivateFlag == TRUE || pMapButton->State[BTN1] & PRESSED_EV)
      {
        IOMapCmd.DeactivateFlag = FALSE;

        //Clear pressed event so it doesn't get double-counted by UI
        pMapButton->State[BTN1] &= ~PRESSED_EV;

        //Go to VM_RESET1 state and report abort
        VarsCmd.VMState = VM_RESET1;
        IOMapCmd.ProgStatus = PROG_ABORT;
        break;
      }

      //Assert that we have an active program
      NXT_ASSERT(VarsCmd.ActiveProgHandle != NOT_A_HANDLE);

      //Execute from at least one clump
      do
      {
        if (cCmdIsClumpIDSane(VarsCmd.RunQ.Head))
        {
          //Stash and dequeue RunQ's head clump
          CurrClumpID = VarsCmd.RunQ.Head;

          //Execute at least one instruction from current clump
          //Execute up to 'Priority' instructions as long as we are in VM_FREE_RUN mode
          //Finishing/suspending a clump, BREAKOUT_REQ, or any errors will also end this loop
          i = 0;
          do
          {
            //Interpret one instruction per call, advancing PC as needed
            Status = cCmdInterpFromClump(CurrClumpID);

#if VM_BENCHMARK
            VarsCmd.InstrCount++;
#endif

            NXT_ASSERT(!IS_ERR(Status));
            if (IS_ERR(Status) || Status == CLUMP_DONE || Status == CLUMP_SUSPEND || Status == BREAKOUT_REQ || Status == STOP_REQ)
            {
              //We're done with this clump or breaking out prematurely,
              //so break the multi-instruction loop
              break;
            }
            else
            {
              //Count up one more instruction for this pass
              i++;
            }
          } while (VarsCmd.VMState == VM_RUN_FREE && i < VarsCmd.pAllClumps[CurrClumpID].Priority);

          //Only rotate RunQ on a "normal" finish, i.e. no error, clump end, or breakout request
          if (!(IS_ERR(Status) || Status == CLUMP_DONE || Status == CLUMP_SUSPEND || Status == BREAKOUT_REQ))
            cCmdRotateQ(&(VarsCmd.RunQ));
        }

        //Re-evaluate conditions for stopping the dataflow scheduler
        //Halt program on all errors
        if (IS_ERR(Status))
        {
          Continue = FALSE;

          VarsCmd.VMState = VM_RESET1;
          IOMapCmd.ProgStatus = PROG_ERROR;
        }
        else if (Status == BREAKOUT_REQ)
        {
          Continue = FALSE;
        }
        //If RunQ is empty or user requested early termination, program is done
        else if (!cCmdIsClumpIDSane(VarsCmd.RunQ.Head) || Status == STOP_REQ)
        {
          Continue = FALSE;

          VarsCmd.VMState = VM_RESET1;
          IOMapCmd.ProgStatus = PROG_OK;
        }
        //VM_RUN_FREE means continue executing until a new ms tick rolls over
        else if (VarsCmd.VMState == VM_RUN_FREE)
        {
          Continue = (IOMapCmd.Tick == dTimerRead());
        }
        //Otherwise execute only one pass per call
        else //VarsCmd.VMState == VM_RUN_SINGLE
        {
          VarsCmd.VMState = VM_RUN_PAUSE;
          Continue = FALSE;
        }

      } while (Continue == TRUE);

    break;
    }
  }//END state machine switch

  //Busy wait to always maintain 1ms period
  BUSY_WAIT_NEXT_MS;

  //Set tick to new value for next time 'round
  IOMapCmd.Tick = dTimerRead();

  return;
}


void cCmdExit(void)
{
  dTimerExit();

  return;
}


NXT_STATUS cCmdReadFileHeader(UBYTE* pData, ULONG DataSize,
            PROG_FILE_OFFSETS* pFileOffsets)
{
  ULONG i;
  UBYTE * pCursor;
  UWORD CurrOffset = 0;
  UBYTE DepCount;
  UWORD DopeVectorOffset;
  UWORD FileClumpCount;
  UBYTE FileMajor, FileMinor,
        CompatibleMinor, CompatibleMajor,
        CurrentMajor;

  NXT_ASSERT(pData != NULL);

  //Assign pCursor to point to version word inside file header
  pCursor = (pData + VM_FORMAT_STRING_SIZE - 2);

  //Decode version numbers into comparable bytes
  FileMajor = *pCursor;
  FileMinor = *(pCursor + 1);
  CompatibleMajor = (UBYTE)(VM_OLDEST_COMPATIBLE_VERSION >> 8);
  CompatibleMinor = (UBYTE)(VM_OLDEST_COMPATIBLE_VERSION);
  CurrentMajor = (UBYTE)(FIRMWAREVERSION >> 8);
  //CurrentMinor = (UBYTE)(FIRMWAREVERSION);

  //Return ERR_VER if file lacks proper format string or version number
  //!!! Only checking major version recommended for future development
  if (strncmp((PSZ)pData, VM_FORMAT_STRING, VM_FORMAT_STRING_SIZE)
   || FileMajor < CompatibleMajor || FileMinor < CompatibleMinor
   || FileMajor > CurrentMajor)
  {
    NXT_BREAK;
    return (ERR_VER);
  }

  //Advance CurrOffset past header information
  CurrOffset += VM_FORMAT_STRING_SIZE;

  //
  //Initialize bookkeeping variables
  //
  VarsCmd.DataspaceCount = *((UWORD*)(pData + CurrOffset));
  CurrOffset += 2;

  VarsCmd.DataspaceSize = *((UWORD*)(pData + CurrOffset));
  CurrOffset += 2;

  VarsCmd.DSStaticSize = *((UWORD*)(pData + CurrOffset));
  CurrOffset += 2;

  pFileOffsets->DSDefaultsSize = *((UWORD*)(pData + CurrOffset));
  CurrOffset += 2;

  pFileOffsets->DynamicDefaults = *((UWORD*)(pData + CurrOffset));
  CurrOffset += 2;

  pFileOffsets->DynamicDefaultsSize = *((UWORD*)(pData + CurrOffset));
  CurrOffset += 2;

  VarsCmd.MemMgr.Head = *((UWORD*)(pData + CurrOffset));
  CurrOffset += 2;

  VarsCmd.MemMgr.Tail = *((UWORD*)(pData + CurrOffset));
  CurrOffset += 2;

  DopeVectorOffset = *((UWORD*)(pData + CurrOffset));
  CurrOffset += 2;

  //!!! Odd code here to deal with type mismatch between file format and CLUMP_ID typedef.
  //Neither is trivial to change, so it's best to just check the data for consistency here.
  FileClumpCount = *((UWORD*)(pData + CurrOffset));
  CurrOffset += 2;

  //Must have at least one clump and count can't exceed the NOT_A_CLUMP sentinel
  if (FileClumpCount == 0 || FileClumpCount >= NOT_A_CLUMP)
    return (ERR_FILE);
  else
    VarsCmd.AllClumpsCount = (CLUMP_ID)FileClumpCount;

  VarsCmd.CodespaceCount = *((UWORD*)(pData + CurrOffset));
  CurrOffset += 2;

  //Can't have a valid program with no code
  if (VarsCmd.CodespaceCount == 0)
    return (ERR_FILE);

  //
  // Now, calculate offsets for each data segment in the file
  //

  CurrOffset += CurrOffset % 2;
  pFileOffsets->DSTOC = CurrOffset;
  CurrOffset += VarsCmd.DataspaceCount * sizeof(DS_TOC_ENTRY);

  CurrOffset += CurrOffset % 2;
  pFileOffsets->DSDefaults = CurrOffset;
  CurrOffset += pFileOffsets->DSDefaultsSize;

  //ClumpRecs must be aligned on even boundaries
  CurrOffset += CurrOffset % 2;
  pFileOffsets->Clumps = CurrOffset;

  //Set cursor to start of clump records
  pCursor = pData + CurrOffset;

  //Set CurrOffset to start of dependent lists
  CurrOffset += VarsCmd.AllClumpsCount * VM_FILE_CLUMP_REC_SIZE;

  //Read dependent count from each clump record, advancing CurrOffset accordingly
  for (i = 0; i < VarsCmd.AllClumpsCount; i++)
  {
    DepCount = *(pCursor + 1);
    CurrOffset += DepCount;
    pCursor += VM_FILE_CLUMP_REC_SIZE;
  }

  //Codespace must be aligned on even boundary
  CurrOffset += CurrOffset % 2;
  pFileOffsets->Codespace = CurrOffset;

  //No need to read through codespace, but make sure CurrOffset ended up sane
  //If not, something went wrong reading the header information
  if (CurrOffset != (DataSize - VarsCmd.CodespaceCount * 2))
  {
    NXT_BREAK;
    return (ERR_FILE);
  }

  //
  // Finally, update VarsCmd fields
  //

  VarsCmd.RunQ.Head = NOT_A_CLUMP;
  VarsCmd.RunQ.Tail = NOT_A_CLUMP;

  //Reset codespace pointer
  VarsCmd.pCodespace = (CODE_WORD*)(pData + pFileOffsets->Codespace);

  //...placing clump records first...
  VarsCmd.pAllClumps = (CLUMP_REC*)(VarsCmd.Pool + VarsCmd.PoolSize);
  VarsCmd.PoolSize += VarsCmd.AllClumpsCount * sizeof(CLUMP_REC);

  //...then DSTOC...
  VarsCmd.pDataspaceTOC = (DS_TOC_ENTRY*)(pData + pFileOffsets->DSTOC);

  //...then the dataspace itself
  ALIGN_TO_MOD(VarsCmd.PoolSize, POOL_ALIGN);
  VarsCmd.pDataspace = (VarsCmd.Pool + VarsCmd.PoolSize);
  IOMapCmd.OffsetDS = (UWORD)((ULONG)(VarsCmd.pDataspace) - (ULONG)&(IOMapCmd));
  VarsCmd.PoolSize += VarsCmd.DataspaceSize;

  //init rest of MemMgr
  VarsCmd.MemMgr.pDopeVectorArray = (DOPE_VECTOR *)(VarsCmd.pDataspace + DopeVectorOffset);
  IOMapCmd.OffsetDVA = (UWORD)((ULONG)(VarsCmd.MemMgr.pDopeVectorArray) - (ULONG)&(IOMapCmd));
  VarsCmd.MemMgr.FreeHead = NOT_A_DS_ID;


  if (VarsCmd.PoolSize > POOL_MAX_SIZE)
  {
    NXT_BREAK;
    return (ERR_FILE);
  }

  return (NO_ERR);
}


//!!! Recursive function
NXT_STATUS cCmdInflateDSDefaults(UBYTE* pDSDefaults, UWORD *pDefaultsOffset, DS_ELEMENT_ID DSElementID)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -