Hacking CH923/CH925/CH926/CH928/JY923/JY925/JY926/JY928 coin acceptor Diagnostic

Purpose / Reason why i would do this:
Simply because the device is cheap and easily accessible for most people, and the pulse count output that it comes with is pretty lame, it misses coins and is a pain in the butt to train the device, however the diagnostic terminal on the bottom puts out information that is essential what ever coin is passed through it weather it accepts it or not. im also thinking that the information on whether it accepted the coin or not is also in the packet. this would mean the end of days for counting pulses, instead the pulse output could be used as a means to interrupt the arduino. another advantage to this would be you would be able to identify more than the stock 6 types of coin, in the us we have 6 major coins, but there are more coins in circulation and each of them are slightly different. (50c piece, silver dollar, susan b anthony, gold dollars, quarters, nickles, dimes, pennies)

What I have so far:

through the only article i can find on the internet i have established that there is a serial output coming from the bottom diagnostic connector on pin 2 or pin 5 depending on how you hold the device, the information as the article says is 19200 baud, however the information i get from the terminal is different than the article, inside the device is a 12c5208AD micro controller it emits serial from the 5th pin, which is how i tracked it to the the diagnostic port is with a continuity meter.

data collected:

with my initial test i collected some information using this code:

void setup() {
  // Open serial communications and wait for port to open:
  Serial.begin(115200);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  Serial.println("Serial 1: Online");
  Serial3.begin(19200);
  while (!Serial3) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  Serial.println("Serial 2: Online");

}

void loop() { // run over and over
  if (Serial3.available()) {
    //int incomingByte = Serial3.read();
    //  Serial.print(incomingByte, HEX);
    //  Serial.print(' ');
    //Serial.write(Serial3.read());
    //Serial.write(cmd,12); // Request Match from scanner
    //delay(100);
    //cnt = 0;
    word mybuffer[11];
    unsigned long startWait = millis();
    while (Serial3.available() < 10 && (millis() - startWait < 3000))
    {
      // Don't do a thing
    }

    // At this point, there are 12 characters or we waited too long
    if (Serial3.available() >= 10)
    {
      for (int i = 0; i < 10; i++)
      {
       mybuffer[i] = Serial3.read();
      }

      for (int i = 0; i < 10; i++)
      {
        Serial.print(mybuffer[i], HEX);
      }
      Serial.println(' ');
    }
    else
    {
      // No reply from scanner in reasonable time
    }
  }

  if (Serial.available()) {
    Serial3.write(Serial.read());
  }
}

is is pretty clear lat the two beginning identifiers are unique to perhaps the diameter of the coin, what the information is im really not concerned with exactly because it could be a bunch of variables telling the actual parameters of the individual coin, which if i worked for the department of weights and measures would probably be really useful, however right now i just need it to identify ALL of the US coins that are currently in circulation.

All coins USD
5, 50c pieces 
16B09091FD1FB 
16809091FD1FB 
16909071FD1FB 
16B09091FD1FB 
16D09091FC1FB
5, Gold Dollars 
17901E06F1FC1FB 
17601E06E1FD1FB 
17501E0691FC1FB 
17401E06F1FC1FB 
17401E06D1FD1FB 

5, Nickles
1E215F1F51FD1FB 
1E315B1F31FD1FB 
1E015C1F51FD1FB 
1E315F1F51FD1FB 
1E01561F31FC1FB 

5, Dimes
1890AE1FD1FC1FB 
1890BE1FC1FD1FB 
1890A81FC1FD1FB 
1890AB1FD1FD1FB 
18C0B31FD1FD1FB 

5, Pennies
19909C1F91FC1FB 
19A09F1FB1FC1FB 
19B0931FB1FD1FB 
19A0A01FC1FD1FB 
19109B1FD1FD1FB

it is probably of worthy note that all of the above coins were rejected because the unit i have is broken, so the values of an accepted coin may be different i wont be able to see that for about another week when i get the replacement in.

obviously if i use the information i can collect currently as a hash it will fail most of the time, so what do you think the best way of "converting" or using this data to identify the coins would be?

in the next couple hours i am going to try the simplest approach and see what sort of results i get, and that is if i add all of the numbers together and average them to see if there is enough variation in the hashes to tell them apart. if you have a better option i would totally love to hear it, as well as any positive and general advice anyone may have .

well some small good news, this coin acceptor isnt broke,i reprogrammed it and it works just fine.

i didn't see a memory battery while i was poking around inside but perhaps they have some sort of memory loss issue.

with that news i programmed it only to receive pennies since i have the most of them after running the same sketch as before my penny information on accept is a little bit different:

