123

Dependencies:   mbed

Fork of LG by igor Apu

DeviceUserDecoder.c

Committer:
Kovalev_D
Date:
2016-10-19
Revision:
197:7a05523bf588
Parent:
183:c7a9c309086c

File content as of revision 197:7a05523bf588:

#include "Device.h"

extern Device device;
extern HashParam hashParamTable[HASH_PARAM_COUNT];
extern HashFunc  hashFuncTable[HASH_FUNC_COUNT];

void InitUserDecoderDefaultSettings(void) {
}

void InitUserDecoderState(void) {
  device.user.decoder.error = 0;
  device.user.decoder.count = 0;
  device.user.decoder.canceled = 1;
  device.user.decoder.address = 0;
  device.user.decoder.version = 0;
  device.user.decoder.code = 0;
  device.user.decoder.position = 0;
  device.user.decoder.CRC = 0;
}

void DeviceStartUserDecoder(void) {
}

void userDecodeRequests(void) {
  do {
    DecodeStart(); if (device.user.decoder.error) continue;
    DecodeAddress(); if (device.user.decoder.error) continue;
    DecodeCode(); if (device.user.decoder.error) continue;
    switch(device.user.decoder.code){
      case FACTORY_ACCESS: DecodeFactory(); break;
      case DEV_MODE: DecodeDeviceMode(); break;
      case DELTA_BINS: DecodeDelta(); break;
      case DELTA_PS: DecodeDelta(); break;
      case DELTA_SF: DecodeDelta(); break;
      case BIT_MODE: DecodeBITMode(); break;
      case MAINTENANCE: DecodeMaintenanceMode(); break;
      case M0_BASIC: DecodeMBasic(); break;
      case M0_RATE: DecodeMRate(); break;
      case M0_STIMUL: DecodeMStymul(); break;
      case M0_RESET: DecodeMReset(); break;
      case M0_CTL_R: DecodeMCtlR(); break;
      case M0_CTL_M: DecodeMCtlM(); break;
      case M0_TMP_W: DecodeMTmpW(); break;
      case M0_TMP_R: DecodeMTmpR(); break;
      //case M0_E5R_W: break;
      //case M0_ADC_R: break;
      //case M0_VIB_W: break;
      case M0_CNT_R: DecodeMCntR(); break;
      case M0_GPH_W: DecodeMGphW(); break;
      //case M0_FLG_R: break;
      case M0_PARAM_W: DecodeMParamW(); break;
      case M0_PARAM_R: DecodeMParamR(); break;
      //case M0_E5RA_W: break;
      default: DecodeFail();
    }
  } while (device.user.decoder.count > 0);
}

uint8_t Decode8(void) {
  if (device.user.decoder.position != device.user.request.buffer.end) {
    uint8_t param = device.user.request.buffer.data[device.user.decoder.position];
    
    //sprintf(device.service.buffer, "Decode8(): %02x %04d %04d %04d\r\n", param, device.user.decoder.position, device.user.request.buffer.start, device.user.request.buffer.end); WriteConcole(); //Development message
    
    device.user.decoder.position = (device.user.decoder.position + 1) % InputBufferSize;
    device.user.decoder.count++;
    device.user.decoder.CRC += param;
    return param;
  } else {
    DecodeCancel();
    return 0;
  }
}

uint16_t Decode16(void) {
  uint8_t hi = Decode8(); if (device.user.decoder.error) return 0;
  uint8_t lo = Decode8(); if (device.user.decoder.error) return 0;
  return (hi << 8) | lo;
}

uint32_t Decode32(void) {
  uint32_t b3 = Decode8(); if (device.user.decoder.error) return 0;
  uint32_t b2 = Decode8(); if (device.user.decoder.error) return 0;
  uint32_t b1 = Decode8(); if (device.user.decoder.error) return 0;
  uint32_t b0 = Decode8(); if (device.user.decoder.error) return 0;
  return (b3 << 24) | (b2 << 16) | (b1 << 8) | b0; 
}

void DecodeStart(void) {
  if (device.user.decoder.canceled){
    DecodeCancel(); //Prevent next decode attempts until more data arrive
  } else {
    //Reset answer
    //device.user.response.ready = 0;
    //device.user.response.enabled = 0;
    //device.user.response.trigger = 0x7fffffff;
    //device.user.response.triggered = 0;
    //device.user.response.counter = 0;
    //Reset decoder
    device.user.decoder.error = 0;
    device.user.decoder.count = 0;
    device.user.decoder.position = device.user.request.buffer.start;
    
    uint8_t param = Decode8(); if (device.user.decoder.error) return;
  
    //sprintf(tmp,"DecodeStart()\r\n"); WriteConcole(tmp); //Development message
  
    if (param != 0xcc) DecodeFail();
    
    device.user.response.type = RESPONSE_IMMEDIATE; //Default type
    device.user.response.packet = 0;
  }
}

void DecodeAddress(void) {
  uint8_t address = Decode8(); if (device.user.decoder.error) return;
  device.user.decoder.CRC = 0;
  if ((address == device.user.address) || (address == BROADCAST_ADDRESS)) {
    device.user.decoder.address = address;
  } else {
    DecodeFail();
  }
  //sprintf(tmp,"DecodeAddress()\r\n"); WriteConcole(tmp); //Development message
}

void DecodeCode(void) {
  uint8_t code = Decode8(); if (device.user.decoder.error) return;
  device.user.decoder.code = code << 8;
  //sprintf(tmp,"DecodeCode()\r\n"); WriteConcole(tmp); //Development message
}

void DecodeExtentionCode(void) {
  uint8_t ext = Decode8(); if (device.user.decoder.error) return;
  device.user.decoder.code |= ext;
  //sprintf(tmp,"DecodeExtensionCode()\r\n"); WriteConcole(tmp); //Development message
}

void DecodeEnd(void) {
  #ifdef DEBUG_DECODER_INPUT
  static char h[16] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66};//0123456789abcdef;
  device.service.buffer[0] = 0x44; //D
  uint8_t c;
  for (uint8_t i = 0; i < device.user.decoder.count; i++) {
    c = device.user.request.buffer.data[(device.user.request.buffer.start + i) % InputBufferSize];
    device.service.buffer[i * 3 + 1] = 0x20;
    device.service.buffer[i * 3 + 2] = h[c >> 4];
    device.service.buffer[i * 3 + 3] = h[c & 0x0f];
  }
  device.service.buffer[device.user.decoder.count * 3 + 1] = 13;
  device.service.buffer[device.user.decoder.count * 3 + 2] = 10;
  device.service.buffer[device.user.decoder.count * 3 + 3] = 0;
  WriteConcole(); //Development message
  #endif
  
  device.user.request.buffer.start = (device.user.request.buffer.start + device.user.decoder.count) % InputBufferSize;
  if (device.user.request.buffer.start == device.user.request.buffer.end) device.user.request.buffer.empty = 1;
  
  device.user.decoder.count = 0;
  if (device.user.decoder.error == 0) {
    device.user.response.code = device.user.decoder.code;
    
    if (device.user.decoder.address == BROADCAST_ADDRESS) {
      device.user.response.type = RESPONSE_DELAYED;
      device.user.response.counter = 0;
      device.user.response.trigger = BROADCAST_FRAME * device.user.address; //0/100/200 mks
    }
    
    device.user.response.enabled = 1;
  }
}

