259 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			259 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "controller.h"
 | |
| #include "spi_master.h"
 | |
| #include "config.h"
 | |
| 
 | |
| Controller::Controller(Player* p, SPIMaster* s) {
 | |
| 	_player = p;
 | |
| 	_spi = s;
 | |
| 	_rfid = new MFRC522(17, MFRC522::UNUSED_PIN);
 | |
| 
 | |
| 	BTN_NEXT_SETUP();
 | |
| 	BTN_PREV_SETUP();
 | |
| 	BTN_VOL_UP_SETUP();
 | |
| 	BTN_VOL_DOWN_SETUP();
 | |
| 
 | |
| 	_spi->select_rc522();
 | |
| 	DEBUG("Initializing RC522...\n");
 | |
| 	_rfid->PCD_Init();
 | |
| 	#ifdef SHOW_DEBUG
 | |
| 		_rfid->PCD_DumpVersionToSerial();
 | |
| 	#endif
 | |
| 	_spi->select_rc522(false);
 | |
| 	INFO("RC522 initialized.\n");
 | |
| 
 | |
| 	for (uint8_t i=0; i<NUM_BUTTONS; i++) _button_last_pressed_at[i]=0;
 | |
| }
 | |
| 
 | |
| void Controller::set_mqtt_client(MQTTClient* m) {
 | |
| 	_mqtt_client = m;
 | |
| }
 | |
| 
 | |
