bool CDVRPTRControllerV2::setConfig()
{
	unsigned char buffer[105U];

	::memset(buffer, 0x00U, 105U);

	buffer[0U] = 'H';
	buffer[1U] = 'E';
	buffer[2U] = 'A';
	buffer[3U] = 'D';
	buffer[4U] = 'X';
	buffer[5U] = '9';
	buffer[6U] = '0';
	buffer[7U] = '0';
	buffer[8U] = '1';

	::memset(buffer + 9U, ' ', LONG_CALLSIGN_LENGTH);
	for (unsigned int i = 0U; i < LONG_CALLSIGN_LENGTH && i < m_callsign.Len(); i++)
		buffer[9U + i] = m_callsign.GetChar(i);

	buffer[65U] = m_duplex ? 0x03U : 0x00U;

	buffer[66U] = m_txInvert ? 0x01U : 0x00U;

	buffer[73U] = (m_modLevel * 256U) / 100U;

	buffer[87U] = 0x01U;

	// CUtils::dump(wxT("Written"), buffer, 105U);

	int ret = m_serial.write(buffer, 105U);
	if (ret != 105)
		return false;

	unsigned int count = 0U;
	unsigned int length;
	RESP_TYPE_V2 resp;
	do {

		::wxMilliSleep(10UL);

		resp = getResponse(m_buffer, length);

		if (resp != RT2_CONFIG) {
			count++;
			if (count >= MAX_RESPONSES) {
				wxLogError(wxT("The DV-RPTR modem is not responding to the configure command"));
				return false;
			}
		}
	} while (resp != RT2_CONFIG);

	// CUtils::dump(wxT("Response"), m_buffer, length);

	wxString firmware((char*)(m_buffer + 9U), wxConvLocal);

	wxLogInfo(wxT("DV-RPTR Modem Firmware version: %s"), firmware.c_str());

	return true;
}
Exemple #2
0
void
exit(int ispanic)
{
	canlock(&active);
	active.machs &= ~(1<<m->machno);
	active.exiting = 1;
	unlock(&active);

	spllo();
	print("cpu %d exiting\n", m->machno);
	do
		delay(100);
	while(consactive());

	splhi();
	delay(1000);	/* give serial fifo time to finish flushing */
	if (getconf("*debug") != nil) {
		USED(ispanic);
		delay(60*1000);		/* give us time to read the screen */
	}
	if(arch->coredetach)
		arch->coredetach();
	setupboot(1);			// set up to halt
	for (; ; )
		firmware();

	// on PC is just:
	//if (0) {
	//	shutdown(ispanic);
	//	arch->reset();
	//}
}
void FirmwareDownloader::systemMessageReceived(const QByteArray &data)
{
    qDebug() << "system message" << data.toHex();

    if (!m_upgradeInProgress) {
        return;
    }

    Bundle firmware(m_bundlePath);

    qDebug() << "** Uploading firmware resources...";
    m_connection->uploadManager()->uploadFirmwareResources(firmware.file(Bundle::FileTypeResources), firmware.crc(Bundle::FileTypeResources), [this, firmware]() {
        qDebug() << "** Firmware resources uploaded. OK";

        qDebug() << "** Uploading firmware binary...";
        m_connection->uploadManager()->uploadFirmwareBinary(false, firmware.file(Bundle::FileTypeFirmware), firmware.crc(Bundle::FileTypeFirmware), [this]() {
            qDebug() << "** Firmware binary uploaded. OK";
            m_connection->systemMessage(WatchConnection::SystemMessageFirmwareComplete);
            m_upgradeInProgress = false;
            emit upgradingChanged();
        }, [this](int code) {
            qWarning() << "** ERROR uploading firmware binary" << code;
            m_connection->systemMessage(WatchConnection::SystemMessageFirmwareFail);
            m_upgradeInProgress = false;
            emit upgradingChanged();
        });
    },
    [this](int code) {
        qWarning() << "** ERROR uploading firmware resources" << code;
        m_connection->systemMessage(WatchConnection::SystemMessageFirmwareFail);
        m_upgradeInProgress = false;
        emit upgradingChanged();
    });
}
void GeneralUtils::configureFabric(std::vector<char> const &buffer) {
    if (GeneralUtils::fileExists("/dev/xdevcfg")) {
        //We are on Kernel 4.6 or lower
        FILE *fd = fopen("/dev/xdevcfg", "w");
        if (fd == NULL) {
            throw std::runtime_error("Could not open /dev/xdevcfg device");
        }
        size_t written = fwrite(buffer.data(), sizeof(char), buffer.size(), fd);
        if (written != buffer.size()) {
            throw std::runtime_error("Could not write complete bitstream to /dev/xdevcfg");
        }
        fclose(fd);
    } else if (GeneralUtils::fileExists("/sys/class/fpga_manager/fpga0/firmware")) {
        const char bitstreamFile[] = "fabric_bitstream.bin";

        std::ofstream bitstream(std::string("/lib/firmware/") + bitstreamFile, std::ios::out | std::ios::binary | std::ios::trunc);
        bitstream.write(buffer.data(), buffer.size());
        bitstream.close();

        std::ofstream firmware("/sys/class/fpga_manager/fpga0/firmware");
        firmware << bitstreamFile;
        firmware.close();
        if (!firmware.good()) {
            throw std::runtime_error("Fabric configuration through fpga_manager failed!");
        }
        // Loading was successful, wait for half a second before using the fpga!
        // or else the board is gone... praise the fpga_manager
        std::this_thread::sleep_for(std::chrono::milliseconds(500));
    } else {
        // TODO load AWS bitstream
    }
}
static signed nvmimage2 (void const * memory, size_t extent, char const * filename, flag_t flags)