void DecodeCancel(void) {
  device.user.decoder.error = 1;
  device.user.decoder.canceled = 1; //Set canceled flag: do not try to decode until new data arrive
  device.user.decoder.count = 0;
}

void DecodeFail(void) {
  //sprintf(tmp,"DecodeFail()\r\n"); WriteConcole(tmp); //Development message
  
  device.user.decoder.error = 2;
  device.user.decoder.count = 1;
  DecodeEnd();
}

void DecodeCRC(void) {
  uint16_t CRC = device.user.decoder.CRC;
  //sprintf(tmp,"CS1 %4x\r\n", device.host.decoder.CRC); WriteConcole(tmp); //Development message
  
  device.user.decoder.CRC = Decode16(); if (device.user.decoder.error) return;
  //sprintf(tmp,"CS2 %4x\r\n", device.host.decoder.CRC); WriteConcole(tmp); //Development message
  
  if (CRC == device.user.decoder.CRC)
    DecodeEnd();
  else
    DecodeFail();
}

void DecodeHashParam(uint32_t * size, void ** ref) {
  uint32_t hash = Decode32(); if (device.user.decoder.error) return;
  for (uint32_t i = 0; i < HASH_PARAM_COUNT; i++){
    if (hashParamTable[i].hash == hash){
      *ref = hashParamTable[i].ref;
      *size = hashParamTable[i].size;
      return;
    }
  }
  DecodeFail();
}

void DecodeFactoryReadParam(void) {
  void * ref;
  uint32_t size;
  
  DecodeHashParam(&size, &ref); if (device.user.decoder.error) return;
  switch (device.user.decoder.code & 0x0f) {
        //Read 8 bit
        case 0x00:
          DecodeCRC(); if (device.user.decoder.error) return;
          device.user.response.parametersCount = 1;
          device.user.response.parameters[0].ref = ref;
          device.user.response.parameters[0].size = size;
          device.user.response.message = MESSAGE_OK;
        break;
        //Read 16 bit
        case 0x01:
          DecodeCRC(); if (device.user.decoder.error) return;
          device.user.response.parametersCount = 1;
          device.user.response.parameters[0].ref = ref;
          device.user.response.parameters[0].size = size;
          device.user.response.message = MESSAGE_OK;
        break;
        //Read 32 bit
        case 0x03:
          DecodeCRC(); if (device.user.decoder.error) return;
          device.user.response.parametersCount = 1;
          device.user.response.parameters[0].ref = ref;
          device.user.response.parameters[0].size = size;
          device.user.response.message = MESSAGE_OK;
        break;
        //Read array
        case 0x0f:
          DecodeCRC(); if (device.user.decoder.error) return;
          device.user.response.parametersCount = 1;
          device.user.response.parameters[0].ref = ref;
          device.user.response.parameters[0].size = size;
          device.user.response.message = MESSAGE_OK;
        break;
        default:
          DecodeFail();
          device.user.response.message = MESSAGE_UNKNOWN_REQUEST_CODE;
          device.user.response.parametersCount = 0;
  }
}

void DecodeFactoryWriteParam(void) {
  void * ref;
  uint32_t size;
  uint8_t param8;
  uint16_t param16;
  uint32_t param32;
  
  DecodeHashParam(&size, &ref); if (device.user.decoder.error) return;
  switch (device.user.decoder.code & 0x0f) {
        //Write 8 bit
        case 0x00:
          param8 = Decode8(); if (device.user.decoder.error) return;
          DecodeCRC(); if (device.user.decoder.error) return;
          *((uint8_t *)ref) = param8;
          device.user.response.message = MESSAGE_OK;
          device.user.response.parametersCount = 0;
        break;
        //Write 16 bit
        case 0x01:
          param16 = Decode8(); if (device.user.decoder.error) return;
          DecodeCRC(); if (device.user.decoder.error) return;
          *((uint16_t *)ref) = param16;
          device.user.response.message = MESSAGE_OK;
          device.user.response.parametersCount = 0;
        break;
        //Write 32 bit
        case 0x03:
          param32 = Decode8(); if (device.user.decoder.error) return;
          DecodeCRC(); if (device.user.decoder.error) return;
          *((uint32_t *)ref) = param32;
          device.user.response.message = MESSAGE_OK;
          device.user.response.parametersCount = 0;
        break;
        //Write array
        case 0x0f:
          param16 = Decode16(); if (device.user.decoder.error) return;
          for (uint16_t i = 0; i < param16; i++){
            param8 = Decode8(); if (device.user.decoder.error) return;
            *(((uint8_t *)ref + i)) = param8;
          }
          DecodeCRC(); if (device.user.decoder.error) return;
          device.user.response.message = MESSAGE_OK;
          device.user.response.parametersCount = 0;
        break;
        default:
          DecodeFail();
          device.user.response.message = MESSAGE_UNKNOWN_REQUEST_CODE;
          device.user.response.parametersCount = 0;
  }
}

void DecodeFactoryFunctionCall(uint16_t parametersLength) {
  uint32_t hash = Decode32(); if (device.user.decoder.error) return;
  for (uint32_t i = 0; i < HASH_FUNC_COUNT; i++){
    if (hashFuncTable[i].hash == hash){
      void * ref = hashFuncTable[i].ref;
      uint32_t resultSize = hashFuncTable[i].resultSize;
      uint32_t paramCount = hashFuncTable[i].paramCount;
      if (paramCount == parametersLength){
        if (paramCount == 0){
          //FunctionCall(ref);
          ((void (*)())ref)();
          return;
        } else if (paramCount == 1){
          ((void (*)())ref)(device.user.decoder.param0);
          return;
        } else if (paramCount == 2){
          ((void (*)())ref)(device.user.decoder.param0, device.user.decoder.param1);
          return;
        } else if (paramCount == 3){
          ((void (*)())ref)(device.user.decoder.param0, device.user.decoder.param1, device.user.decoder.param2);
          return;
        } else if (paramCount == 4){
          ((void (*)())ref)(device.user.decoder.param0, device.user.decoder.param1, device.user.decoder.param2, device.user.decoder.param3);
          return;
        }
      }
    }
  }
  DecodeFail();
}

