Serial port write buffer
I see a number of things that may help you improve your program.

Don't use Hungarian notation

Read this for an explantion of why you shouldn't use Hungarian notation. 

Use unsigned types where appropriate

It's unlikely that the values you are passing to ConvertShortToByte or ConvertIntToByte are intended to be signed values.  Signed values are treated differently than unsigned values when shifted because of sign extension.  In this case, that's almost certainly not what is needed.

Return something useful from functions

The conversion functions would be more useful if they returned a pointer just past the current value.  Also rather than a pointer and index, why not just pass a pointer?  Rewritten that would look like this:

BYTE *ConvertShortToByte(unsigned short value, BYTE* buffer)
{
  *buffer++ = value &gt;&gt; 8;
  *buffer++ = value;
  return buffer;
}


Eliminate "magic numbers"

This code has a number of "magic numbers," that is, unnamed constants such as 0x0B, 0xCA, 60 etc.  Generally it's better to avoid that and give such constants meaningful names.  That way, if anything ever needs to be changed, you won't have to go hunting through the code for all instances of "60" and then trying to determine if this particular 60 is relevant to the desired change or if it is some other constant that happens to have the same value.

Use an object

A packet is a natural for an object, so why not make a Packet class?  Here's one way to do it:

class Packet {
public:
    Packet (unsigned seq, unsigned time, const std::vector&lt;unsigned short&gt;&amp; data)
    {
      BYTE *buff = buffer;
      *buff++ = MSG_TYPE;
      buff = ConvertIntToByte(time, buff);
      buff = ConvertIntToByte(seq, buff);
      buff = ConvertIntToByte(0, buff); // filler
      buff = ConvertShortToByte(data.size(), buff);
      for (const auto item : data) {
          buff = ConvertShortToByte(item, buff);
      }
      *buff++ = MSG_END;
    }
    size_t size() const { return 16 + (((buffer[13] &lt;&lt; 8) + buffer[14]) &lt;&lt; 1); }
    static constexpr BYTE MSG_TYPE = 0x0B;  // start of packet
    static constexpr BYTE MSG_END = 0xCA;  // end of packet
    static constexpr size_t BUFF_SIZE = 60;
private:
    BYTE buffer[BUFF_SIZE];
};


If you need access to the underlying buffer, there are a few ways to do it.  First, you could simply make the buffer a public data member (or alternatively make Packet a struct).  Second, you could provide a handle that would return a const * reference to the internal buffer.  Third, you could eliminate the need by providing, for example a write member function.  Fourth, you could declare the buffer in place and then use "placement new" which is a common idiom for communications protocols in which a packet is built in a fixed location buffer.  Since many people seem unfamiliar with the use of "placement new", I'll elaborate.

Use "placement new"

If a buffer is already allocated and you want to create a Packet in place, it can be done using "placement new":

BYTE ucXmtdat[60];
Packet *pkt = new (ucXmtdat) Packet(m_iMsgSequence, iUTCTime, m_data);


This creates a Packet at the location specified by ucXmtdat without allocating further memory.  Note that when this form is used, it is entirely up to you to make sure that the memory area is really big enough and it's entirely up to you to destroy the object when finished.  In this case, there's not really anything to do since ucXmtdat (which is not a very nice name, by the way) is local and will simply disappear when it goes out of scope.