Andriy Makukha
/
football_project_wo_output
football_project_wo_output
Fork of football_project by
main.cpp
- Committer:
- andriym
- Date:
- 2016-06-16
- Revision:
- 95:3cc3ae2e5e7f
- Parent:
- 94:831a7fc2d69a
- Child:
- 97:2894fbc2d4f8
File content as of revision 95:3cc3ae2e5e7f:
#include <RFM69.h> #include <list> #include <DebounceIn.h> #ifdef BLE_ENABLE #include "ble/BLE.h" #include "ble/services/DFUService.h" #endif using namespace std; Timer tmr; //Output out; #ifdef BLE_ENABLE BLEDevice ble; // Optional: Device Name, add for human read-ability //const static char DEVICE_NAME[] = "PassiveCoach"; // You have up to 26 bytes of advertising data to use. //const static uint8_t AdvData[] = {0x01,0x02,0x03,0x04,0x05}; /* Example of hex data */ //const static uint8_t AdvData[] = {"Keep the Space!"}; /* Example of character data */ #endif // BLE_ENABLE /////////////////////////////////// PINS /////////////////////////////////// DebounceIn buttonTeam(BUT_TEAM); DebounceIn buttonSpace(BUT_SPACE); DebounceIn buttonVolMore(BUT_VOL_MORE); DebounceIn buttonVolLess(BUT_VOL_LESS); DigitalOut ledTeamA(LED_TEAM_A); DigitalOut ledTeamB(LED_TEAM_B); DigitalOut ledSpace5(LED_SPACE5); DigitalOut ledSpace10(LED_SPACE10); DigitalOut ledSpace15(LED_SPACE15); DigitalOut ledSpace20(LED_SPACE20); DigitalOut ledBuzzer(LED_BUZZER_ON); AnalogIn ain(ANALOG_IN); // used for randomizing #ifdef NORDIC DigitalOut buzzer(BUZZER); #ifndef HARD_V2 DigitalOut buzzLow(BUZZ_LOW); #endif DigitalOut buzzMed(BUZZ_MED); DigitalOut buzzHigh(BUZZ_HIGH); #else PwmOut speaker(BUZZER); // passive buzzer #endif /////////////////////////////////// RADIO /////////////////////////////////// #ifdef ENABLE_PIN static RFM69 radio(RFM_MOSI, RFM_MISO, RFM_SCK, RFM_SS, RFM_IRQ, RFM_ISM_EN); #else static RFM69 radio(RFM_MOSI, RFM_MISO, RFM_SCK, RFM_SS, RFM_IRQ); #endif static bool promiscuousMode = true; // set 'true' to sniff all packets on the same network /////////////////////////////////// FUNCTIONS /////////////////////////////////// void beep(float period, float time, uint8_t vol) { #ifdef ENABLE_SOUND if(!vol) return; #ifdef NORDIC if(vol>=3) { #ifndef HARD_V2 buzzLow = LOW_ON; #endif buzzMed = MED_OFF; buzzHigh = HIGH_OFF; } else if(vol>=2) { #ifndef HARD_V2 buzzLow = LOW_OFF; #endif buzzMed = MED_ON; buzzHigh = HIGH_OFF; } else { #ifndef HARD_V2 buzzLow = LOW_OFF; #endif buzzMed = MED_OFF; buzzHigh = HIGH_ON; } buzzer = 0; // P-MOSFET wait(time); buzzer = 1; #else speaker.period(period); if(vol>=3) speaker = 0.5; //50% duty cycle - max volume else if(vol>=2) speaker = 0.33; else speaker = 0.2; wait(time); speaker=0.0; // turn off audio #endif #endif } void binary_sound(int z) { // Beeps numbers according to their binary form // (used for debugging in display-less and serial-less environments) #ifdef ENABLE_SOUND #ifndef NORDIC speaker.period(0.004); while(z) { speaker = 0.5; if(z&1) wait(0.5); else wait(0.25); speaker = 0.0; wait(1.0); z >>= 1; } beep(NOTE_A4, 1.0, 2); #endif #endif } void generate_name(char rand_name[], uint8_t size) { // Generate random name on the 62 character alphabet memset(rand_name, 0x00, size); char alph[63] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; uint32_t seed = ((ain.read_u16()+3)/17)*(radio.readTemperature(-1)+37)*((ain.read_u16()+5)/13); srand(seed); for(int i=0;i<size-1;i++) { rand_name[i] = alph[abs(rand()) % 62]; } } void spaceLEDs(int level) { if(level<=0) { ledSpace5 = 1; ledSpace10 = 0; ledSpace15 = 0; ledSpace20 = 0; } else if(level<=1) { ledSpace5 = 0; ledSpace10 = 1; ledSpace15 = 0; ledSpace20 = 0; } else if(level<=2) { ledSpace5 = 0; ledSpace10 = 0; ledSpace15 = 1; ledSpace20 = 0; } else { ledSpace5 = 0; ledSpace10 = 0; ledSpace15 = 0; ledSpace20 = 1; } } #ifdef BLE_ENABLE void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) { //pc.printf("Disconnected \r\n"); //pc.printf("Restart advertising \r\n"); ble.startAdvertising(); } // Optional: Restart advertising when peer disconnects /* void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) { BLE::Instance().gap().startAdvertising(); } */ // This function is called when the ble initialization process has failed void onBleInitError(BLE &ble, ble_error_t error) { // Avoid compiler warnings (void) ble; (void) error; // Initialization error handling should go here } // Callback triggered when the ble initialization process has finished /* void bleInitComplete(BLE::InitializationCompleteCallbackContext *params) { BLE& ble = params->ble; ble_error_t error = params->error; if (error != BLE_ERROR_NONE) { // In case of error, forward the error handling to onBleInitError onBleInitError(ble, error); return; } // Ensure that it is the default instance of BLE if(ble.getInstanceID() != BLE::DEFAULT_INSTANCE) { return; } // Set device name characteristic data ble.gap().setDeviceName((const uint8_t *) DEVICE_NAME); // Optional: add callback for disconnection ble.gap().onDisconnection(disconnectionCallback); // Sacrifice 3B of 31B to Advertising Flags ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE ); ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); // Sacrifice 2B of 31B to AdvType overhead, rest goes to AdvData array you define ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::MANUFACTURER_SPECIFIC_DATA, AdvData, sizeof(AdvData)); // Optional: Add name to device ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); // Set advertising interval. Longer interval == longer battery life ble.gap().setAdvertisingInterval(100); // 100ms // Start advertising ble.gap().startAdvertising(); } */ #endif // BLE_ENABLE /////////////////////////////////// CLASSES /////////////////////////////////// struct Contact { int16_t rssi; uint32_t time_ms; }; class Player { public: char name[NAME_LEN+1]; int8_t team; Player(const char rand_name[]) { memset(name, 0x00, NAME_LEN+1); memcpy(name, rand_name, NAME_LEN); } void update(int8_t _team, int rssi, uint32_t time=NULL) { // Remember this contact team = _team; Contact c; c.rssi = rssi; c.time_ms = (time!=NULL) ? time : tmr.read_ms(); contacts.push_front(c); // Cleanup while(contacts.size() > MAX_RECORDS) contacts.pop_back(); while(!contacts.empty() && c.time_ms - contacts.back().time_ms > MAX_HISTORY_MS) contacts.pop_back(); } int16_t get_distance(int &cnt) { // Find max RSSI uint32_t cur_time = tmr.read_ms(); int16_t max_rssi=-128; cnt=0; for (list<Contact>::iterator it=contacts.begin(); it != contacts.end(); ++it) { if(cur_time - it->time_ms > SIGNALS_VALID_MS) break; if(it->rssi > max_rssi) max_rssi = it->rssi; cnt++; } return max_rssi; } inline bool operator==(const char rhs[]){ return memcmp(name, rhs, NAME_LEN)==0; } inline bool operator==(const Player& rhs){ return *this==rhs.name; } //inline bool operator!=(const char rhs[]){ return !(*this == rhs); } private: list<Contact> contacts; }; class Players { public: list<Player> players; void update(const char name[], int8_t team, int16_t rssi, uint32_t time_ms=NULL) { list<Player>::iterator it; for (it=players.begin(); it != players.end(); ++it) { if(*it==name) break; } if(it!=players.end()) { it->update(team, rssi, time_ms); } else { Player p(name); p.update(team, rssi, time_ms); players.push_front(p); } } void showAll(int8_t team, uint8_t level, uint8_t volume) { // Output the current state to the user: // - show the current information table and/or // - beep if the user is too close to another one int i=0, nContacts, signal, maxTeamSignal = -128; list<Player>::iterator it; //out.clear(); for (it=players.begin(); it != players.end(); ++it) { signal = it->get_distance(nContacts); if(signal>-128) { /* out.printf("%d ", ++i); out.printf((team==it->team) ? "+" : "-"); // teammate or opponent? out.printf("%s ", it->name); out.printf("%d/%d", -signal, nContacts); out.printf((-signal<SPACE[level]) ? "!" : " "); out.printf("\r\n"); */ } if(team==it->team && signal>maxTeamSignal) { maxTeamSignal = signal; } } //if(!i) { // out.printf("Nobody around\r\n"); // beep(NOTE_A5,0.5,volume); //} if(-maxTeamSignal<SPACE[level]) { beep(NOTE_A4, 0.33, volume); } } }; /////////////////////////////////// MAIN CODE /////////////////////////////////// int main() { #ifdef BLE_ENABLE // BLE initialization ble.init(); ble.onDisconnection(disconnectionCallback); #endif // BLE_ENABLE char tx_buff[100] = {0}; char rx_buff[100] = {0}; char rand_name[NAME_LEN+1] = {0}; char other_name[NAME_LEN+1] = {0}; int8_t myTeam = 1, otherTeam; uint8_t level = 1, volume = 1; // SPACE10, VOL_LOW int bTeamNew, bTeamOld, bSpaceOld, bSpaceNew, bVMNew, bVLNew, bVMOld, bVLOld; // Blink all the LEDs at startup spaceLEDs(0); wait(0.2); spaceLEDs(1); wait(0.2); spaceLEDs(2); wait(0.2); spaceLEDs(3); wait(0.2); ledSpace20 = 0; #ifdef TEST_LED_SOUND // Test LEDs and sound simultaneously to save time buzzMed = MED_OFF; buzzHigh = HIGH_OFF; ledBuzzer = 1; buzzer=0; wait(0.2); buzzer=1; ledBuzzer = 0; buzzMed = MED_ON; ledTeamA = 1; buzzer=0; wait(0.2); buzzer=1; ledTeamA = 0; buzzMed = MED_OFF; buzzHigh = HIGH_ON; ledTeamB = 1; buzzer=0; wait(0.2); buzzer=1; ledTeamB = 0; buzzHigh = HIGH_OFF; #else ledBuzzer = 1; wait(0.2); ledBuzzer = 0; ledTeamA = 1; wait(0.2); ledTeamA = 0; ledTeamB = 1; wait(0.2); ledTeamB = 0; // Beep all the levels on startup beep(NOTE_A5, 0.2, 1); beep(NOTE_A5, 0.2, 2); beep(NOTE_A5, 0.2, 3); #endif // ...and go to a informative LEDs spaceLEDs(level); ledBuzzer = volume ? 1 : 0; if(myTeam & 1) ledTeamA = 1; else ledTeamB = 1; // Buttons initialization buttonSpace.mode(PullDown); buttonVolMore.mode(PullDown); buttonVolLess.mode(PullDown); #ifdef NORDIC buttonTeam.mode(PullDown); bTeamOld = 0; #else buttonTeam.mode(PullUp); bTeamOld = 1; #endif bSpaceOld = 0; bVMOld = 0; bVLOld = 0; #ifdef BLE_ENABLE // setup advertising ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED); ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); ble.accumulateAdvertisingPayload(GapAdvertisingData::SHORTENED_LOCAL_NAME, (const uint8_t *)"KeepTheSpace", sizeof("KeepTheSpace") - 1); //ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS, // (const uint8_t *)uart_base_uuid_rev, sizeof(uart_base_uuid)); // 100ms; in multiples of 0.625ms. ble.setAdvertisingInterval(160); //ble.addService(uartService); DFUService dfu(ble); ble.startAdvertising(); //pc.printf("Advertising Start \r\n"); /* // GAP version BLE& ble = BLE::Instance(BLE::DEFAULT_INSTANCE); ble.init(bleInitComplete); // Initialize BLE baselayer DFUService dfu( ble ); */ #endif // BLE_ENABLE // Pick node number char this_node = int(ain.read()*255+17)*int(ain.read()*255+11); // random node value //out.printf("Node: %d\r\n", this_node); // Initialize the radio radio.initialize(FREQUENCY, this_node, NETWORKID); #ifdef HIGH_POWER radio.setHighPower(true); #endif radio.encrypt(0); radio.promiscuous(promiscuousMode); if(FREQUENCY == RF69_868MHZ) radio.setFrequency(868000000); else if(FREQUENCY == RF69_915MHZ) radio.setFrequency(915000000); // Pick node name generate_name(rand_name, sizeof(rand_name)); /* out.printf("Name: %s\r\n", rand_name); out.sleep(2.0); */ tmr.start(); Players players; uint32_t last_send = tmr.read_ms(); uint32_t last_shown = tmr.read_ms(); //uint32_t min_wait = SEND_RATE_MS - 0.5*SEND_RATE_MS*SEND_DESYNC; //uint32_t send_wait = min_wait; while (true) { // Read team button bTeamNew = buttonTeam; if(bTeamNew==PRESSED && bTeamOld==RELEASED) { myTeam = (myTeam==1) ? 2 : 1; ledTeamA = myTeam & 1; ledTeamB = ~myTeam & 1; /* out.clear(); out.printf("New team: %d\r\n", myTeam); out.sleep(2); */ } bTeamOld = bTeamNew; // Read space button bSpaceNew = buttonSpace; if(bSpaceNew && !bSpaceOld) { level = (level+1) & 0b11; // four states spaceLEDs(level); /* out.clear(); out.printf("New level: %d\r\n", level); out.sleep(2); */ } bSpaceOld = bSpaceNew; // Read volume buttons bVMNew = buttonVolMore.read(); bVLNew = buttonVolLess.read(); if(bVMNew && !bVMOld) { volume++; if(volume>3) volume=3; ledBuzzer = 1; /* out.clear(); out.printf("New volume: %d\r\n", volume); out.sleep(2); */ } if(bVLNew && !bVLOld) { if(volume>0) volume--; if(!volume) ledBuzzer = 0; /* out.clear(); out.printf("New volume: %d\r\n", volume); out.sleep(2); */ } bVMOld = bVMNew; bVLOld = bVLNew; // Output unsigned long current_time = tmr.read_ms(); if (current_time - last_shown > CYCLE_MS) { players.showAll(myTeam, level, volume); last_shown = current_time; } // Radios if (current_time - last_send > SEND_RATE_MS) { // Send message snprintf(tx_buff, sizeof(tx_buff), "N=%s,%d", rand_name, myTeam); radio.send(EVERY_NODE, tx_buff, strlen(tx_buff)); last_send = current_time; //send_wait = min_wait + (rand() % SEND_RATE_MS)*SEND_DESYNC; //// Some debugging info I used to display //out.clear(); //out.printf("Sent: %s\r\n", tx_buff); //uint8_t tempC = radio.readTemperature(-1); // -1 = user cal factor, adjust for correct ambient //uint8_t gain = (radio.readReg(REG_LNA) & 0b111000)>>3; // LNA Current Gain //uint32_t freq = radio.getFrequency(); //out.printf("T: %d, G: %d\r\n", tempC, gain); //if(freq!=868000000) out.printf("Freq: %d\r\n", freq); //beep(NOTE_A3, 0.05, volume); } if (radio.receiveDone()) { memset(rx_buff, 0x00, sizeof(rx_buff)); memcpy(rx_buff, (char*)radio.DATA, radio.DATALEN > sizeof(rx_buff)-1 ? sizeof(rx_buff)-1 : radio.DATALEN); if(rx_buff[0]=='N' && rx_buff[1]=='=') { memcpy(other_name, rx_buff+2, NAME_LEN); other_name[5] = 0x00; if(sizeof(rx_buff)>8 && rx_buff[7]==',') { otherTeam = rx_buff[8]-'0'; } else otherTeam = 1; players.update(other_name, otherTeam, radio.RSSI, tmr.read_ms()); //uint8_t gain = (radio.readReg(REG_LNA) & 0b111000)>>3; // LNA Current Gain //out.clear(); //out.printf("Other: %s\r\n", other_name); //out.printf("RSSI: %d, G: %d\r\n", radio.RSSI, gain); //beep(NOTE_A5, 0.5, volume); } else { // received unknown signal uint8_t gain = (radio.readReg(REG_LNA) & 0b111000)>>3; // LNA Current Gain /* out.clear(); out.printf("Got: %s\r\n", rx_buff); out.printf("RSSI: %d, G: %d\r\n", radio.RSSI, gain); out.sleep(2.0); */ } } #ifdef BLE_ENABLE // ble.waitForEvent(); #endif // BLE_ENABLE } }