{
	struct nvm_header1 * nvm_header;
	unsigned module = 0;
	uint32_t offset = 0;
	do
	{
		nvm_header = (struct nvm_header1 *)((char *)(memory) + offset);
		if (LE32TOH (nvm_header->HEADERVERSION) != 0x60000000)
		{
			if (_allclr (flags, NVM_SILENCE))
			{
				error (0, errno, NVM_HDR_VERSION, filename, module);
			}
			return (-1);
		}
		if (checksum32 (nvm_header, sizeof (* nvm_header), 0))
		{
			if (_allclr (flags, NVM_SILENCE))
			{
				error (0, errno, NVM_HDR_CHECKSUM, filename, module);
			}
			return (-1);
		}
		offset += sizeof (* nvm_header);
		extent -= sizeof (* nvm_header);
		if (_anyset (flags, NVM_VERBOSE))
		{
			printf ("------- %s (%d) -------\n", filename, module);
			nvmpeek1 (nvm_header);
		}
		if (LE32TOH (nvm_header->IMAGETYPE) == NVM_IMAGE_FIRMWARE)
		{
			firmware (filename, module, (char *)(memory) + offset, 0x70, flags);
		}
		if (checksum32 ((char *)(memory) + offset, LE32TOH (nvm_header->IMAGELENGTH), nvm_header->IMAGECHECKSUM))
		{
			if (_allclr (flags, NVM_SILENCE))
			{
				error (0, errno, NVM_IMG_CHECKSUM, filename, module);
			}
			return (-1);
		}
		offset += LE32TOH (nvm_header->IMAGELENGTH);
		extent -= LE32TOH (nvm_header->IMAGELENGTH);
		module++;
	}
	while (nvm_header->NEXTHEADER);
	if (extent)
	{
		if (_allclr (flags, NVM_SILENCE))
		{
			error (0, errno, NVM_HDR_LINK, filename, module);
		}
	}
	return ((signed)(extent));
}
void FlashFirmwareDialog::updateUI()
{
  ui->firmwareFilename->setText(fwName);
  ui->burnButton->setEnabled(QFile(fwName).exists());

  FirmwareInterface firmware(fwName);
  if (firmware.isValid()) {
    ui->firmwareInfoFrame->show();
    ui->date->setText(firmware.getDate() + " " + firmware.getTime());
    ui->version->setText(firmware.getVersion());
    ui->variant->setText(firmware.getEEpromId());
    ui->date->setEnabled(true);
    ui->version->setEnabled(true);
    ui->variant->setEnabled(true);
    if (firmware.hasSplash()) {
      ui->splashFrame->show();
      ui->splash->setFixedSize(firmware.getSplashWidth(), firmware.getSplashHeight());
    }
    else {
      ui->splashFrame->hide();
    }
  }
  else {
    imageSource = FIRMWARE;
    ui->firmwareInfoFrame->hide();
    ui->splashFrame->hide();
  }

  QImage image;
  switch(imageSource) {
    case FIRMWARE:
      ui->useFirmwareSplash->setChecked(true);
      image = firmware.getSplash();
      break;
    case PROFILE:
      ui->useProfileSplash->setChecked(true);
      image.load(g.profile[g.id()].splashFile());
      break;
    case LIBRARY:
      ui->useLibrarySplash->setChecked(true);
      image.load(imageFile);
      break;
    case EXTERNAL:
      ui->useExternalSplash->setChecked(true);
      image.load(imageFile);
      break;
  }

  if (!image.isNull()) {
    ui->splash->setPixmap(makePixMap(image, g.profile[g.id()].fwType()));
  }
}
	void FalconCLIBase::addOptions(int value)
	{
		if(value & COMM_OPTIONS)
		{
			po::options_description comm("Communication Options");
			comm.add_options()
#if defined(LIBUSB)
				("libusb", "use libusb-1.0 based driver")
#endif
#if defined(LIBFTDI)
				("libftdi", "use libftdi based driver")
#elif defined(LIBFTD2XX)
				("ftd2xx", "use ftd2xx based driver")
#endif
				;
			m_progOptions.add(comm);
		}

		if(value & DEVICE_OPTIONS)
		{
			po::options_description device("Device options");
			device.add_options()
				("device_count", "Print the number of devices currently connected and return")
				("device_index", po::value<int>(), "Opens device of given index (starts at 0)")
				;

			m_progOptions.add(device);
		}

		if(value & FIRMWARE_OPTIONS)
		{
			po::options_description firmware("Firmware Options");
			firmware.add_options()
				("nvent_firmware", "Use 'nVent' firmware (Recommended)")
				("test_firmware", "Use test firmware")
				("firmware_file", po::value<std::string>(), "Specify external firmware file (instead of nvent or test)")
				("force_firmware", "Force firmware download, even if already loaded")
				("skip_checksum", "Ignore checksum errors when loading firmware (useful for FTD2XX on non-windows platforms)")
				;
			m_progOptions.add(firmware);
		}

#ifdef ENABLE_LOGGING
		po::options_description debug("Debug Message Options");
		debug.add_options()
			("debug_level", po::value<std::string>(), "Level of debug messages to print (FATAL, ERROR, WARN, INFO, DEBUG) (Default: FATAL)")
			;
//		("output_file", po::value<std::string>(), "File to output debug messages to (outputs to stdout otherwise")
		m_progOptions.add(debug);		
#endif
	}