19B09D1FD1FE1FE 
19A0951FB1FE1FE 
1980961FB1FE1FE 
1960991FC1FE1FE 
19D09C1FC1FE1FE 
1950981FE1FE1FE 
19E09C1FB1FE1FE 
18304F1FC1FE1FE 
1960931FC1FE1FE 
1980931FB1FE1FE 
1A009E1FC1FE1FE 
18004E1FE1FE1FE 
19A09C1FE1FE1FE 
19B09C1FD1FE1FE 
19909F1FE1FE1FE 
19C09C1FD1FE1FE 
19B0A31FE1FE1FE 
19509C1FE1FE1FE 
19E09C1FE1FE1FE 
19B09E1FE1FE1FE 
19E09C1FC1FE1FE 
19D0A21FE1FE1FE

a direct comparison for the same penny (because i drew a smiley face on it with a sharpie) looks like this:

19909C1F91FC1FB    not accepted

19909F1FE1FE1FE    accepted

so it would appear that the first 2 hex are the type of the coin, perhaps, (pure speculation) then 909f/909c are coin specific parameters? shooting in the dark, off to go come up with a coin checksum algorithm...of some sort... :slight_smile:

Update:

i accidentally picked up a dime, and put it into the acceptor and it accepted it as a penny, on the machine itself, this could have to do with my 'f' settings in the actual programming of the machine i set F for coin 1 to 20 and since pennies and dimes are about the same size, i can see why it accepted it, however on the diagnostic output you can still see it was a dime:

1 97 0 90 1 FD 1 FE 1 FE  penny
1 8F 0 93 1 FE 1 FE 1 FE  penny
1 9A 0 9E 1 FD 1 FF 1 FE  penny
1 97 0 93 1 FE 1 FE 1 FE  penny
1 80 0 9F 1 FE 1 FE 1 FE  dime
1 7D 0 4B 1 FE 1 FF 1 FE  penny
1 92 0 90 1 FE 1 FE 1 FE  
1 93 0 96 1 FD 1 FE 1 FE  
1 93 0 93 1 FE 1 FE 1 FE  
1 95 0 96 1 FE 1 FF 1 FE  
1 95 0 96 1 FE 1 FF 1 FE  
1 9B 0 93 1 FD 1 FF 1 FE  
1 99 0 99 1 FE 1 FE 1 FE  
1 81 0 AB 1 FE 1 FE 1 FE  dime 
1 89 0 B1 1 FE 1 FE 1 FE  dime 
1 86 0 B4 1 FE 1 FE 1 FE  dime
1 89 0 B2 1 FE 1 FE 1 FE  dime
1 83 0 A4 1 FE 1 FE 1 FE  dime

im going to go change the f value to 10 and see what happens

Update 2:

after changing the value of "F" to 10 my results are different and a little better:

1 99 0 99 1 FD 1 FE 1 FE  Penny Accepted      sum = 22F / 3 = BA
1 9D 0 9C 1 FD 1 FE 1 FE  ""                  sum = 236 / 3 = BC
1 9C 0 A2 1 FE 1 FE 1 FE  ""
1 99 0 8E 1 FB 1 FE 1 FE  Penny Rejected
1 9E 0 9F 1 FD 1 FE 1 FE  Penny Accepted      sum = 23A / 3 = BE
1 80 0 48 1 FB 1 FE 1 FE  ""
1 9B 0 9F 1 FC 1 FE 1 FE  ""
1 9B 0 9F 1 FC 1 FE 1 FE  ""
1 9C 0 9F 1 FD 1 FE 1 FE  ""
1 A2 0 9F 1 FC 1 FE 1 FE  ""
1 9C 0 9C 1 FC 1 FE 1 FE  ""
1 9E 0 A5 1 FD 1 FE 1 FE  ""
1 8B 0 AE 1 FE 1 FE 1 FE  Dime Rejected           sum = 237 / 3 = BD
1 8C 0 BA 1 FE 1 FE 1 FE  ""                                      C1
1 89 0 AB 1 FE 1 FE 1 FE  ""                                      BB
1 89 0 AE 1 FE 1 FE 1 FE  ""                                      BC
1 86 0 B1 1 FE 1 FE 1 FE  ""

it would appear the "1 FE 1 FE" on the end is a constant of some sort, but with the device unprogrammed the end constant was "FB" i think that i can for this moment rule out the "FB" and go with what i know, based on the pattern above the 1 and 0's wouldnt have a very large impact on a hash, so i will remove them and use the changing data in columns 2,4,6 to see if i can come up with a coin filter.

Update 3:
averaging the values wont work. need another method

