Esempio n. 1
0
/**
  * Prints the given string to the display, one character at a time.
  *
  * Blocks the calling thread until all the text has been displayed.
  *
  * @param s The string to display.
  *
  * @param delay The time to delay between characters, in milliseconds. Defaults
  *              to: MICROBIT_DEFAULT_PRINT_SPEED.
  *
  * @return MICROBIT_OK, MICROBIT_CANCELLED or MICROBIT_INVALID_PARAMETER.
  *
  * @code
  * display.print("abc123",400);
  * @endcode
  */
int MicroBitDisplay::print(ManagedString s, int delay)
{
    //sanitise this value
    if(delay <= 0 )
        return MICROBIT_INVALID_PARAMETER;

    // If there's an ongoing animation, wait for our turn to display.
    this->waitForFreeDisplay();

    // If the display is free, it's our turn to display.
    // If someone called stopAnimation(), then we simply skip...
    if (animationMode == ANIMATION_MODE_NONE)
    {
        if (s.length() == 1)
        {
            return printCharAsync(s.charAt(0));
        }
        else
        {
            this->printAsync(s, delay);
            fiberWait();
        }
    }
    else
    {
        return MICROBIT_CANCELLED;
    }

    return MICROBIT_OK;
}
Esempio n. 2
0
/**
  * Prints the given ManagedString to the display, one character at a time.
  * Returns immediately, and executes the animation asynchronously.
  *
  * @param s The string to display.
  *
  * @param delay The time to delay between characters, in milliseconds. Must be > 0.
  *              Defaults to: MICROBIT_DEFAULT_PRINT_SPEED.
  *
  * @return MICROBIT_OK, or MICROBIT_INVALID_PARAMETER.
  *
  * @code
  * display.printAsync("abc123",400);
  * @endcode
  */
int MicroBitDisplay::printAsync(ManagedString s, int delay)
{
    if (s.length() == 1)
        return printCharAsync(s.charAt(0));

    //sanitise this value
    if (delay <= 0 )
        return MICROBIT_INVALID_PARAMETER;

    if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED)
    {
        printingChar = 0;
        printingText = s;
        animationDelay = delay;
        animationTick = 0;

        animationMode = ANIMATION_MODE_PRINT_TEXT;
    }
    else
    {
        return MICROBIT_BUSY;
    }

    return MICROBIT_OK;
}
/**
  * Reads characters until a character matches one of the given delimeters
  *
  * @param delimeters the number of characters to match against
  * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
  *        gives a different behaviour:
  *
  *            ASYNC - Will attempt read the immediate buffer, and look for a match.
  *                    If there isn't, an empty ManagedString will be returned.
  *
  *            SYNC_SPINWAIT - will return MICROBIT_INVALID_PARAMETER
  *
  *            SYNC_SLEEP - Will first of all consider the characters in the immediate buffer,
  *                         if a match is not found, it will block on an event, fired when a
  *                         character is matched.
  *
  * @return an empty ManagedString on error, or a ManagedString containing characters
  */
ManagedString MicroBitUARTService::readUntil(ManagedString delimeters, MicroBitSerialMode mode)
{
    if(mode == SYNC_SPINWAIT)
        return MICROBIT_INVALID_PARAMETER;

    int localTail = rxBufferTail;
    int preservedTail = rxBufferTail;

    int foundIndex = -1;

    //ASYNC mode just iterates through our stored characters checking for any matches.
    while(localTail != rxBufferHead && foundIndex  == -1)
    {
        //we use localTail to prevent modification of the actual tail.
        char c = rxBuffer[localTail];

        for(int delimeterIterator = 0; delimeterIterator < delimeters.length(); delimeterIterator++)
            if(delimeters.charAt(delimeterIterator) == c)
                foundIndex = localTail;

        localTail = (localTail + 1) % rxBufferSize;
    }

    //if our mode is SYNC_SLEEP, we set up an event to be fired when we see a
    //matching character.
    if(mode == SYNC_SLEEP && foundIndex == -1)
    {
        eventOn(delimeters, mode);

        foundIndex = rxBufferHead - 1;

        this->delimeters = ManagedString();
    }

    if(foundIndex >= 0)
    {
        //calculate our local buffer size
        int localBuffSize = (preservedTail > foundIndex) ? (rxBufferSize - preservedTail) + foundIndex : foundIndex - preservedTail;

        uint8_t localBuff[localBuffSize + 1];

        memclr(&localBuff, localBuffSize + 1);

        circularCopy(rxBuffer, rxBufferSize, localBuff, preservedTail, foundIndex);

        //plus one for the character we listened for...
        rxBufferTail = (rxBufferTail + localBuffSize + 1) % rxBufferSize;

        return ManagedString((char *)localBuff, localBuffSize);
    }

    return ManagedString();
}
Esempio n. 4
0
/**
 * Enter pairing mode. This is mode is called to initiate pairing, and to enable FOTA programming
 * of the micro:bit in cases where BLE is disabled during normal operation.
 */