void FlashFirmwareDialog::on_useFirmwareSplash_clicked()
{
  FirmwareInterface firmware(fwName);
  if (!firmware.isValid()) {
    QMessageBox::warning(this, tr("Error"), tr( "The firmware file is not valid." ));
  }
  else if (!firmware.hasSplash()) {
    QMessageBox::warning(this, tr("Error"), tr( "There is no start screen image in the firmware file." ));
  }
  else {
    imageSource = FIRMWARE;
  }
  updateUI();
}
void FlashFirmwareDialog::on_burnButton_clicked()
{
  g.flashDir(QFileInfo(fwName).dir().absolutePath());
  g.profile[g.id()].fwName(fwName);
  g.checkHardwareCompatibility(ui->checkHardwareCompatibility->isChecked());
  g.backupOnFlash(ui->backupEEprom->isChecked());

  qDebug() << "FlashFirmwareDialog: flashing" << fwName;

  if (imageSource != FIRMWARE) {
    // load the splash image
    const QPixmap * pixmap = ui->splash->pixmap();
    QImage image;
    if (pixmap) {
      image = pixmap->toImage().scaled(ui->splash->width(), ui->splash->height());
    }
    if (image.isNull()) {
      QMessageBox::critical(this, tr("Warning"), tr("Splash image not found"));
      return;
    }
    // write the customized firmware
    QString tempFile;
    if (getFileType(fwName) == FILE_TYPE_HEX)
      tempFile = generateProcessUniqueTempFileName("flash.hex");
    else
      tempFile = generateProcessUniqueTempFileName("flash.bin");
    qDebug() << "FlashFirmwareDialog: patching" << fwName << "with custom splash screen and saving to" << tempFile;
    FirmwareInterface firmware(fwName);
    firmware.setSplash(image);
    if (firmware.save(tempFile) <= 0) {
      QMessageBox::critical(this, tr("Warning"), tr("Cannot save customized firmware"));
      return;
    }
    startFlash(tempFile);
  }
  else {
    startFlash(fwName);
  }
}
Exemple #10
0
bool TellStick::isUpgradable() const {
	QString fw = firmware();
	if (fw == "?") {
		return false;
	}
	int firmware = fw.toInt();
	if (type() == 1) {
		//TellStick
		if (firmware <= 3) {
			return false;
		}
		if (firmware < 6) {
			return true;
		}

	} else if (type() == 2) {
		//TellStick Duo
		if (firmware < 10) {
			return true;
		}
	}
	return false;
}
bool convertEEprom(const QString &sourceEEprom, const QString &destinationEEprom, const QString &firmwareFilename)
{
  Firmware *currentFirmware = GetCurrentFirmware();
  FirmwareInterface firmware(firmwareFilename);
  if (!firmware.isValid())
    return false;

  unsigned int version = firmware.getEEpromVersion();
  unsigned int variant = firmware.getEEpromVariant();

  QFile sourceFile(sourceEEprom);
  int eeprom_size = sourceFile.size();
  if (!eeprom_size)
    return false;

  if (!sourceFile.open(QIODevice::ReadOnly))
    return false;

  QByteArray eeprom(eeprom_size, 0);
  long result = sourceFile.read(eeprom.data(), eeprom_size);
  sourceFile.close();

  QSharedPointer<RadioData> radioData = QSharedPointer<RadioData>(new RadioData());
  if (!loadEEprom(*radioData, (uint8_t *)eeprom.data(), eeprom_size) || !currentFirmware->saveEEPROM((uint8_t *)eeprom.data(), *radioData, variant, version))
    return false;

  QFile destinationFile(destinationEEprom);
  if (!destinationFile.open(QIODevice::WriteOnly))
    return false;

  result = destinationFile.write(eeprom.constData(), eeprom_size);
  destinationFile.close();
  if (result != eeprom_size)
    return false;

  return true;
}
Exemple #12
0
void KbFirmware::processDownload(QNetworkReply* reply){
    if(reply->error() != QNetworkReply::NoError)
        return;
    // Update last check
    lastCheck = lastFinished = QDateTime::currentMSecsSinceEpoch();
    QByteArray data = reply->readAll();
    // Don't do anything if this is the same as the last version downloaded
    QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Sha256);
    if(hash == fwTableHash)
        return;
    fwTableHash = hash;
    if(hasGPG == UNKNOWN){
        // Check for a GPG installation
        QProcess gpg;
        gpg.start("gpg", QStringList("--version"));
        gpg.waitForFinished();
        if(gpg.error() == QProcess::FailedToStart)
            // No GPG install
            hasGPG = NO;
        else {
            QString output = QString::fromUtf8(gpg.readAll());
            // Must support RSA keys and SHA256
            if(output.contains("RSA", Qt::CaseInsensitive) && output.contains("SHA256", Qt::CaseInsensitive))
                hasGPG = YES;
            else
                hasGPG = NO;
        }
        if(!hasGPG)
            qDebug() << "No GPG detected, signature verification disabled";
    }
    if(hasGPG){
        // If GPG is available, check the signature on the file before proceeding.
        QDir tmp = QDir::temp();
        // Save file to a temporary path. Include PID to avoid conflicts
        qint64 pid = QCoreApplication::applicationPid();
        QString fwPath = tmp.absoluteFilePath(QString("ckb-%1-firmware").arg(pid));
        QFile firmware(fwPath);
        if(!firmware.open(QIODevice::WriteOnly)
                || firmware.write(data) != data.length()){
            qDebug() << "Failed to write firmware file to temporary location, aborting firmware check";
            return;
        }
        firmware.close();
        // Write GPG key
        QString keyPath = tmp.absoluteFilePath(QString("ckb-%1-key.gpg").arg(pid));
        if(!QFile::copy(":/bin/msckey.gpg", keyPath)){
            firmware.remove();
            qDebug() << "Failed to write GPG key to temporary location, aborting firmware check";
            return;
        }
        // Check signature
        QProcess gpg;
        gpg.start("gpg", QStringList("--no-default-keyring") << "--keyring" << keyPath << "--verify" << fwPath);
        gpg.waitForFinished();
        // Clean up temp files
        tmp.remove(fwPath);
        tmp.remove(keyPath);
        if(gpg.error() != QProcess::UnknownError || gpg.exitCode() != 0){
            qDebug() << "GPG couldn't verify firmware signature:";
            qDebug() << gpg.readAllStandardOutput();
            qDebug() << gpg.readAllStandardError();
            return;
        }
        // Signature good, proceed to update database
    }
    fwTable.clear();
    QStringList lines = QString::fromUtf8(data).split("\n");
    bool scan = false;
    foreach(QString line, lines){
        // Collapse whitespace
        line.replace(QRegExp("\\s+"), " ").remove(QRegExp("^\\s")).remove(QRegExp("\\s$"));
        // Skip empty or commented-out lines
        if(line.length() == 0 || line.at(0) == '#')
            continue;
        // Don't read anything until the entries begin and don't read anything after they end
        if(!scan){
            if(line == "!BEGIN FW ENTRIES")
                scan = true;
            else
                continue;
        }
        if(line == "!END FW ENTRIES")
            break;
        QStringList components = line.split(" ");
        if(components.length() != 7)
            continue;
        // "VENDOR-PRODUCT"
        QString device = components[0].toUpper() + "-" + components[1].toUpper();
        FW fw;
        fw.fwVersion = components[2].toFloat();                             // Firmware blob version
        fw.url = QUrl::fromPercentEncoding(components[3].toLatin1());       // URL to zip file
        fw.ckbVersion = KbManager::parseVersionString(components[4]);       // Minimum ckb version
        fw.fileName = QUrl::fromPercentEncoding(components[5].toLatin1());  // Name of file inside zip
        fw.hash = QByteArray::fromHex(components[6].toLatin1());            // SHA256 of file inside zip
        // Update entry
        fwTable[device] = fw;
    }