ok i dont think that basic math is going to solve this this time i tried 2 * 4 + 6 / '3':

 Hash: 7184 Orig: 1 8E 0 96 1 FE 1 FE 1 FE  Penny Accepted
 Hash: 7287 Orig: 1 92 0 94 1 FE 1 FE 1 FE  ""
 Hash: 7832 Orig: 1 95 0 9C 1 FD 1 FE 1 FE  ""
 Hash: 7091 Orig: 1 8F 0 93 1 FE 1 FE 1 FE  ""
 Hash: 6895 Orig: 1 8B 0 93 1 FE 1 FE 1 FE  ""
 Hash: 7138 Orig: 1 94 0 8F 1 FC 1 FE 1 FE  ""
 Hash: 7532 Orig: 1 98 0 93 1 FC 1 FE 1 FE  ""
 Hash: 7988 Orig: 1 98 0 9C 1 FE 1 FE 1 FE  ""
 Hash: 7782 Orig: 1 9B 0 95 1 FD 1 FE 1 FE  ""
 Hash: 8246 Orig: 1 9A 0 9F 1 FD 1 FE 1 FE  ""
 Hash: 3241 Orig: 1 80 0 4A 1 FD 1 FE 1 FE  Dime Rejected
 Hash: 7156 Orig: 1 88 0 9C 1 FE 1 FE 1 FE  Same Dime 4 more times
 Hash: 7202 Orig: 1 83 0 A3 1 FE 1 FE 1 FE  
 Hash: 7115 Orig: 1 83 0 A1 1 FE 1 FE 1 FE  
 Hash: 7482 Orig: 1 89 0 A2 1 FE 1 FE 1 FE  
 Hash: 7444 Orig: 1 8A 0 A0 1 FE 1 FE 1 FE

I think i have hit on something, just not sure what it is...

Recent Test:

Pennies Accepted: 
Hash: 8092 Orig: 1 9A 0 9C 1 FD 1 FE 1 FE  
 Hash: 8403 Orig: 1 9C 0 A0 1 FB 1 FE 1 FE  
 Hash: 7682 Orig: 1 95 0 99 1 FB 1 FE 1 FE  
 Hash: 3489 Orig: 1 83 0 4E 1 FB 1 FE 1 FE  
 Hash: 7937 Orig: 1 9A 0 99 1 FB 1 FE 1 FE  
 Hash: 7583 Orig: 1 96 0 96 1 FB 1 FE 1 FE  
 Hash: 7988 Orig: 1 9B 0 99 1 FB 1 FE 1 FE  
 Hash: 8143 Orig: 1 9B 0 9C 1 FB 1 FE 1 FE  
 Hash: 7785 Orig: 1 99 0 97 1 FC 1 FE 1 FE  
 Hash: 7733 Orig: 1 99 0 96 1 FB 1 FE 1 FE  
Dimes Accepted
 Hash: 7482 Orig: 1 89 0 A2 1 FD 1 FE 1 FE  
 Hash: 7590 Orig: 1 8B 0 A2 1 FD 1 FE 1 FE  
 Hash: 7924 Orig: 1 8C 0 A8 1 FD 1 FE 1 FE  
 Hash: 7588 Orig: 1 86 0 A8 1 FE 1 FE 1 FE  
 Hash: 8092 Orig: 1 8F 0 A8 1 FD 1 FE 1 FE  
 Hash: 8074 Orig: 1 8D 0 AA 1 FD 1 FE 1 FE  
 Hash: 8092 Orig: 1 8F 0 A8 1 FE 1 FE 1 FE  
 Hash: 7996 Orig: 1 8A 0 AC 1 FD 1 FE 1 FE  
 Hash: 8146 Orig: 1 8B 0 AE 1 FE 1 FE 1 FE  
 Hash: 7482 Orig: 1 89 0 A2 1 FD 1 FE 1 FE  
Nickles Rejected 
Hash: 7270 Orig: 1 E3 1 5F 1 F5 1 FE 1 FE  
 Hash: 7043 Orig: 1 E3 1 5C 1 F5 1 FE 1 FE  
 Hash: 7012 Orig: 1 E2 1 5C 1 F5 1 FE 1 FE  
 Hash: 7270 Orig: 1 E3 1 5F 1 F5 1 FE 1 FE  
 Hash: 7238 Orig: 1 E2 1 5F 1 F5 1 FE 1 FE  
 Hash: 7043 Orig: 1 E3 1 5C 1 F5 1 FE 1 FE  
 Hash: 6503 Orig: 1 E0 1 56 1 F5 1 FE 1 FE  
 Hash: 7270 Orig: 1 E3 1 5F 1 F7 1 FE 1 FE  
 Hash: 7238 Orig: 1 E2 1 5F 1 F5 1 FE 1 FE  
 Hash: 6769 Orig: 1 E4 1 58 1 F5 1 FE 1 FE

I know that there is 4 settable options on these machines the E which is the amount of coins to accept, the H which is the number of samples, P the number of Pulses and F which is the filter strength,(how often to reject vs accept.)