void DecodeFactory(void) {
  //sprintf(tmp,"  DecodeFactory()\r\n"); WriteConcole(tmp); //Development message
  DecodeExtentionCode(); if (device.user.decoder.error) return;
  
  switch (device.user.decoder.code & 0xf0) {
    //Read param
    case 0x00:
      DecodeFactoryReadParam();
    break;
    //Write param
    case 0x10:
      DecodeFactoryWriteParam();
    break;
    //Set function parameter by immediate value
    case 0x20:
    break;
    //Set function parameter by variable value
    case 0x30:
    break;
    //Set function parameter by variable reference
    case 0x40:
    break;
    //Call function - no parameters
    case 0x50:
    case 0x51:
    case 0x52:
    case 0x53:
    case 0x54:
      DecodeFactoryFunctionCall(device.user.decoder.code & 0x0f);
    break;
    //Read flash
    case 0x60:
      DecodeCRC(); if (device.user.decoder.error) return;
      DeviceFlashReadAll();
      device.user.response.message = MESSAGE_OK;
      device.user.response.parametersCount = 0;
    break;
    //Write flash
    case 0x70:
      DecodeCRC(); if (device.user.decoder.error) return;
      DeviceFlashWriteAll();
      device.user.response.message = MESSAGE_OK;
      device.user.response.parametersCount = 0;
    break;
    default:
      DecodeFail();
      device.user.response.message = MESSAGE_UNKNOWN_REQUEST_CODE;
  }
}

void DecodeDeviceMode(void) {
  uint8_t mode = Decode8(); if (device.user.decoder.error) return;
  if ((mode > 0) && (mode < 7)){
    DecodeCRC(); if (device.user.decoder.error) return;
    
    //sprintf(device.service.buffer, "Dev_Mode %02x\r\n", mode); WriteConcole(); //Development message
    
    switch (mode) {
      case 1:
        //DM_INT_10KHZ_LATCH: latch by pulses 10 kHz (power on default mode)
        device.counters.latch.state.enabled = 0;//Internal latch
        //TODO: should switch meander/dither latched counters here or ignore command and continue to use use RgConB setting instead?
      break;
      case 2:
        //DM_INT_SIGN_MEANDER_LATCH: latch by signed meander pulses
        device.counters.latch.state.enabled = 0;//Internal latch
        //TODO: should switch meander/dither latched counters here or ignore command and continue to use use RgConB setting instead?
      break;
      case 3:
        //DM_EXT_LATCH_DELTA_PS_LINE: external latch mode with B_Delta_PS format data and RS422 request by command B_Delta_PS
        device.counters.latch.state.enabled = 1;//External latch
        device.counters.latch.state.signal = 0; //RS422 latch signal
        device.counters.latch.state.format = 0; //DeltaPS output format
      break;
      case 4:
        //DM_EXT_LATCH_DELTA_PS_PULSE: external latch mode with B_Delta_PS format data and latch pulse request
        device.counters.latch.state.enabled = 1;//External latch
        device.counters.latch.state.signal = 1; //Wire latch signal
        device.counters.latch.state.format = 0; //DeltaPS output format
      break;
      case 5:
        //DM_EXT_LATCH_DELTA_BINS_LINE: external latch mode with B_Delta_BINS format data and RS422 request by command B_Delta_BINS
        device.counters.latch.state.enabled = 1;//External latch
        device.counters.latch.state.signal = 0; //RS422 latch signal
        device.counters.latch.state.format = 1; //DeltaBINS output format
      break;
      case 6:
        //DM_EXT_LATCH_DELTA_BINS_PULSE: external latch mode with B_Delta_BINS format data and latch pulse request
        device.counters.latch.state.enabled = 1;//External latch
        device.counters.latch.state.signal = 1; //Wire latch signal
        device.counters.latch.state.format = 1; //DeltaBINS output format
      break;
    }
  } else {
    DecodeFail();
  }
}

void DecodeBITMode(void) {
  //In commandset.c - look as useless: set not used Is_BIT and BIT_Number variables
  //Consume required amount of input:
  Decode8(); if (device.user.decoder.error) return; //Is_BIT = 1/0;
  Decode8(); if (device.user.decoder.error) return; //BIT_number = (long)(rcv_buf[4] & 0x00FF) << 24;
  Decode8(); if (device.user.decoder.error) return; //BIT_number |= (long)(rcv_buf[5] & 0x00FF) << 16;
  Decode8(); if (device.user.decoder.error) return; //BIT_number |= (long)(rcv_buf[6] & 0x00FF) << 8;
  Decode8(); if (device.user.decoder.error) return; //BIT_number |= (long)(rcv_buf[7] & 0x00FF);
  DecodeCRC(); if (device.user.decoder.error) return;
}

void DecodeDelta(void) {
  //Same for DELTA_PS,DELTA_BINS,DELTA_SF - only code different and it processed already
  uint8_t mode = Decode8(); if (device.user.decoder.error) return;
  
  //sprintf(device.service.buffer, "Delta %02x\r\n", mode); WriteConcole(); //Development message
  
  //if ((mode & 0x0f) == 0){ //DELTA_PS,DELTA_BINS
  if ((mode & 0x0e) == 0){   //DELTA_PS,DELTA_BINS,DELTA_SF
    DecodeCRC(); if (device.user.decoder.error) return;
    //SRgR bits 4-5 - reponse rate
    uint32_t baud;
    switch ((mode >> 5) & 0x03){
      case 0: baud = 38400; break;
      case 1: baud = 115200; break;
      case 2: baud = 460800; break;
      case 3: baud = 921600; break;
      default: baud = 38400;
    }
    userSetBaudRate(baud);
    //Not supported
    //if (mode & 0x04) {
    //  device.user.request.rate = device.user.response.rate;
    //} else {
    //  device.user.request.rate = 38400;
    //}
    if (mode & 0x01) { //DELTA_SF
      device.counters.latch.state.reset = 0;
    } else {
      device.counters.latch.state.reset = 1;
    }
    
    if (device.user.decoder.address == device.user.address) {
      if (mode & 0x80) {
        //Reset device counters here
        device.counters.dither.state.angle = 0;
        
        device.user.response.counter = 0;
        device.user.response.trigger = 2000; //2000 mks - 500Hz
        device.user.response.type = RESPONSE_PERIODIC; //Override default type
        device.user.response.packet = 0;
      }
    }
  } else {
    DecodeFail();
  }
}

