diff --git a/README.md b/README.md index 51a7d76..02a5ef2 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ jubeat copious - saucer (one new reader (no keypad) + one led board (game won't DDR SN-SN2 (2 old slotted readers) -DDR X-X3 (2 readers (old or new) in sd, 2 readers (old or new) + led board ? in HD) +DDR X-X3 (2 readers (old or new) in sd, 2 readers (old or new) + HDXB button board and RGB speakers lights in HD) drum mania (1 old reader) diff --git a/acrealio/Ddr.cpp b/acrealio/Ddr.cpp index fa82d83..e80f418 100644 --- a/acrealio/Ddr.cpp +++ b/acrealio/Ddr.cpp @@ -7,11 +7,35 @@ Ddr::Ddr() { byte rType[] = {0x04, 0x02, 0x00, 0x00}; byte rVersion[] = {0x01, 0x01, 0x00}; - setVersion(rType, 0x00, rVersion, "HDXS"); + setVersion(rType, 0x00, rVersion, "HDXB"); + + //RGB LEDs + pinMode(LED_DDR_HDXB_P1S_R, OUTPUT); + pinMode(LED_DDR_HDXB_P1S_G, OUTPUT); + pinMode(LED_DDR_HDXB_P1S_B, OUTPUT); + pinMode(LED_DDR_HDXB_P2S_R, OUTPUT); + pinMode(LED_DDR_HDXB_P2S_G, OUTPUT); + pinMode(LED_DDR_HDXB_P2S_B, OUTPUT); + pinMode(LED_DDR_HDXB_P1W_R, OUTPUT); + pinMode(LED_DDR_HDXB_P1W_G, OUTPUT); + pinMode(LED_DDR_HDXB_P1W_B, OUTPUT); + pinMode(LED_DDR_HDXB_P2W_R, OUTPUT); + pinMode(LED_DDR_HDXB_P2W_G, OUTPUT); + pinMode(LED_DDR_HDXB_P2W_B, OUTPUT); + + //Button Lights + pinMode(LT_DDR_HDXB_P1_START, OUTPUT); + pinMode(LT_DDR_HDXB_P1_LR, OUTPUT); + pinMode(LT_DDR_HDXB_P1_UD, OUTPUT); + pinMode(LT_DDR_HDXB_P2_START, OUTPUT); + pinMode(LT_DDR_HDXB_P2_LR, OUTPUT); + pinMode(LT_DDR_HDXB_P2_UD, OUTPUT); } void Ddr::init() { + + } void Ddr::update() @@ -36,21 +60,64 @@ short Ddr::processRequest(byte* request, byte* answer) memcpy(answer+5, getVersion(), 0x2C); break; - // - // init? - case 0x00: - case 0x03: + case 0x10: //ping + answer[4] = 8; + answer[5]=0x45; + answer[6]=0x00; + answer[7]=0xdd; + answer[8]=0x80; //only byte that changes from the write leds code reply.... + answer[9]=0xd4; + answer[10]=0x00; + answer[11]=0xcb; + answer[12]=0x00; + + case 0x12: //write LEDs + //request[5] is always 0, followed by GRB (yes... GRB from what I can tell...) &0x7F + //lets multiply by 2 to get full 8 bit width for full brightness! + analogWrite(LED_DDR_HDXB_P1S_G,((request[6]&0x7F)*2)); + analogWrite(LED_DDR_HDXB_P1S_R,((request[7]&0x7F)*2)); + analogWrite(LED_DDR_HDXB_P1S_B,((request[8]&0x7F)*2)); + analogWrite(LED_DDR_HDXB_P2S_G,((request[9]&0x7F)*2)); + analogWrite(LED_DDR_HDXB_P2S_R,((request[10]&0x7F)*2)); + analogWrite(LED_DDR_HDXB_P2S_B,((request[11]&0x7F)*2)); + analogWrite(LED_DDR_HDXB_P1W_G,((request[12]&0x7F)*2)); + analogWrite(LED_DDR_HDXB_P1W_R,((request[13]&0x7F)*2)); + analogWrite(LED_DDR_HDXB_P1W_B,((request[14]&0x7F)*2)); + analogWrite(LED_DDR_HDXB_P2W_G,((request[15]&0x7F)*2)); + analogWrite(LED_DDR_HDXB_P2W_R,((request[16]&0x7F)*2)); + analogWrite(LED_DDR_HDXB_P2W_B,((request[17]&0x7F)*2)); + + //now lets do the static lights -- take the first 6 bytes and grab the high bit, if its set, then write 1, else 0 + digitalWrite(LT_DDR_HDXB_P1_START,(request[6]&0x80)>0?1:0); + digitalWrite(LT_DDR_HDXB_P1_LR,(request[7]&0x80)>0?1:0); + digitalWrite(LT_DDR_HDXB_P1_UD,(request[8]&0x80)>0?1:0); + digitalWrite(LT_DDR_HDXB_P2_START,(request[9]&0x80)>0?1:0); + digitalWrite(LT_DDR_HDXB_P2_LR,(request[10]&0x80)>0?1:0); + digitalWrite(LT_DDR_HDXB_P2_UD,(request[11]&0x80)>0?1:0); + + answer[4] = 8; + answer[5]=0x45; + answer[6]=0x00; + answer[7]=0xdd; + answer[8]=0x40; + answer[9]=0xd4; + answer[10]=0x00; + answer[11]=0xcb; + answer[12]=0x00; + + break; + + // init commands? + case 0x00: //actually used here + case 0x03: //actually used here case 0x16: case 0x20: + case 0x28: //actually used here case 0x30: answer[4] = 1; answer[5] = 0x00; break; - case 0x10: //unknow - - break; - } diff --git a/acrealio/Node.cpp b/acrealio/Node.cpp index 8856392..62c6430 100644 --- a/acrealio/Node.cpp +++ b/acrealio/Node.cpp @@ -5,17 +5,6 @@ // // Construct node version // -void Node::setVersion(byte* rType, byte rFlag, byte* rVersion, const char* rCode) -{ - char compileDate[0x10] = __DATE__; - char compileTime[0x10] = __TIME__; - memcpy(nodeVersion, rType, 4); - nodeVersion[4] = rFlag; - memcpy(nodeVersion+4+1, rVersion, 3); - memcpy(nodeVersion+8, rCode,4); - memcpy(nodeVersion+8+4, compileDate, 0x10); - memcpy(nodeVersion+8+4+16, compileTime, 0x10); -} // // Return node version diff --git a/acrealio/Node.h b/acrealio/Node.h index 91f34a2..222b24d 100644 --- a/acrealio/Node.h +++ b/acrealio/Node.h @@ -7,18 +7,27 @@ class Node { public: - virtual void init(); - - const char* getVersion(); - void setVersion(byte* rType, byte rFlag, byte* rVersion, const char* rCode); - - virtual short processRequest(byte* request, byte* sendBuff); - virtual void update(); //update things like keypadstate and rfid - - -private: + //making these default empty to save on space if someone wants to go through and kill all those empty implementations + virtual void init(){}; + virtual void update(){}; //update things like keypadstate and rfid + const char* getVersion(); + virtual void setVersion(byte* rType, byte rFlag, byte* rVersion, const char* rCode) + { + char compileDate[0x10] = __DATE__; + char compileTime[0x10] = __TIME__; + memcpy(nodeVersion, rType, 4); + nodeVersion[4] = rFlag; + memcpy(nodeVersion+4+1, rVersion, 3); + memcpy(nodeVersion+8, rCode,4); + memcpy(nodeVersion+8+4, compileDate, 0x10); + memcpy(nodeVersion+8+4+16, compileTime, 0x10); + }; + + virtual short processRequest(byte* request, byte* sendBuff);//everyone should implement this + virtual short processBroadcast(byte* payload, int length, byte* answer){return 0;};// by default a class doesn't need to implement this + char nodeVersion[0x2C]; diff --git a/acrealio/RfidModule.h b/acrealio/RfidModule.h index 8dc0d43..86227a5 100644 --- a/acrealio/RfidModule.h +++ b/acrealio/RfidModule.h @@ -4,6 +4,22 @@ #include "Arduino.h" #include "pinoutconfig.h" +#if RFID_MODULE1==1 + #define RFID_MODULE1_TYPE RR10 +#elif RFID_MODULE1==2 + #define RFID_MODULE1_TYPE SL015M +#else + #define RFID_MODULE1_TYPE RR10 +#endif + +#if RFID_MODULE2==1 + #define RFID_MODULE2_TYPE RR10 +#elif RFID_MODULE2==2 + #define RFID_MODULE2_TYPE SL015M +#else + #define RFID_MODULE2_TYPE RR10 +#endif + class RfidModule { public: diff --git a/acrealio/Sat.cpp b/acrealio/Sat.cpp new file mode 100644 index 0000000..1330103 --- /dev/null +++ b/acrealio/Sat.cpp @@ -0,0 +1,81 @@ +#include "Arduino.h" +#include "Sat.h" + + +//contructor +Sat::Sat() +{ + //special type and version, node name is DDRS for all satellites + byte rType[] = {0x05, 0x01, 0x00, 0x00}; + byte rVersion[] = {0x01, 0x00, 0x02}; + setVersion(rType, 0x00, rVersion, "DDRS"); + + +} + +//needed an overloaded set version here, one version of DDR was VERY particular about having everything perfect +void Sat::setVersion(byte* rType, byte rFlag, byte* rVersion, const char* rCode) +{ + //hard coded date and time + char compileDate[0x10] = {0x41, 0x75, 0x67, 0x20, 0x32, 0x35, 0x20, 0x32, 0x30, 0x30, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00}; + char compileTime[0x10] = {0x31, 0x34, 0x3A, 0x32, 0x38, 0x3A, 0x34, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + memcpy(nodeVersion, rType, 4); + nodeVersion[4] = rFlag; + memcpy(nodeVersion+4+1, rVersion, 3); + memcpy(nodeVersion+8, rCode,4); + memcpy(nodeVersion+8+4, compileDate, 0x10); + memcpy(nodeVersion+8+4+16, compileTime, 0x10); +} + +//every node will get it's individual payload, it should not exceed 40 (0x28) bytes +short Sat::processBroadcast(byte* payload, int length, byte* answer) +{ + answer[0]=0xFE; + answer[1]=0x00; + + // Do something fun here, like maybe spam random lights on this node! + // Someone help decipher the decision forest in the spire MCU please + // There are fancy animations on the spires, its likely an arduino cannot + // address and controll every light individually to perform these animations + // and patterns, as well as brightness control. Each node will probably need + // some sort of MCU on it's own communicated to from here to perform an animation + // In otherwords, get ready for lots of software serials and a whole OTHER device + // to build on top of this + + return 2; // the length of the answer we provide + +} + +//not a lot of these, most of this is just responding to +short Sat::processRequest(byte* request, byte* answer) +{ + answer[0] = request[0] | 0x80; // reader id + answer[1] = request[1]; // ? + answer[2] = request[2]; // command + answer[3] = request[3]; // paquet id + answer[4] = 0; // data length + + switch (answer[2]) // switch on the command + { + // + // get version + case 0x02: + answer[4] = 0x2C; + memcpy(answer+5, getVersion(), 0x2C); + break; + + + // init commands? + default: + answer[4] = 1; + answer[5] = 0x00; + break; + + + + } + + + +} + diff --git a/acrealio/Sat.h b/acrealio/Sat.h new file mode 100644 index 0000000..8b3cc19 --- /dev/null +++ b/acrealio/Sat.h @@ -0,0 +1,15 @@ +#include "Arduino.h" +#include "Node.h" + +class Sat: public Node +{ +public: + Sat(); //contructor + short processRequest(byte* request, byte* sendBuff); + short processBroadcast(byte* payload, int length, byte* answer); + void setVersion(byte* rType, byte rFlag, byte* rVersion, const char* rCode); +private: + + +}; + diff --git a/acrealio/acrealio.ino b/acrealio/acrealio.ino index 48cb325..e957ff2 100644 --- a/acrealio/acrealio.ino +++ b/acrealio/acrealio.ino @@ -6,11 +6,15 @@ #include "RR10.h" #include "SL015M.h" #include "Ddr.h" +#include "Sat.h" #define MINTIME 14 // Min time between 2 sent packet(Min is 14ms, Max is around 50ms) some games require this -#define MAX_NODES 3 +#define MAX_NODES 7 + + + /////////////////////////// // Serial protocol with host @@ -61,35 +65,30 @@ LedBoard nod2("LEDB");//led board Reader nod1;//first reader IoBoard nod2("KFCA");//io board -#else //2 readers + DDR LED board ? +#elif GAMETYPE == 5 // 2 readers + DDR HDBX button board with Speaker RGB LEDs Reader nod1;//first reader Reader nod2;//second reader -Ddr nod3; -//LedBoard nod3("LEDB");//led board +Ddr nod3; //HDXB board + +#elif GAMETYPE == 6 // satellites + +Sat monitor_satellite, left_inner_satellite, left_middle_satellite, left_outer_satellite, right_inner_satellite, right_middle_satellite, right_outer_satellite; //satellites #endif //1P rfid module allocation +RFID_MODULE1_TYPE mod1; -#if RFID_MODULE1 == 1 -SL015M mod1; -#else -RR10 mod1; -#endif //2P rfid module allocation #if GAMETYPE == 2 || GAMETYPE == 5 -#if RFID_MODULE2 == 1 -SL015M mod2; -#else -RR10 mod2; -#endif + RFID_MODULE2_TYPE mod2; #endif @@ -103,8 +102,10 @@ void setup() // set nodes configuration //set first rfid module +#if GAMETYPE !=6 mod1.setPins(R1_DET,&R1_SER); nod1.setRfidModule(&mod1); +#endif #if GAMETYPE == 0 //pop'n music with card dispenser @@ -159,7 +160,8 @@ void setup() nbnodes = 2; -#else // 2readers + DDR ??? board + +#elif GAMETYPE==5 // 2readers + DDR HDBX button board with Speaker RGB LEDs //1p reader nod1.setrCode("ICCB",0); @@ -178,7 +180,17 @@ void setup() nodes[2] = &nod3; nbnodes = 3; - + +#elif GAMETYPE == 6 // ddr satellites + nodes[0] = &monitor_satellite; + nodes[1] = &left_inner_satellite; + nodes[2] = &left_middle_satellite; + nodes[3] = &left_outer_satellite; + nodes[4] = &right_inner_satellite; + nodes[5] = &right_middle_satellite; + nodes[6] = &right_outer_satellite; + + nbnodes = 7; #endif @@ -193,12 +205,8 @@ void setup() void loop() { if (initDone) { - for (int r=0;rupdate();//update each node - } - if ((millis() - lastRecv) > 50000) { // If no comm for 50sec, timeout + if ((millis() - lastRecv) > 500000) { // If no comm for 500sec, timeout initDone = false; // Reset init //digitalWrite(13, LOW); Serial.end(); // and close serial port @@ -236,10 +244,20 @@ void serialEvent() { nodeEnum(); else { - if (request[0] >= node_id && request[0] < node_id+nbnodes)//command recipient is one of our nodes - processRequest(); - else //if it's not for us, (cmd aimed at another node or at the host) send it to next node - forwardRequest(); + if (request[0] >= 0x10 && request[0] < 0x80 ) //if our destination is a broadcast + { + processBroadcast(); + } + else + { + if (request[0] >= node_id && request[0] < node_id+nbnodes)//command recipient is one of our nodes + { + processRequest(); + } + else //if it's not for us, (cmd aimed at another node or at the host) send it to next node + { forwardRequest(); + } + } } req_i = 0; //empty request buffer @@ -319,11 +337,22 @@ void getRequest() // boolean isRequestComplete() { + if (req_i >= 6) // check if at least minimum size { - if (req_i >= 6+ request[4]) // if long enough, including data length + if (request[0]>=0x10 && request[0]<0x80) //broadcast style + { + if (req_i >= 3+ request[1]) // if long enough, including data length + { + return true; + } + } + else //request style { - return true; + if (req_i >= 6+ request[4]) // if long enough, including data length + { + return true; + } } } return false; @@ -335,8 +364,16 @@ boolean isRequestComplete() boolean checkRequestChecksum() { byte sum = 0; + + //request style int bufsize = 6 + request[4]; + //broadcast checksum length override if it is a broadcast + if (request[0]>=0x10 && request[0]<0x80) + { + bufsize= 3+ request[1]; + } + for (int i=0;iprocessRequest(request, answer);//have it process the request + if (answer[0]!=0) sendAnswer(answer); //hack because DDR spires have commands in which it does NOT respond to during an ACIO broadcast + +} + +void processBroadcast() { + byte answer[256]; // broadcast answer buffer + answer[0]=request[0]; // standard affair for an answer + int nodes_in_broadcast = request[0]>>4; // shift the high nibble of the node address right to get an integer of how many nodes are in the broadcast + answer[1]=2*nodes_in_broadcast; // this is the length; AFAIK, every broadcast node returns FE 00, so 2 bytes times the number of nodes is our payload length + int answer_size=2; // so far we defined 2 bytes in our answer + int device_packet_size= (request[1]/nodes_in_broadcast); // a broadcast supposedly has a fixed size payload across every node? Divide the length of the payload by number of nodes to get the length of a nodes payload + //byte individual_device_broadcast_buffer[40]; + for (int i=0;iprocessBroadcast(individual_device_broadcast_buffer,device_packet_size,answer+answer_size); + + //use the magic of pointers to avoid needless allocation and copy! + answer_size+=nodes[i]->processBroadcast(request+2+(i*device_packet_size),device_packet_size,answer+answer_size); + } sendAnswer(answer); } @@ -374,6 +431,10 @@ void sendAnswer(byte* answer) // checksum calculation byte sum = 0; int bufsize = 6 + answer[4]; + if (request[0]>=0x10 && request[0]<0x80) + { + bufsize= 3+ answer[1]; + } for (int i=0;i=0x10 && request[0]<0x80)) + { + Serial.write(0xAA); + } + */ Serial.write(0xAA); diff --git a/acrealio/pinoutconfig.h b/acrealio/pinoutconfig.h index b9829da..2ef15a6 100644 --- a/acrealio/pinoutconfig.h +++ b/acrealio/pinoutconfig.h @@ -1,7 +1,13 @@ #ifndef CONFIG_H #define CONFIG_H -#define GAMETYPE 1 //0:pop'n with card dispenser 1: pop'n, drummania(1 reader) 2:iidx/ddr sd/gf(2readers) 3:jubeat (1reader+Ledboard) 4: sdvx (1reader+ioboard) 5: ddr hd (2readers + ??? board) +#define GAMETYPE 6 //0: pop'n with card dispenser + //1: pop'n, drummania(1 reader) + //2: iidx/ddr sd/gf(2readers) + //3: jubeat (1reader+Ledboard) + //4: sdvx (1reader+ioboard) + //5: ddr hd (2readers + HDXB button board with speaker RGB lights) + //6: satellites #define RFID_BAUD 115200 //Baud rate for RFID Module @@ -50,6 +56,33 @@ #define LED3_G 12 #define LED3_B 11 +//pins for ddr HDXB RGB LEDs (use PWM pins) and button lights +#define LED_DDR_HDXB_P1S_R 4 +#define LED_DDR_HDXB_P1S_G 3 +#define LED_DDR_HDXB_P1S_B 2 + +#define LED_DDR_HDXB_P2S_R 7 +#define LED_DDR_HDXB_P2S_G 6 +#define LED_DDR_HDXB_P2S_B 5 + +#define LED_DDR_HDXB_P1W_R 10 +#define LED_DDR_HDXB_P1W_G 9 +#define LED_DDR_HDXB_P1W_B 8 + +#define LED_DDR_HDXB_P2W_R 13 +#define LED_DDR_HDXB_P2W_G 12 +#define LED_DDR_HDXB_P2W_B 11 + + +#define LT_DDR_HDXB_P1_START 41 +#define LT_DDR_HDXB_P1_LR 43 +#define LT_DDR_HDXB_P1_UD 45 + +#define LT_DDR_HDXB_P2_START 47 +#define LT_DDR_HDXB_P2_LR 49 +#define LT_DDR_HDXB_P2_UD 51 + + @@ -78,9 +111,16 @@ COL C COL B COL A #define K1_4 35 -//pins for card reader 1 RFID Module -#define R1_DET 20 -#define R1_SER Serial1 +//if not something that can run on an uno (like satellites) +#if GAMETYPE<6 + //pins for card reader 1 RFID Module + #define R1_DET 20 + #define R1_SER Serial1 + + //pins for card reader 2 RFID Module + #define R2_DET 21 + #define R2_SER Serial2 +#endif //pins for card reader 2 keypad (colls ABC, rows 1234) #define K2_A 26 @@ -91,10 +131,5 @@ COL C COL B COL A #define K2_3 32 #define K2_4 34 - -//pins for card reader 2 RFID Module -#define R2_DET 21 -#define R2_SER Serial2 - #endif