int main()
{
  GPIO_InitTypeDef gpioInit = {0};
  struct syslinkPacket slPacket;
  struct crtpPacket_s packet;
  unsigned int ledGreenTime=0;
  unsigned int ledRedTime = 0;
  unsigned int ledBlueTime = 0;


  /* Detecting if we need to boot firmware or DFU bootloader */
  bootpinInit();
  if (bootpinStartFirmware() == true) {
    if (*((uint32_t*)FIRMWARE_START) != 0xFFFFFFFFU) {
      void (*firmware)(void) __attribute__((noreturn)) = (void *)(*(uint32_t*)(FIRMWARE_START+4));
      bootpinDeinit();
      // Start firmware
      NVIC_SetVectorTable(FIRMWARE_START, 0);
      __set_MSP(*((uint32_t*)FIRMWARE_START));
      firmware();
    }
  } else if (bootpinNrfReset() == true) {
    void (*bootloader)(void) __attribute__((noreturn)) = (void *)(*(uint32_t*)(SYSTEM_BASE+4));
    bootpinDeinit();
    // Start bootloader
    NVIC_SetVectorTable(SYSTEM_BASE, 0);
    __set_MSP(*((uint32_t*)SYSTEM_BASE));
    bootloader();

  }
  bootpinDeinit();

  /* Booting CRTP Bootloader! */
  SystemInit();
  uartInit();
  

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE);
  
  gpioInit.GPIO_Pin = GPIO_Pin_2;
  gpioInit.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_Init(GPIOD, &gpioInit);
  
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);

  gpioInit.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_0;
  gpioInit.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_Init(GPIOC, &gpioInit);
  GPIO_WriteBit(GPIOC, GPIO_Pin_0, 1);
  GPIO_WriteBit(GPIOC, GPIO_Pin_1, 1);

  SysTick->LOAD = (SystemCoreClock/8)/1000; // Set systick to overflow every 1ms
  SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk;
  NVIC_EnableIRQ(SysTick_IRQn);
  
  // Blue LED ON by default
  GPIO_WriteBit(GPIOD, GPIO_Pin_2, 1);

  while(1) {
    if (syslinkReceive(&slPacket)) {
      if (slPacket.type == SYSLINK_RADIO_RAW) {
        memcpy(packet.raw, slPacket.data, slPacket.length);
        packet.datalen = slPacket.length-1;

        ledGreenTime = tick;
        GPIO_WriteBit(GPIOC, GPIO_Pin_1, 0);

        if (bootloaderProcess(&packet)) {
          ledRedTime = tick;
          GPIO_WriteBit(GPIOC, GPIO_Pin_0, 0);

          memcpy(slPacket.data, packet.raw, packet.datalen+1);
          slPacket.length = packet.datalen+1;
          syslinkSend(&slPacket);
        }
      }
    }

    if (ledGreenTime!=0 && tick-ledGreenTime>10) {
      GPIO_WriteBit(GPIOC, GPIO_Pin_1, 1);
      ledGreenTime = 0;
    }
    if (ledRedTime!=0 && tick-ledRedTime>10) {
      GPIO_WriteBit(GPIOC, GPIO_Pin_0, 1);
      ledRedTime = 0;
    }

    if ((tick-ledBlueTime)>500) {
      if (GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_2)) {
        GPIO_WriteBit(GPIOD, GPIO_Pin_2, 0);
      } else {
        GPIO_WriteBit(GPIOD, GPIO_Pin_2, 1);
      }
      ledBlueTime = tick;
    }
  }
  return 0;
}
/* Ma-ma-ma-main function! */
void main()
{
  state_t state = LISTENING;
  command_t cmd = CMD_NO_CMD;
	firmware_start firmware;

  uint16_t channel_timer = 0, bootloader_timer = 0, connection_timer = 0;
  uint8_t ch_i = 0, firmware_number = 0;
  bool running;
	
  uint16_t bytes_received = 0;
  uint16_t bytes_total = 0;

  uint8_t ea_default, rf_default;

  // Disable RF interrupt
  rf_default = RF;
  RF = 0;
  // Disable global interrupt
  ea_default = EA;
  EA = 0;
  
  // Set up parameters for RF communication.
  configureRF();

  #ifdef DEBUG_LED_
  P0DIR = 0;
  P0 = 0x55;
  #endif 

  running = true;
  // Boot loader loop.
  // Will terminate after a couple of seconds if firmware has been successfully
  // installed.
  while (running) {
		
    // Polls the RF-interrupt bit every iteration. 
    if (RFF) {
      RFF = 0;
      nrf_irq();

      if (packet_received) {
        packet_received = false;
        connection_timer = 0;
        cmd = MSG_CMD;
     
        switch (cmd) {
          // Host initiates contact with the device.
          case CMD_INIT:
            // Send ACK to host, go to CONNECTED state if successful.
            sendInitAck(&state);
            // Reset timers 
            channel_timer = bootloader_timer = 0;
            break;

          // Host starts a firmware update.
          case CMD_UPDATE_START:
            if (state == CONNECTED) {
              // Initiate firmware updates, go to RECEIVING_FIRMWARE state
              // if successful.
              startFirmwareUpdate(&state, &bytes_total, &bytes_received, 
                                     &firmware_number);
            }

            #ifdef DEBUG_LED_
            P0 = state;
            #endif 
            break;

          // Write message containing one hex record.
          case CMD_WRITE:
            if (state == RECEIVING_FIRMWARE) {
              writeHexRecord(&state, &bytes_received); 
            }

            #ifdef DEBUG_LED_
            P0 = 0x40;
            #endif
            break;

          // Firmware update has been completed.
          case CMD_UPDATE_COMPLETE:
            CE_LOW();
            // Check that every byte is received.
            if (bytes_received == bytes_total) {
              // Mark firmware as successfully installed. 
              hal_flash_byte_write(FW_INSTALLED, 0x01);
              hal_flash_byte_write(FW_NUMBER, firmware_number); 
              state = CONNECTED;
              send(CMD_ACK);
            } else {
              send(CMD_NACK);
            }

            if (!send_success) {
              state = ERROR;
            }

            #ifdef DEBUG_LED_
            P0 = 0x10;
            #endif
            break;

          // Host request data from flash at specified address.
          case CMD_READ:
            readHexRecord();

            #ifdef DEBUG_LED_
            P0 = 0x20;
            #endif
            break;

          // Host sends ping to check connections with device.
          case CMD_PING:
            if (state != LISTENING) {
              send(CMD_PONG);
            }

            #ifdef DEBUG_LED_
            P0 = 0x80;
            #endif
            break;

          // Host sends disconnect
          case CMD_EXIT:
            state = LISTENING;
            break;

          // These commands should no be received.
          case CMD_NO_CMD:
          default:
            state = ERROR;
            break;
        }
        // Clear command
        cmd = CMD_NO_CMD;
      }

    // RF interrupt bit not set
    } else if (state == LISTENING) {
      // Will listen to one channel for 'a while' before changing.
      channel_timer++;
      if (channel_timer > CHANNEL_TIMEOUT) {
        channel_timer = 0;
        // Go to next channel
        ch_i = (ch_i+1)%3;
        hal_nrf_set_rf_channel(default_channels[ch_i]);

        #ifdef DEBUG_LED_
        P0 = ch_i;
        #endif

        // After changing channels and being in the LISTENING state
        // for 'a while', boot loader loop will check if there is firmware
        // installed, and if so end the while(running) loop.
        bootloader_timer++;
        if (bootloader_timer > BOOTLOADER_TIMEOUT) {
          bootloader_timer = 0;
          running = (hal_flash_byte_read(FW_INSTALLED) == 0x01) ? false : true;
        }
      }

    // While connected must receive something or connection times out.
    // Connection timer reset when packet received.
    } else if (state == CONNECTED) {
      connection_timer++;
      if (connection_timer > CONNECTION_TIMEOUT) {
        state = LISTENING;
      }
    }
	} 

  resetRF();

  #ifdef DEBUG_LED_
  // Default value for P0DIR
  P0 = 0x00;
  P0DIR = 0xFF;
  #endif

  EA = ea_default;
  RF = rf_default;

  // Reads address of firmware's reset vector.
  temp_data[0] = hal_flash_byte_read(FW_RESET_ADDR_H);
  temp_data[1] = hal_flash_byte_read(FW_RESET_ADDR_L);
	firmware = (firmware_start)(((uint16_t)temp_data[0]<<8) | (temp_data[1]));
	
  // Jump to firmware. Goodbye!
	firmware();
}
void FirmwareDownloader::performUpgrade()
{
    if (!m_updateAvailable) {
        qWarning() << "No update available";
        return;
    }

    if (m_upgradeInProgress) {
        qWarning() << "Upgrade already in progress. Won't start another one";
        return;
    }

    m_upgradeInProgress = true;
    emit upgradingChanged();

    QNetworkRequest request(m_url);
    QNetworkReply *reply = m_nam->get(request);
    connect(reply, &QNetworkReply::finished, [this, reply](){
        reply->deleteLater();

        if (reply->error() != QNetworkReply::NoError) {
            qWarning() << "Erorr fetching firmware" << reply->errorString();
            m_upgradeInProgress = false;
            emit upgradingChanged();
            return;
        }

        QByteArray data = reply->readAll();

        QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Sha256).toHex();

        if (hash != m_hash) {
            qWarning() << "Downloaded data hash doesn't match hash from target";
            m_upgradeInProgress = false;
            emit upgradingChanged();
            return;
        }

        QDir dir("/tmp/" + m_pebble->address().toString().replace(":", "_"));
        if (!dir.exists() && !dir.mkpath(dir.absolutePath())) {
            qWarning() << "Error saving file" << dir.absolutePath();
            m_upgradeInProgress = false;
            emit upgradingChanged();
            return;
        }
        QString path = "/tmp/" + m_pebble->address().toString().replace(":", "_");
        QFile f(path + "/" + reply->request().url().fileName());
        if (!f.open(QFile::WriteOnly | QFile::Truncate)) {
            qWarning() << "Cannot open tmp file for writing" << f.fileName();
            m_upgradeInProgress = false;
            emit upgradingChanged();
            return;
        }
        f.write(data);
        f.close();

        if (!ZipHelper::unpackArchive(f.fileName(), path)) {
            qWarning() << "Error unpacking firmware archive";
            m_upgradeInProgress = false;
            emit upgradingChanged();
            return;
        }

        Bundle firmware(path);
        if (firmware.file(Bundle::FileTypeFirmware).isEmpty() || firmware.file(Bundle::FileTypeResources).isEmpty()) {
            qWarning() << "Firmware bundle file missing binary or resources";
            m_upgradeInProgress = false;
            emit upgradingChanged();
            return;
        }

        qDebug() << "** Starting firmware upgrade **";
        m_bundlePath = path;
        m_connection->systemMessage(WatchConnection::SystemMessageFirmwareStart);

    });
}