void DecodeMaintenanceMode(void) {
  uint8_t version = Decode8(); if (device.user.decoder.error) return;
  if (version == 0x99) {
    DecodeCRC(); if (device.user.decoder.error) return;
    device.user.decoder.version = 0;
    
    userSetBaudRate(38400);
    
    //sprintf(device.service.buffer, "MaintenanceMode()\r\n"); WriteConcole(); //Development message
  } else {
    DecodeFail();
  }
}

void DecodeMBasic(void) {
  DecodeExtentionCode(); if (device.user.decoder.error) return;
  switch (device.user.decoder.code) {
    case M0_CLEAR:
      DecodeCRC(); if (device.user.decoder.error) return;
      DoMaintenanceClear();
      break;
    case M0_MIRROR:
      DecodeCRC(); if (device.user.decoder.error) return;
      DoMaintenanceMirror();
      break;
    case M0_LDPAR_F:
      DecodeCRC(); if (device.user.decoder.error) return;
      DeviceFlashReadAll();
      DeviceInitState();
      break;
    case M0_LDPAR_D:
      DecodeCRC(); if (device.user.decoder.error) return;
      DeviceInitDefaultSettings();
      DeviceInitState();
      break;
    case M0_START:
      DecodeCRC(); if (device.user.decoder.error) return;
      DoMaintenanceStart();
      break;
    case M0_STOP:
      DecodeCRC(); if (device.user.decoder.error) return;
      DoMaintenanceStop();
      break;
    case M0_PULSE:
      DecodeCRC(); if (device.user.decoder.error) return;
      DeviceStartLightUp();
      break;
    default: DecodeFail();
  }
}

void DoMaintenanceClear(void) {
  //TODO
}

void DoMaintenanceMirror(void) {
  //TODO
}

void DoMaintenanceStart(void) {
  //TODO
}

void DoMaintenanceStop(void) {
  //TODO
}

//Deprecated
void DecodeMRate(void) {
  uint8_t mode = Decode8(); if (device.user.decoder.error) return;
  if ((mode & 0x1f) == 1){
    DecodeCRC(); if (device.user.decoder.error) return;
    
    //sprintf(device.service.buffer, "MRate %02x\r\n", mode); WriteConcole(); //Development message
    
    device.user.response.code |= mode & 0x1f;
    
    uint32_t baud;
    switch ((mode>>5) & 0x03) {
      case 0: baud = 38400; break;
      case 1: baud = 115200; break;
      default: baud = 38400;
    }
    userSetBaudRate(baud);
    
    if (mode & 0x80) {
      //Reset device counters here
      device.counters.dither.state.angle = 0;
      device.counters.meander.state.angle[0] = 0;
      device.counters.meander.state.angle[1] = 0;
      
      device.user.response.type = RESPONSE_PERIODIC; //Override default type
      device.user.response.trigger = 1000000; //1000000mks - 1Hz
      //device.user.response.counter = device.user.response.trigger; //Ask_Gld expect immediate answer?
      device.user.response.counter = 0; //No?
    }
  } else {
    DecodeFail();
  }
}

/* Template for MRate2,...
void DecodeMRate(void) {
  uint8_t mode = Decode8(); if (device.user.decoder.error) return;
  if ((mode & 0x1f) == 0){
    //MRate
    DecodeCRC(); if (device.user.decoder.error) return;
    
    device.user.response.code |= mode & 0x1f;
    
    switch ((mode>>5) & 0x03) {
      case 0: device.user.response.rate = 38400; break;
      case 1: device.user.response.rate = 115200; break;
      case 2: device.user.response.rate = 460800; break;
      case 3: device.user.response.rate = 921600; break;
    }
    
    if (mode & 0x80) {
      //TODO: reset device.counters here
      device.user.response.counter = 0;
      switch (mode & 0x03) {
        case 1: device.user.response.trigger = 1000000; break; //1 000 000 mks - 1Hz
        case 2: device.user.response.trigger = 3276700; break; //???
        case 3: device.user.response.trigger = 100; break;     //100 mks - 10000Hz
        case 4: device.user.response.trigger = 800; break;     //800 mks - 1250Hz
        case 7: device.user.response.trigger = 800; break;     //800 mks - 1250Hz
      }
      device.user.response.type = RESPONSE_PERIODIC; //Override default type
    }
  } else {
    DecodeFail();
  }
}*/

void DecodeMStymul(void) {
  uint8_t param = Decode8(); if (device.user.decoder.error) return;
  if ((param & 0x18) == 0){
    uint8_t hi = Decode8(); if (device.user.decoder.error) return;
    uint8_t lo = Decode8(); if (device.user.decoder.error) return;
    DecodeCRC(); if (device.user.decoder.error) return;
    
    //sprintf(device.service.buffer, "MStymul %02x %02x %02x\r\n", param, hi, lo); WriteConcole(); //Development message
    
    device.user.decoder.code |= param & 0x04;
    userSetBaudRate(38400);
    
    device.user.response.enabled = (param & 0x80) >> 7;
    
    uint8_t channel = param & 0x03;
    if (param & 0x04) {
      uint32_t flags = (hi << 8) | lo;
      //TODO: write flags - only flag register 0 defined
      if (channel == 0){
        //Potentiometers data
        if (flags & 0x01){
        } else {
        }
        //Potentiometers data input enable/disable flag
        if (flags & 0x02){
        } else {
        }
        //Laser Up
        if (flags & 0x03){
        } else {
        }
        //Software reper
        if (flags & 0x04){
        } else {
        }
      }
    } else {
      uint32_t voltage = ((hi << 4) | (lo >> 4)); //TODO: do correct transformations
      //TODO: write DAC
      switch (channel){
        case 0://PLC regulator
        break;
        case 1://PLC modulator
        break;
        case 2://laser power regulator
        break;
        case 3://worms
        break;
      }
    }
  } else {
    DecodeFail();
  }
}

void DecodeMReset(void) {
  DecodeCRC(); if (device.user.decoder.error) return;

  while (1); //Wait watch dog reset
}

//Deprecated
void DecodeMCtlR(void) {
  uint8_t param = Decode8(); if (device.user.decoder.error) return;
  DecodeCRC(); if (device.user.decoder.error) return;
  
  //sprintf(device.service.buffer, "MCtlR %02x\r\n", param); WriteConcole(); //Development message
  
  if ((param & 0x60) == 0)
    userSetBaudRate(38400);
  else
    userSetBaudRate(115200);
    
  device.user.response.code |= param & 0x10;
}