| void Controller::loop() {
 | |
| 	unsigned long now = millis();
 | |
| 	if ((_last_rfid_scan_at < now - RFID_SCAN_INTERVAL) || (now < _last_rfid_scan_at)) {
 | |
| 		_check_rfid();
 | |
| 		_last_rfid_scan_at = now;
 | |
| 	}
 | |
| 	_check_serial();
 | |
| 	_check_buttons();
 | |
| 
 | |
| 	if ((_last_mqtt_report_at < now - MQTT_REPORT_INTERVAL) || (now < _last_mqtt_report_at)) {
 | |
| 		_send_mqtt_report();
 | |
| 		_last_mqtt_report_at = now;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| uint32_t Controller::_get_rfid_card_uid() {
 | |
| 	_spi->select_rc522();
 | |
| 	if (!_rfid->PICC_ReadCardSerial()) {
 | |
| 		if (!_rfid->PICC_IsNewCardPresent()) {
 | |
| 			return 0;
 | |
| 		}
 | |
| 		if (!_rfid->PICC_ReadCardSerial()) {
 | |
| 			return 0;
 | |
| 		}
 | |
| 	}
 | |
| 	_spi->select_rc522(false);
 | |
| 	uint32_t uid = _rfid->uid.uidByte[0]<<24 | _rfid->uid.uidByte[1]<<16 | _rfid->uid.uidByte[2]<<8 | _rfid->uid.uidByte[3];
 | |
| 	return uid;
 | |
| }
 | |
| 
 | |
| void Controller::_check_rfid() {
 | |
| 	uint32_t uid = _get_rfid_card_uid();
 | |
| 	if (uid != _last_rfid_card_uid) {
 | |
| 		if (uid > 0) {
 | |
| 			_mqtt_client->publish_rfid_uid(uid);
 | |
| 			_no_rfid_card_count = 0;
 | |
| 			String temp = String(uid, HEX);
 | |
| 			String s_uid = "";
 | |
| 			for (int i=0; i<(8-temp.length()); i++) {
 | |
| 				s_uid.concat("0");
 | |
| 			}
 | |
| 			s_uid.concat(temp);
 | |
| 			INFO("New RFID card uid: %s\n", s_uid.c_str());
 | |
| 			_player->play_id(s_uid);
 | |
| 			
 | |
| 			
 | |
| 			DEBUG("Trying to read RFID data...");
 | |
| 			_spi->select_rc522();
 | |
| 			String data = "";
 | |
| 			MFRC522::MIFARE_Key key;
 | |
| 			for (int i=0; i<6; i++) key.keyByte[i]=0xFF;
 | |
| 			MFRC522::PICC_Type type = _rfid->PICC_GetType(_rfid->uid.sak);
 | |
| 			MFRC522::StatusCode status;
 | |
| 			uint8_t sectors = 0;
 | |
| 			switch(type) {
 | |
| 				case MFRC522::PICC_TYPE_MIFARE_MINI: sectors = 5; break;
 | |
| 				case MFRC522::PICC_TYPE_MIFARE_1K: sectors = 16; break;
 | |
| 				case MFRC522::PICC_TYPE_MIFARE_4K: sectors = 40; break;
 | |
| 				default: INFO("Unknown PICC type %s\n", String(MFRC522::PICC_GetTypeName(type)).c_str());
 | |
| 			}
 | |
| 			
 | |
| 			for (uint8_t sector=0; sector<sectors; sector++) {
 | |
| 				uint8_t blocks = (sector < 32) ? 4 : 16;
 | |
| 				uint8_t block_offset = (sector < 32) ? sector * 4 : 128 + (sector - 32) * 16;
 | |
| 				
 | |
| 				status = _rfid->PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, block_offset, &key, &_rfid->uid);
 | |
| 				if (status != MFRC522::STATUS_OK) {
 | |
| 					DEBUG("PCD_Authenticate() failed: %s\n", String(_rfid->GetStatusCodeName(status)).c_str());
 | |
| 					continue;
 | |
| 				}
 | |
| 				
 | |
| 				for (uint8_t block=0; block<blocks-1; block++) {
 | |
| 					byte buffer[16];
 | |
| 					uint8_t byte_count = 16;
 | |
| 					status = _rfid->MIFARE_Read(block_offset + block, buffer, &byte_count);
 | |
| 					if (status != MFRC522::STATUS_OK) {
 | |
| 						DEBUG("MIFARE_Read() failed: %s\n", String(_rfid->GetStatusCodeName(status)).c_str());
 | |
| 						continue;
 | |
| 					}
 | |
| 					for (int i=0; i<16; i++) {
 | |
| 						if (buffer[i]!=0x00) data.concat(buffer[i]);
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 			
 | |
| 			_rfid->PICC_HaltA();
 | |
| 			_rfid->PCD_StopCrypto1();
 | |
| 			_spi->select_rc522(false);
 | |
| 			
 | |
| 			DEBUG("Data from RFID: %s", data.c_str());
 | |
| 			
 | |
| 		} else {
 | |
| 			if (_no_rfid_card_count >= 1) {
 | |
| 				INFO("No more RFID card.\n");
 | |
| 				_player->stop();
 | |
| 			} else {
 | |
| 				_no_rfid_card_count++;
 | |
| 				return;
 | |
| 			}
 | |
| 		}
 | |
| 		_last_rfid_card_uid = uid;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void Controller::_check_serial() {
 | |
| 	if (Serial.available() > 0) {
 | |
| 		char c = Serial.read();
 | |
| 		Serial.printf("%c", c);
 | |
| 		if (c==10 || c==13) {
 | |
| 			if (_serial_buffer.length()>0) {
 | |
| 				_execute_serial_command(_serial_buffer);
 | |
| 				_serial_buffer = String();
 | |
| 			}
 | |
| 		} else {
 | |
| 			_serial_buffer.concat(c);
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void Controller::_execute_serial_command(String cmd) {
 | |
| 	DEBUG("Executing command: %s\n", cmd.c_str());
 | |
| 
 | |
| 	if (cmd.equals("ls")) {
 | |
| 		_execute_command_ls("/");
 | |
| 	} else if (cmd.startsWith("ls ")) {
 | |
| 		_execute_command_ls(cmd.substring(3));
 | |
| 	} else if (cmd.equals("play")) {
 | |
| 		_player->play_random_album();
 | |
| 	} else if (cmd.startsWith("play ")) {
 | |
| 		_player->play_id(cmd.substring(5));
 | |
| 	} else if (cmd.startsWith("sys ")) {
 | |
| 		_player->play_system_sound(cmd.substring(4));
 | |
| 	} else if (cmd.equals("stop")) {
 | |
| 		_player->stop();
 | |
| 	} else if (cmd.equals("help")) {
 | |
| 		_execute_command_help();
 | |
| 	} else if (cmd.equals("-")) {
 | |
| 		_player->vol_down();
 | |
| 	} else if (cmd.equals("+")) {
 | |
| 		_player->vol_up();
 | |
| 	} else if (cmd.equals("p")) {
 | |
| 		_player->track_prev();
 | |
| 	} else if (cmd.equals("n")) {
 | |
| 		_player->track_next();
 | |
| 	} else if (cmd.equals("ids")) {
 | |
| 		_execute_command_ids();
 | |
| 	} else {
 | |
| 		ERROR("Unknown command: %s\n", cmd.c_str());
 | |
| 	}
 | |
| 	return;
 | |
| }
 | |
| 
 | |
| void Controller::_execute_command_ls(String path) {
 | |
| 	INFO("Listing contents of %s:\n", path.c_str());
 | |
| 	std::list<String> files = _player->ls(path);
 | |
| 	for(std::list<String>::iterator it=files.begin(); it!=files.end(); ++it) {
 | |
| 		INFO("  %s\n", (*it).c_str());
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void Controller::_execute_command_ids() {
 | |
| 	for (std::map<String, String>::iterator it = _player->id_to_folder_map.begin(); it!=_player->id_to_folder_map.end(); ++it) {
 | |
| 		INFO("  %s -> %s\n", it->first.c_str(), it->second.c_str());
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void Controller::_execute_command_help() {
 | |
| 	INFO("Valid commands are:");
 | |
| 	INFO("  help      - Displays this help\n");
 | |
| 	INFO("  ls [dir]  - Lists the contents of [dir] or, if not given, of /\n");
 | |
| 	INFO("  ids       - Lists all known ID-to-folder mappings\n");
 | |
| 	INFO("  play [id] - Plays the album with the given id\n");
 | |
| 	INFO("  sys [file]- Plays the file as system sound\n");
 | |
| 	INFO("  stop      - Stops playback\n");
 | |
| 	INFO("  - / +     - Decrease or increase the volume\n");
 | |
| 	INFO("  p / n     - Previous or next track\n");
 | |
| }
 | |
| 
 | |
| void Controller::_check_buttons() {
 | |
| 	if (BTN_PREV() && _debounce_button(0)) {
 | |
| 		_player->track_prev();
 | |
| 	} else if (BTN_VOL_UP() && _debounce_button(1)) {
 | |
| 		_player->vol_up();
 | |
| 	} else if (BTN_VOL_DOWN() && _debounce_button(2)) {
 | |
| 		_player->vol_down();
 | |
| 	} else if (BTN_NEXT() && _debounce_button(3)) {
 | |
| 		_player->track_next();
 | |
| 	}
 | |
| }
 | |
| 
 | |
| bool Controller::_debounce_button(uint8_t index) {
 | |
| 	bool ret = false;
 | |
| 	if (_button_last_pressed_at[index] + DEBOUNCE_MILLIS < millis()) {
 | |
| 		DEBUG("Button %d pressed.\n", index);
 | |
| 		ret = true;
 | |
| 	}
 | |
| 	_button_last_pressed_at[index] = millis();
 | |
| 	return ret;
 | |
| }
 | |
| String Controller::get_status_json() {
 | |
| 	String response = String("{");
 | |
| 	response.concat("\"state\": \"");
 | |
| 	response.concat(_player->is_playing() ? "playing" : "idle");
 | |
| 	response.concat("\", ");
 | |
| 	if (_player->is_playing()) {
 | |
| 		response.concat("\"album\": \"");
 | |
| 		response.concat(_player->album());
 | |
| 		response.concat("\", \"track\": ");
 | |
| 		response.concat(_player->track());
 | |
| 		response.concat(", \"position\": ");
 | |
| 		response.concat(_player->position());
 | |
| 		response.concat(", ");
 | |
| 	}
 | |
| 	response.concat("\"volume\": ");
 | |
| 	response.concat(_player->volume());
 | |
| 	response.concat(", \"volume_max\": ");
 | |
| 	response.concat(VOLUME_MAX);
 | |
| 	response.concat(", \"volume_min\": ");
 | |
| 	response.concat(VOLUME_MIN);
 | |
| 	response.concat(", \"rfid_uid\": ");
 | |
| 	response.concat(String(_last_rfid_card_uid, HEX));
 | |
| 	response.concat("}\n");
 | |
| 	return response;
 | |
| }
 | |
| 
 | |
| void Controller::_send_mqtt_report() {
 | |
| 
 | |
| }
 |