void MicroBitBLEManager::pairingMode(MicroBitDisplay &display)
{
	ManagedString namePrefix("BBC micro:bit [");
	ManagedString namePostfix("]");
	ManagedString BLEName = namePrefix + deviceName + namePostfix;

	ManagedString msg("PAIRING MODE!");

	int timeInPairingMode = 0;
	int brightness = 255;
	int fadeDirection = 0;

    ble->gap().stopAdvertising();

    // Clear the whitelist (if we have one), so that we're discoverable by all BLE devices.
#if CONFIG_ENABLED(MICROBIT_BLE_WHITELIST)
    BLEProtocol::Address_t addresses[MICROBIT_BLE_MAXIMUM_BONDS];
    Gap::Whitelist_t whitelist;
    whitelist.addresses = addresses;
    whitelist.capacity = MICROBIT_BLE_MAXIMUM_BONDS;
    whitelist.size = 0;
    ble->gap().setWhitelist(whitelist);
    ble->gap().setAdvertisingPolicyMode(Gap::ADV_POLICY_IGNORE_WHITELIST);
#endif

	// Update the advertised name of this micro:bit to include the device name
    ble->clearAdvertisingPayload();

    ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
    ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)BLEName.toCharArray(), BLEName.length());
    ble->setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    ble->setAdvertisingInterval(200);

    ble->gap().setAdvertisingTimeout(0);
    ble->gap().startAdvertising();

	// Stop any running animations on the display
	display.stopAnimation();
	display.scroll(msg);

	// Display our name, visualised as a histogram in the display to aid identification.
	showNameHistogram(display);

	while(1)
	{
		if (pairingStatus & MICROBIT_BLE_PAIR_REQUEST)
		{
			timeInPairingMode = 0;
			MicroBitImage arrow("0,0,255,0,0\n0,255,0,0,0\n255,255,255,255,255\n0,255,0,0,0\n0,0,255,0,0\n");
			display.print(arrow,0,0,0);

			if (fadeDirection == 0)
				brightness -= MICROBIT_PAIRING_FADE_SPEED;
			else
				brightness += MICROBIT_PAIRING_FADE_SPEED;

			if (brightness <= 40)
				display.clear();

			if (brightness <= 0)
				fadeDirection = 1;

			if (brightness >= 255)
				fadeDirection = 0;

			if (uBit.buttonA.isPressed())
			{
				pairingStatus &= ~MICROBIT_BLE_PAIR_REQUEST;
				pairingStatus |= MICROBIT_BLE_PAIR_PASSCODE;
			}
		}

		if (pairingStatus & MICROBIT_BLE_PAIR_PASSCODE)
		{
			timeInPairingMode = 0;
			display.setBrightness(255);
			for (int i=0; i<passKey.length(); i++)
			{
				display.image.print(passKey.charAt(i),0,0);
				uBit.sleep(800);
				display.clear();
				uBit.sleep(200);

				if (pairingStatus & MICROBIT_BLE_PAIR_COMPLETE)
					break;
			}

			uBit.sleep(1000);
		}

		if (pairingStatus & MICROBIT_BLE_PAIR_COMPLETE)
		{
			if (pairingStatus & MICROBIT_BLE_PAIR_SUCCESSFUL)
			{
				MicroBitImage tick("0,0,0,0,0\n0,0,0,0,255\n0,0,0,255,0\n255,0,255,0,0\n0,255,0,0,0\n");
				display.print(tick,0,0,0);
                uBit.sleep(5000);

                /*
                 * Disabled, as the API to return the number of active bonds is not reliable at present...
                 *
                display.clear();
                ManagedString c(getBondCount());
                ManagedString c2("/");
                ManagedString c3(MICROBIT_BLE_MAXIMUM_BONDS);
                ManagedString c4("USED");

                display.scroll(c+c2+c3+c4);
                *
                *
                */
			}
			else
			{
				MicroBitImage cross("255,0,0,0,255\n0,255,0,255,0\n0,0,255,0,0\n0,255,0,255,0\n255,0,0,0,255\n");
				display.print(cross,0,0,0);
			}
		}

		uBit.sleep(30);
		timeInPairingMode++;

		if (timeInPairingMode >= MICROBIT_BLE_PAIRING_TIMEOUT * 30)
			microbit_reset();
	}
}
/**
  * Copies characters into the buffer used for Transmitting to the central device.
  *
  * @param s the string to transmit
  * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
  *        gives a different behaviour:
  *
  *            ASYNC - Will copy as many characters as it can into the buffer for transmission,
  *                    and return control to the user.
  *
  *            SYNC_SPINWAIT - will return MICROBIT_INVALID_PARAMETER
  *
  *            SYNC_SLEEP - Will perform a cooperative blocking wait until all
  *                         given characters have been received by the connected
  *                         device.
  *
  * @return the number of characters written, or MICROBIT_NOT_SUPPORTED if there is
  *         no connected device, or the connected device has not enabled indications.
  */