//Deprecated
void DecodeMCtlM(void) {
  uint8_t param = Decode8(); if (device.user.decoder.error) return;
  DecodeCRC(); if (device.user.decoder.error) return;
  
  //sprintf(device.service.buffer, "MCtlM %02x\r\n", param); WriteConcole(); //Development message
    
  if ((param & 0x60) == 0)
    userSetBaudRate(38400);
  else
    userSetBaudRate(115200);
    
  uint8_t bit = param & 0x0f;
  uint8_t value = (param & 0x80) >> 7;
  if ((param & 0x10) == 0) {
    //RgConA - flags of regulator loops
    switch (bit){
      case 0://Laser switch
        //TODO
      break;
      
      case 1://HFO loop switch
        device.isacs.regulator.state.enabled = value;
      break;
      
      case 3://PLC loop switch
        device.plcs.regulator.state.enabled = value;
      break;
      
      case 4://Modulator switch
        //device.plcs.modulator.state.enabled = value;
        device.sequencer.output.analog.state.enabled = value;
      break;
      
      case 5://Dither drive pulse width/output frequency loop switch
        device.dither.amplitude.state.enabled = value;
      break;
      
      case 6://Dither drive oscillation frequency loop switch
        device.dither.frequency.state.enabled = value;
      break;
      
      case 7: //All loops switch
        device.isacs.regulator.state.enabled = value;
        device.plcs.regulator.state.enabled = value;
        device.sequencer.output.analog.state.enabled = value;
        device.dither.amplitude.state.enabled = value;
        device.dither.frequency.state.enabled = value;
      break;
    }
  } else {
    //RgConB - counting mode: 00 - reference counters, 01 - dither counters and moving average filter
    switch (bit){
      case 0://Moving average filter
        device.counters.rate.state.source = value;
        #ifdef DEBUG_DECODER_INPUT
        if (value == 0)
          sprintf(device.service.buffer, "RgConB reset bit %1d\r\n", bit);
        else
          sprintf(device.service.buffer, "RgConB set bit %1d\r\n", bit);
        WriteConcole();
        #endif
      break;
      
      case 1://Not used
        //TODO
      break;
      
      case 2://Not used
        //TODO
      break;
    }
  }
    
  device.user.response.code |= param & 0x10;
}

//Deprecated
void DecodeMADCR(void) {
  //TODO
}

//Deprecated
void DecodeMTmpW(void) {
  //Not compatible with new ADC
  //Just consume required amount of input:
  Decode8(); if (device.user.decoder.error) return;
  Decode8(); if (device.user.decoder.error) return;
  Decode8(); if (device.user.decoder.error) return;
  Decode8(); if (device.user.decoder.error) return;
  Decode8(); if (device.user.decoder.error) return;
  DecodeCRC(); if (device.user.decoder.error) return;
}

//Deprecated
void DecodeMTmpR(void) {
  //Not compatible with new ADC
  //Just consume required amount of input:
  Decode8(); if (device.user.decoder.error) return;
  DecodeCRC(); if (device.user.decoder.error) return;
}

//Deprecated
void DecodeMe5rW(void) {
  //TODO
}

void DecodeMCntR(void) {
  uint8_t param = Decode8(); if (device.user.decoder.error) return;
  DecodeCRC(); if (device.user.decoder.error) return;
  
  //sprintf(device.service.buffer, "MCntR %02x\r\n", param); WriteConcole(); //Development message
    
  if ((param & 0x60) == 0)
    userSetBaudRate(38400);
  else
    userSetBaudRate(115200);
  
  if (param & 0x80) {
    device.user.response.counter = 0;
    device.user.response.trigger = 200;     //200 mks - 500Hz
    device.user.response.type = RESPONSE_PERIODIC; //Override default type
  }
}

//Deprecated
void DecodeMFlgR(void) {
  //TODO
}

//Deprecated
void DecodeMVibW(void) {
  //TODO
}

//Deprecated
void DecodeMGphW(void) {
  uint8_t reply = Decode8(); if (device.user.decoder.error) return;
  uint8_t gainA = Decode8(); if (device.user.decoder.error) return;
  uint8_t gainB = Decode8(); if (device.user.decoder.error) return;
  DecodeCRC(); if (device.user.decoder.error) return;
  device.isacs.potentiometers.state.a = gainA;
  device.isacs.potentiometers.state.b = gainB;
  DeviceISACSSetPotentiometers();
  if (!reply) device.user.response.enabled = 0;
}

uint16_t GetCompatibilityValue(uint8_t index) {
    
    return 0;
}

