Thanks for all the help.
After doing some investigation with an oscilloscope, I've figured out what's going on:
Sample pure data from reader (LSB first, spaces added for clarity):
10 0000 11000 10 0000 00000 10 0100 01110 10 1011 00001 10 0101 00000 10
^s 0 ^3 ^p^s ^0 ^0 ^p^s ^2 ^E ^p^s ^D ^0 ^p^s ^A ^0 ^s
For a data value of
0 3 0 0 2 E D 0 A 0 -> 30 00 E2 0D 0A
s is the stop indicator, p is the parity bit, and others are the hex data.
What is happening on my arduino is that the parity bit is being read as the most significant bit for the second half of the byte, then the previous least significant bit is used to overwrite the new least significant bit of that half-byte.
Applied to the previous example:
11000 -> 1000
00000 -> 0000
01110 -> 0110
00001 -> 0001
00000 -> 0000
which produces:
0 1 0 0 2 6 D 8 A 0 -> 10 00 62 8D 0A
explaining the conversion that you see in my original example at the start and end bytes:
30 00 E2 0D 0A -> 10 00 62 8D 0A
If for some reason anyone else runs into this incredibly specific problem, I've converted the data back in the arduino logic with these functions (no they're not optimal):
byte fixBits(byte rc) {
byte five = rc & 0x10;
byte six = getParity(rc) << 5;
byte hex1 = (rc & 0xF0) << 1;
byte hex2 = rc & 0x0F;
return ((hex2 | hex1) & 0xCF) | five | six; // bit masking
}
byte getParity(byte rc) {
int sum = 0;
byte test = rc;
for (int i = 0; i < 8; i++) {
sum += test & 1;
test >> 1;
}
return sum & 1;
}
If anyone can describe exactly why this is happening I'd be curious to hear it, but otherwise this issue is solved.