The Process of Setup for Parameters

  1. Press the "Add" and "minus" buttons at the same time for about three seconds, then the letter "A" will appear from the LED display.
  2. Press the "setup" button once, and the letter "E" will appear. Next, use the buttons to choose how many kinds of coins you would like to use; then press the "setup" button again to finish.
  3. The letter "H" will appear after pressing the button. Use the "Add" and "minus" buttons to choose how many samples you would like to insert later. Next press the "setup" button again to finish.
  4. The letter "P" will appear after pressing the button. Use the "Add" and "minus" buttons to choose the amount of output's signals/pulses you want. The quantity limited is 50 times. Next, press the "setup" button to finish.
  5. The letter "F" will appear after pressing the button. Use the "Add" and "minus" buttons to choose accuracy. The value is from 1~30, and 1 is the most accurate. Normally, 5~10 will be fine.Next, press the "setup" button to finish.
  6. So far, you have successfully set up the first coin. please repeat all above procedures until you have set up all the coins. The letter "A" will appear again after all above procedures are finished.
  7. Press the "setup" button, and the letter "E" will appear. Finally, turn off and turn on the power. The setup will be stored.

this time i set the machine up to accept both dimes and pennies, but still reject nickles. you can see in colum 2 that the information in this column clearly relates to the type of the coin. i do believe that larger heavier coins give steadier and more consistent results. In the second column there is much less variation in the E* values, this leads me to believe that this number is a function of the mass of the coin and its diameter (speculation) because the Pennies and dimes are only 2MM in diameter different and weigh only fractal grams apart from each other. i noticed when i had it apart it has a metal detector, or rather a ferromagnetic pick up coil, if this were sensitive enough the second value could be in relation to the "material makeup" of the coin itself, some illogical calculated value probably from the onboard ADC, which would explain why it varies even when repeatedly using the same coin.

i managed to find a manual that confirms part of my theory in it it states:

CH-926 is mainly based on material, weight and size to identify coins. We use the most up to date algorithm to design software. Therefore, CH-926 is very stable and accurate even when environment changes such as temperature, and humidity etc… In order to increase the accuracy, we suggest different version of coins use different channel to set up.

more information I have found on a similar device, that in form and connections as well as sensor placement is exactly the same as the CH923 that i have, has native access to the serial port includes a serial protocol, if it is an evolved version of the device i have (which as far as Chinese engineering goes is not a far fetched concept) then perhaps it shares some of the same packet information:

1. Normal idle status bytes will report one group data
A1 A2 A3 A4 A5
A1: Header byte 0x98
A2: Mulpitly of setting
A3: Divide of setting
A4: Coin value mount stored inside the EU1
A5: Check sum of the bytes before
2. Coin data receiverd will include three groups data
A1 A2 A3 A4 A5 A6 A7 A8 A9 A10 A11 A12 A13 A14 A15
A1: Header byte: 0x97
A2: Mulpitly of setting
A3: Divide of setting
A4: Coin value accepted
A5: Check sum of the bytes before
A6: Header byte:0x91
A7: Reserved
A8: Pulse width of setting
A9: Reserved
A10: Check sum of the bytes before
A11: Header byte:0x94
A12: Reserved
A13: Pulse width of setting
A14: Coin channel (From BANK A: 1 to 6 and BANK B: 7 to 12)
A15: Check sum of the bytes before
3. Error coin data will include one group data
A1 A2 A3 A4 A5
A1: Header bye: 0x92
A2,A3,A4: Reserved
A5: Check sum of the bytes before
4. Right coin data but coin jammed inside the EU1 will include two groups data
A1 A2 A3 A4 A5 A6 A7 A8 A9 A10
A1: Header bye: 0x93
A2 A3 A4: Reserved
A5: Check sum of the bytes before
A6: Header bye: 0x92
A7 A8 A9: Reserved
A10: Check sum of the bytes before

technically by this documents standards i am getting a packet like condition 4. 10 bytes, however i am basing that on the information from the aforementioned article. however i think that is correct because the data does not have a running offset. i will go check and come back.

definately confirmed to be 10 bytes, i checked it all the way up to 15 after 10 the program ceases to function(as it is designed to do), now i just need to figure out the packet format...

given that i have seen the guts i am pretty sure this is the patent the device stems from... meaning i should be able to put some of these calculations to work to reverse engineer the machine, hopefully :slight_smile:

...on second thought that math wont fit into an arduino, so back to the hard way :slight_smile: although after reading the patent i think i have an idea on what those computed values are.

one of those first 3 columns is the magnetic ratio, symmetry, and the size... how to use that information in an informal way in order to still get useful information remains to be seen.