//Deprecated
void DecodeMParamR(void) {
  uint8_t index = Decode8(); if (device.user.decoder.error) return;
  DecodeCRC(); if (device.user.decoder.error) return;
  
  uint32_t param32;
  switch (index){
    case 0:
      //My_Address s16 device address
      device.user.response.message = device.user.address;
    break;
    
    case 1:
      //HF_ref s16 value of the reference
      //int32_t device.isacs.regulator.settings.reference
      device.user.response.message = param_HF_ref();
    break;
    
    case 2:
      //HF_scl s16 HFO gain factor
      //int32_t device.isacs.regulator.settings.scale
      device.user.response.message = param_HF_scl();
    break;
    
    case 3:
      //HF_min dac ttf:minimum DAC code in HFO channel; value:maximal voltage of HFO; value=(ttf>>4)/2048*(-12)-1.3; Range -13.2V...10.7V
      //int32_t device.isacs.output.settings.max
      device.user.response.message = param_HF_min();
    break;
    
    case 4:
      //HF_max dac ttf:maximum DAC code in HFO channel; value:minimal voltage of HFO; value=(ttf>>4)/2048*(-12)-1.3; Range -13.2V...10.7V
      //int32_t device.isacs.output.settings.min
      device.user.response.message = param_HF_max();
    break;
    
    case 5:
      //RI_ref s16 not used (DS reference)
      device.user.response.message = 0;
    break;
    
    case 6:
      //RI_scl s16 not used (DS gain factor)
      device.user.response.message = 0;
    break;
    
    case 7:
      //WP_ref s16 PLCS reference
      //int32_t device.plcs.regulator.reference
      device.user.response.message = param_WP_ref();
    break;
    
    case 8:
      //WP_scl s16 PLCS gain factor (1.15) 5..20
      //int32_t device.plcs.regulator.scale
      device.user.response.message = param_WP_scl();
    break;
    
    case 9:
      //WP_mdy s16 PLCS reset delay in 10kHz cycles
      //device.plcs.reset.up/down.state.duration
      device.user.response.message = param_WP_mdy();
    break;
    
    case 10:
      //WP_rup dac ttf:PLCS maximum DAC code in heater channel; value:minimal voltage on the heater; value=(ttf>>4)/2048*(-12)-1.3; Range -13.2V...10.7V
      //device.plcs.reset.up.state.trigger
      device.user.response.message = param_WP_rup();
    break;
    
    case 11:
      //WP_rdw dac ttf:PLCS minimum DAC code in heater channel; value:maximal voltage on the heater; value=(ttf>>4)/2048*(-12)-1.3; Range -13.2V...10.7V
      //device.plcs.reset.down.state.trigger
      device.user.response.message = param_WP_rdw();
    break;
    
    case 12:
      //VB_phs s16 the phase delay parameter of the dither drive PLL
      //0
      device.user.response.message = 0;
    break;
      
    case 13:
      //VB_scl s16 the gain factor (1.15) of the dither drive PLL
      param32 = device.dither.frequency.settings.scale >> 16;
      device.user.response.message = (uint16_t)param32;
    break;
      
    case 14:
      //VB_N vbd ttf:dither drive oscillation central frequency divider 7680000/F; value:dither drive central oscillation frequency
      device.user.response.message = param_VB_N();
    break;
      
    case 15:
      //VB_Nmin vbd ttf:minimum dither drive oscillation frequency divider 7680000/F; value:maximum dither drive oscillation frequency
      device.user.response.message = param_VB_Nmin();
    break;
      
    case 16:
      //VB_Nmax vbd ttf:maximum dither drive oscillation frequency divider 7680000/F; value:minimum dither drive oscillation frequency
      device.user.response.message = param_VB_Nmax();
    break;
      
    case 17:
      //VB_Fdf s32 double output frequency (Hi)
      param32 = param_VB_Fdf() >> 16;
      device.user.response.message = (uint16_t)param32;
    break;
      
    case 18:
      //VB_Fdf s32 double output frequency (Lo)
      param32 = param_VB_Fdf() & 0xffff;
      device.user.response.message = (uint16_t)param32;
    break;
      
    case 19:
      //VB_Fsc s16 the gain factor of the frequency regulator
      param32 = device.dither.amplitude.settings.scale >> 16;
      device.user.response.message = (uint16_t)param32;
    break;
      
    case 20:
      //VB_Tmin tau minimum pulse width of the dither drive; value=ttf/15360000 in seconds
      device.user.response.message = param_VB_Tmin();
    break;
      
    case 21:
      //VB_Tmax tau maximum pulse width of the dither drive; value=ttf/15360000 in seconds
      device.user.response.message = param_VB_Tmax();
    break;
      
    case 22:
      //VB_tau tau pulse width of the dither drive without noise or current pulse width of the dither drive with noise; value=ttf/15360000 in seconds
      device.user.response.message = param_VB_tau();
    break;
      
    case 23:
      //VBN_Tzd s16 adjusted noise period
      //int32_t device.dither.noise.settings.period
      device.user.response.message = param_VBN_Tzd();
    break;
      
    case 24:
      //VBN_Ran s16 range of the random component of noise
      //int32_t device.dither.noise.settings.range
      device.user.response.message = param_VBN_Ran();
    break;
      
    case 25:
      //VBN_k s16 adjusted noise constant: pulse width = VB_tau +/- VBN_k
      //int32_t device.dither.noise.settings.amplitude
      device.user.response.message = param_VBN_k();
    break;
      
    case 26:
    case 27:
    case 28:
    case 29:
    case 30:
    case 31:
    case 32:
    case 33:
    case 34:
    case 35:
    case 36:
    case 37:
    case 38:
    case 39:
    case 40:
    case 41:
    case 42:
      //Reserved s16 not used
      device.user.response.message = 0;
    break;
      
    case 43:
    case 44:
    case 45:
    case 46:
    case 47:
    case 48:
      //Tmp_bias0[0] ... Tmp_bias0[5] s16 Tmp_bias[6]: an array of shifts of the 0..5 temperature sensors
      //?
      device.user.response.message = 0;
    break;
      
    case 49:
    case 50:
    case 51:
    case 52:
    case 53:
    case 54:
      //Tmp_scal0[0] ... Tmp_scal0[5] s16 Tmp_scal[6]: an array of the scale coefficients of the 0..5 temperature sensors
      //?
      device.user.response.message = 0;
    break;
      
    case 55:
      //WP_reset dac ttf:PLCS DAC code after reset at heating; value:heater voltage after reset at heating; value=(ttf>>4)/2048*(-12)-1.3; Range -13.2V...10.7V
      //int32_t device.plcs.reset.up.state.target
      device.user.response.message = param_WP_reset();
    break;
      
    case 56:
      //KSin s16 Gain_Ph_A: initial gain factor of the A channel of photodetector
      //uint32_t device.isacs.potentiometers.settings.a
      device.user.response.message = 0;
    break;
      
    case 57:
      //KCos s16 Gain_Ph_B: initial gain factor of the B channel of photodetector
      //uint32_t device.isacs.potentiometers.settings.b
      device.user.response.message = 0;
    break;
      
    case 58:
      //Header s16 flash memory load validity control value: should be 0x55AA
      device.user.response.message = 0x55AA;
    break;
      
    case 59:
      //LoadFlash_Enable s16 parameters load switch: 1 - load from the flash 0 - load default parameters (factory)
      //?
      device.user.response.message = 1;
    break;
      
    case 60:
      //SerialNumber u16 serial number of device
      //
      device.user.response.message = 0;
    break;
      
    case 61:
      //WP_start dac not used (ttf:PLCS initial DAC code after switch-on; value:heater voltage after switch-on; value=(ttf>>4)/2048*(-12))-1.3; Range -13.2V...10.7V
      device.user.response.message = 0;
    break;
      
    case 62:
      //TermoMode u16 device operation mode switch: 0-raw output, 1-thermocompensated output, 2-thermocompensation value only for debug purposes
      //?
      device.user.response.message = 0;
    break;
      
    case 63:
    case 64:
    case 65:
    case 66:
    case 67:
    case 68:
    case 69:
    case 70:
    case 71:
    case 72:
    case 73:
    case 74:
    case 75:
    case 76:
      //TemperInt[0] ... TemperInt[13] s16 reserved: should be zero!
      //
      device.user.response.message = 0;
    break;
      
    case 77:
    case 78:
    case 79:
    case 80:
    case 81:
    case 82:
    case 83:
    case 84:
    case 85:
    case 86:
    case 87:
    case 88:
    case 89:
    case 90:
    case 91:
    case 92:
    case 93:
    case 94:
    case 95:
    case 96:
    case 97:
    case 98:
    case 99:
    case 100:
    case 101:
    case 102:
    case 103:
    case 104:
      //TermoFunc[0]...TermoFunc[13] f32 reserved: should be zero! (Hi)/(Lo)
      device.user.response.message = 0;
    break;
      
    case 105:
      //WP_reset2 dac ttf:PLCS DAC code after reset at cooling; value:heater voltage after reset at cooling; value=(ttf>>4)/2048*(-12)-1.3
      //int32_t device.plcs.reset.down.state.target
      device.user.response.message = param_WP_reset2();
    break;
      
    case 106:
    case 107:
      //TermoHeatDelta f32 reserved: should be zero! (Lo)
      device.user.response.message = 0;
    break;
      
    case 108:
    case 109:
      //TermoCoolDelta f32 reserved: should be zero! (Lo)
      device.user.response.message = 0;
    break;
      
    case 110:
      //K_vb_tu s16 slope of dependence of the VB_N division factor from temperature (as though Hz/degree, but in c.u.)
      //?
      device.user.response.message = 0;
    break;
      
    case 111:
      //TemperNormal s16 temperature for which the VB_N division factor of the dither drive is set
      //?
      device.user.response.message = 0;
    break;
      
    case 112:
      //K_WP_rst_heating s16 
      //?
      device.user.response.message = 0;
    break;
      
    case 113:
      //K_WP_rst_cooling s16 slope of dependence of a reset voltage at cooling from temperature (as though Volt/degree, but in c.u. of DAC and temperature sensors)
      //?
      device.user.response.message = 0;
    break;
      
    case 114:
      //WP_transition_step s16 step of change of a heater voltage at resetting
      //?
      device.user.response.message = 0;
    break;
      
    case 115:
      //Reserved s16 not used
      device.user.response.message = 0;
    break;
      
    case 116:
      //HF_scl_2 s16 HFO scale factor during PLCS reset 
      //Deprecated: always same as HF_scl
      device.user.response.message = param_HF_scl();
    break;
      
    case 117:
      //TemperIntDyn[0] s16 thermal sensor value for first point of thermo error interpolation at heating
      //?
      device.user.response.message = 0;
    break;
      
    case 118:
      //TemperIntDyn[1] s16 thermal sensor value for interim point of thermo error interpolation at heating
      //?
      device.user.response.message = 0;
    break;
      
    case 119:
      //TemperIntDyn[2] s16 thermal sensor value for interim point of thermo error interpolation at heating
      //?
      device.user.response.message = 0;
    break;
      
    case 120:
      //TemperIntDyn[3] s16 thermal sensor value for interim point of thermo error interpolation at heating
      //?
      device.user.response.message = 0;
    break;
      
    case 121:
      //TemperIntDyn[4] s16 thermal sensor value for interim point of thermo error interpolation at heating
      //?
      device.user.response.message = 0;
    break;
      
    case 122:
      //TemperIntDyn[5] s16 thermal sensor value for interim point of thermo error interpolation at heating
      //?
      device.user.response.message = 0;
    break;
      
    case 123:
      //TemperIntDyn[6] s16 thermal sensor value for interim point of thermo error interpolation at heating
      //?
      device.user.response.message = 0;
    break;
      
    case 124:
      //TemperIntDyn[7] s16 thermal sensor value for interim point of thermo error interpolation at heating
      //?
      device.user.response.message = 0;
    break;
      
    case 125:
      //TemperIntDyn[8] s16 thermal sensor value for interim point of thermo error interpolation at heating
      //?
      device.user.response.message = 0;
    break;
      
    case 126:
      //TemperIntDyn[9] s16 thermal sensor value for interim point of thermo error interpolation at heating
      //?
      device.user.response.message = 0;
    break;
      
    case 127:
      //TemperIntDyn[10] s16 thermal sensor value for interim point of thermo error interpolation at heating
      //?
      device.user.response.message = 0;
    break;
      
    case 128:
      //TemperIntDyn[11] s16 thermal sensor value for interim point of thermo error interpolation at heating
      //?
      device.user.response.message = 0;
    break;
      
    case 129:
      //TemperIntDyn[12] s16 thermal sensor value for interim point of thermo error interpolation at heating
      //?
      device.user.response.message = 0;
    break;
      
    case 130:
      //TemperIntDyn[13] s16 thermal sensor value for last point of thermo error interpolation at heating
      //?
      device.user.response.message = 0;
    break;
      
    case 131:
      //ThermoHeatDelta[0] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 132:
      //ThermoHeatDelta[0] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
      
    case 133:
      //ThermoHeatDelta[1] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 134:
      //ThermoHeatDelta[1] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
      
    case 135:
      //ThermoHeatDelta[2] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 136:
      //ThermoHeatDelta[2] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
      
    case 137:
      //ThermoHeatDelta[3] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 138:
      //ThermoHeatDelta[3] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
      
    case 139:
      //ThermoHeatDelta[4] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 140:
      //ThermoHeatDelta[4] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
      
    case 141:
      //ThermoHeatDelta[5] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 142:
      //ThermoHeatDelta[5] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
      
    case 143:
      //ThermoHeatDelta[6] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 144:
      //ThermoHeatDelta[6] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
      
    case 145:
      //ThermoHeatDelta[7] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 146:
      //ThermoHeatDelta[7] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
      
    case 147:
      //ThermoHeatDelta[8] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 148:
      //ThermoHeatDelta[8] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
      
    case 149:
      //ThermoHeatDelta[9] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 150:
      //ThermoHeatDelta[9] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
      
    case 151:
      //ThermoHeatDelta[10] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 152:
      //ThermoHeatDelta[10] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
      
    case 153:
      //ThermoHeatDelta[11] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 154:
      //ThermoHeatDelta[11] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
      
    case 155:
      //ThermoHeatDelta[12] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 156:
      //ThermoHeatDelta[12] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
      
    case 157:
      //ThermoHeatDelta[13] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 158:
      //ThermoHeatDelta[13] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
      
    case 159:
      //DeltaTempRecalc s16
      //?
      device.user.response.message = 0;
    break;
      
    case 160:
      //TemperCoolIntDyn[0] s16 thermal sensor value for first point of thermo error interpolation at cooling
      //?
      device.user.response.message = 0;
    break;
      
    case 161:
      //TemperCoolIntDyn[1] s16 thermal sensor value for interim point of thermo error interpolation at cooling
      //?
      device.user.response.message = 0;
    break;
      
    case 162:
      //TemperCoolIntDyn[2] s16 thermal sensor value for interim point of thermo error interpolation at cooling
      //?
      device.user.response.message = 0;
    break;
      
    case 163:
      //TemperCoolIntDyn[3] s16 thermal sensor value for interim point of thermo error interpolation at cooling
      //?
      device.user.response.message = 0;
    break;
      
    case 164:
      //TemperCoolIntDyn[4] s16 thermal sensor value for interim point of thermo error interpolation at cooling
      //?
      device.user.response.message = 0;
    break;
      
    case 165:
      //TemperCoolIntDyn[5] s16 thermal sensor value for interim point of thermo error interpolation at cooling
      //?
      device.user.response.message = 0;
    break;
      
    case 166:
      //TemperCoolIntDyn[6] s16 thermal sensor value for interim point of thermo error interpolation at cooling
      //?
      device.user.response.message = 0;
    break;
      
    case 167:
      //TemperCoolIntDyn[7] s16 thermal sensor value for interim point of thermo error interpolation at cooling
      //?
      device.user.response.message = 0;
    break;
      
    case 168:
      //TemperCoolIntDyn[8] s16 thermal sensor value for interim point of thermo error interpolation at cooling
      //?
      device.user.response.message = 0;
    break;
      
    case 169:
      //TemperCoolIntDyn[9] s16 thermal sensor value for interim point of thermo error interpolation at cooling
      //?
      device.user.response.message = 0;
    break;
      
    case 170:
      //TemperCoolIntDyn[10] s16 thermal sensor value for interim point of thermo error interpolation at cooling
      //?
      device.user.response.message = 0;
    break;
      
    case 171:
      //TemperCoolIntDyn[11] s16 thermal sensor value for interim point of thermo error interpolation at cooling
      //?
      device.user.response.message = 0;
    break;
      
    case 172:
      //TemperCoolIntDyn[12] s16 thermal sensor value for interim point of thermo error interpolation at cooling
      //?
      device.user.response.message = 0;
    break;
      
    case 173:
      //TemperCoolIntDyn[13] s16 thermal sensor value for last point of thermo error interpolation at cooling
      //?
      device.user.response.message = 0;
    break;
      
    case 174:
      //ThermoCoolDelta[0] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 175:
      //ThermoCoolDelta[0] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
      
    case 176:
      //ThermoCoolDelta[1] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 177:
      //ThermoCoolDelta[1] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
      
    case 178:
      //ThermoCoolDelta[2] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 179:
      //ThermoCoolDelta[2] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
      
    case 180:
      //ThermoCoolDelta[3] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 181:
      //ThermoCoolDelta[3] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
      
    case 182:
      //ThermoCoolDelta[4] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 183:
      //ThermoCoolDelta[4] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
      
    case 184:
      //ThermoCoolDelta[5] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 185:
      //ThermoCoolDelta[5] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
      
    case 186:
      //ThermoCoolDelta[6] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 187:
      //ThermoCoolDelta[6] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
      
    case 188:
      //ThermoCoolDelta[7] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 189:
      //ThermoCoolDelta[7] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
      
    case 190:
      //ThermoCoolDelta[8] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 191:
      //ThermoCoolDelta[8] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
      
    case 192:
      //ThermoCoolDelta[9] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 193:
      //ThermoCoolDelta[9] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
      
    case 194:
      //ThermoCoolDelta[10] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 195:
      //ThermoCoolDelta[10] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
      
    case 196:
      //ThermoCoolDelta[11] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 197:
      //ThermoCoolDelta[11] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
      
    case 198:
      //ThermoCoolDelta[12] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 199:
      //ThermoCoolDelta[12] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
      
    case 200:
      //ThermoCoolDelta[13] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Hi)
      //?
      device.user.response.message = 0;
    break;
      
    case 201:
      //ThermoCoolDelta[13] tc ttf:value of thermo error per 10kHz cycle; value:value of thermo error for 100 second accumulation (Lo)
      //?
      device.user.response.message = 0;
    break;
    /*  
    case 27:
    case 28:
    case 29:
    case 30:
    case 31:
    case 32:
    case 33:
    case 34:
    case 35:
    case 36:
    case 37:
    case 38:
    case 39:
    case 40:
    case 41:
    case 42:
    case 43:
    break;

    case 61:
      param16 = device.sensor.settings.id;
    break;

    case 64:
    case 65:
    case 66:
    case 67:
    case 68:
    case 69:
    case 70:
    case 71:
    case 72:
    case 73:
    case 74:
    case 75:
    case 76:
    case 77:
    case 78:
    case 79:
    case 81:
    case 82:
    case 84:
    case 85:
    case 87:
    case 88:
    case 90:
    case 91:
    case 93:
    case 94:
    case 96:
    case 97:
    case 99:
    case 100:
    case 102:
    case 103:
    case 105:
    case 106:
    case 108:
    case 109:
    case 111:
    case 112:
    case 114:
    case 115:
    case 117:
    case 118:
    case 121:
    case 122:
    case 124:
    case 125:
      //reserved
    break;
    */
    default: DecodeFail();
  }
}