int MicroBitUARTService::send(ManagedString s, MicroBitSerialMode mode)
{
    return send((uint8_t *)s.toCharArray(), s.length(), mode);
}
/**
  * Reads until one of the delimeters matches a character in the rxBuff
  *
  * @param delimeters a ManagedString containing a sequence of delimeter characters e.g. ManagedString("\r\n")
  *
  * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode
  *        gives a different behaviour:
  *
  *            ASYNC - If one of the delimeters matches a character already in the rxBuff
  *                    this method will return a ManagedString up to the delimeter.
  *                    Otherwise, it will return an Empty ManagedString.
  *
  *            SYNC_SPINWAIT - If one of the delimeters matches a character already in the rxBuff
  *                            this method will return a ManagedString up to the delimeter.
  *                            Otherwise, this method will spin (lock up the processor) until a
  *                            received character matches one of the delimeters.
  *
  *            SYNC_SLEEP - If one of the delimeters matches a character already in the rxBuff
  *                         this method will return a ManagedString up to the delimeter.
  *                         Otherwise, the calling fiber sleeps until a character matching one
  *                         of the delimeters is seen.
  *
  *         Defaults to SYNC_SLEEP.
  *
  * @return A ManagedString containing the characters up to a delimeter, or an Empty ManagedString,
  *         if another fiber is currently using this instance for reception.
  *
  * @note delimeters are matched on a per byte basis.
  */
ManagedString MicroBitSerial::readUntil(ManagedString delimeters, MicroBitSerialMode mode)
{

    if(rxInUse())
        return ManagedString();

    //lazy initialisation of our rx buffer
    if(!(status & MICROBIT_SERIAL_RX_BUFF_INIT))
    {
        int result = initialiseRx();

        if(result != MICROBIT_OK)
            return result;
    }

    lockRx();

    int localTail = rxBuffTail;
    int preservedTail = rxBuffTail;

    int foundIndex = -1;

    //ASYNC mode just iterates through our stored characters checking for any matches.
    while(localTail != rxBuffHead && foundIndex  == -1)
    {
        //we use localTail to prevent modification of the actual tail.
        char c = rxBuff[localTail];

        for(int delimeterIterator = 0; delimeterIterator < delimeters.length(); delimeterIterator++)
            if(delimeters.charAt(delimeterIterator) == c)
                foundIndex = localTail;

        localTail = (localTail + 1) % rxBuffSize;
    }

    //if our mode is SYNC_SPINWAIT and we didn't see any matching characters in our buffer
    //spin until we find a match!
    if(mode == SYNC_SPINWAIT)
    {
        while(foundIndex == -1)
        {
            while(localTail == rxBuffHead);

            char c = rxBuff[localTail];

            for(int delimeterIterator = 0; delimeterIterator < delimeters.length(); delimeterIterator++)
                if(delimeters.charAt(delimeterIterator) == c)
                    foundIndex = localTail;

            localTail = (localTail + 1) % rxBuffSize;
        }
    }

    //if our mode is SYNC_SLEEP, we set up an event to be fired when we see a
    //matching character.
    if(mode == SYNC_SLEEP && foundIndex == -1)
    {
        eventOn(delimeters, mode);

        foundIndex = rxBuffHead - 1;

        this->delimeters = ManagedString();
    }

    if(foundIndex >= 0)
    {
        //calculate our local buffer size
        int localBuffSize = (preservedTail > foundIndex) ? (rxBuffSize - preservedTail) + foundIndex : foundIndex - preservedTail;

        uint8_t localBuff[localBuffSize + 1];

        memclr(&localBuff, localBuffSize + 1);

        circularCopy(rxBuff, rxBuffSize, localBuff, preservedTail, foundIndex);

        //plus one for the character we listened for...
        rxBuffTail = (rxBuffTail + localBuffSize + 1) % rxBuffSize;

        unlockRx();

        return ManagedString((char *)localBuff, localBuffSize);
    }

    unlockRx();

    return ManagedString();
}
/**
  * Transmits the given string onto the broadcast radio.
  *
  * This is a synchronous call that will wait until the transmission of the packet
  * has completed before returning.
  *
  * @param data The packet contents to transmit.
  *
  * @return MICROBIT_OK on success, or MICROBIT_INVALID_PARAMETER if the buffer is invalid,
  *         or the number of bytes to transmit is greater than `MICROBIT_RADIO_MAX_PACKET_SIZE + MICROBIT_RADIO_HEADER_SIZE`.
  */
int MicroBitRadioDatagram::send(ManagedString data)
{
    return send((uint8_t *)data.toCharArray(), data.length());
}