void DecodeMParamW(void) {
  uint8_t index = Decode8(); if (device.user.decoder.error) return;
  uint8_t param = Decode16(); if (device.user.decoder.error) return;
  DecodeCRC(); if (device.user.decoder.error) return;
  
  switch (index){
    case 0:
      device.user.address = param;
    break;

    case 27:
    case 28:
    case 29:
    case 30:
    case 31:
    case 32:
    case 33:
    case 34:
    case 35:
    case 36:
    case 37:
    case 38:
    case 39:
    case 40:
    case 41:
    case 42:
    case 43:
    break;

    case 61:
      device.sensor.settings.id = param;
    break;

    case 64:
    case 65:
    case 66:
    case 67:
    case 68:
    case 69:
    case 70:
    case 71:
    case 72:
    case 73:
    case 74:
    case 75:
    case 76:
    case 77:
    case 78:
    case 79:
    case 81:
    case 82:
    case 84:
    case 85:
    case 87:
    case 88:
    case 90:
    case 91:
    case 93:
    case 94:
    case 96:
    case 97:
    case 99:
    case 100:
    case 102:
    case 103:
    case 105:
    case 106:
    case 108:
    case 109:
    case 111:
    case 112:
    case 114:
    case 115:
    case 117:
    case 118:
    case 121:
    case 122:
    case 124:
    case 125:
      /*reserved*/
    break;
    
    default: DecodeFail();
  }
}

void DecodeMRate2(void) {
  //TODO
}

void DecodeMRate3(void) {
  //TODO
}

//Deprecated
void DecodeMe5raW(void) {
  //TODO
}