Beispiel #1
0
void
CannaLooper::_HandleLocationReply(BMessage* msg)
{
	BPoint where = B_ORIGIN;
	float height = 0.0;
	int32 start;

	SERIAL_PRINT(("CannaLooper: B_INPUT_METHOD_LOCATION_REQUEST received\n"));

	start = fCanna->GetRevStartPositionInChar();

#ifdef DEBUG
	type_code type;
	int32 count;
	msg->GetInfo("be:location_reply", &type, &count);
	SERIAL_PRINT(("CannaLooper: LOCATION_REPLY has %d locations.\n", count));
	SERIAL_PRINT(("CannaLooper: RevStartPosition is %d.\n", start));
#endif

	msg->FindPoint("be:location_reply", start, &where);
	msg->FindFloat("be:height_reply", start, &height);
	BMessage m(KOUHO_WINDOW_SHOWAT);
	m.AddPoint("position", where);
	m.AddFloat("height", height);

	fKouhoWindow->PostMessage(fCanna->GenerateKouhoString());
	fKouhoWindow->PostMessage(&m);
}
Beispiel #2
0
void
CannaLooper::Quit()
{
	// delete palette here
	SERIAL_PRINT(("CannaLooper: destructor called.\n"));
	delete fCanna;

	if (fKouhoWindow != NULL) {
		SERIAL_PRINT(("CannaLooper: Sending QUIT to kouho window...\n"));

		fKouhoWindow->Lock();
		fKouhoWindow->Quit();
	}

	if (fPaletteWindow) {
		SERIAL_PRINT(("CannaLooper: Sending QUIT to palette...\n"));

		fPaletteWindow->Lock();
		fPaletteWindow->Quit();
	}

	fOwner->SetMenu(NULL, BMessenger());
	delete fMenu;
	BLooper::Quit();
}
Beispiel #3
0
void last_hopper_waypoint(int h) {
	Hopper& hopper = hoppers[h];
	Target& last_waypoint = hopper_waypoints[h][0];
	int hx = boundaries[hopper.index].x;
	int hy = boundaries[hopper.index].y;
	last_waypoint.theta = atan2(hy - last_waypoint.y, hx - last_waypoint.x);
	SERIAL_PRINT("last waypoint: ");
	SERIAL_PRINT(hopper_waypoints[h][0].x);
	SERIAL_PRINT(' ');
	SERIAL_PRINT(hopper_waypoints[h][0].y);
	SERIAL_PRINT(' ');
	SERIAL_PRINTLN(hopper_waypoints[h][0].theta * RADS);
}
Beispiel #4
0
void
CannaLooper::_ForceKakutei()
{
	SERIAL_PRINT(( "CannaLooper: _ForceKakutei() called\n" ));

	uint32 result = fCanna->Kakutei();

	SERIAL_PRINT(("CannaLooper: returned from Kakutei(). result = %d\n",
		result));

	if (result != NOTHING_TO_KAKUTEI)
		_ProcessResult(result);
	else
		SendInputStopped();
}
Beispiel #5
0
BottomlineWindow::BottomlineWindow()
	: BWindow(BRect(0, 0, 350, 16), "", 
		kLeftTitledWindowLook, 
		B_FLOATING_ALL_WINDOW_FEEL,
		B_NOT_V_RESIZABLE | B_NOT_CLOSABLE | B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE
			| B_AVOID_FOCUS | B_WILL_ACCEPT_FIRST_CLICK)
{
	BRect textRect = Bounds();
	textRect.OffsetTo(B_ORIGIN);
	textRect.InsetBy(2,2);
	fTextView = new BTextView(Bounds(), "", textRect, be_plain_font,
		NULL, B_FOLLOW_ALL, B_WILL_DRAW | B_FRAME_EVENTS);
	AddChild(fTextView);

	fTextView->SetText("");

	BRect   screenFrame = (BScreen(B_MAIN_SCREEN_ID).Frame());
	BPoint pt;
	pt.x = 100;
	pt.y = screenFrame.Height()*2/3 - Bounds().Height()/2;	
	
	MoveTo(pt);
	Show();

	SERIAL_PRINT(("BottomlineWindow created\n"));
}
Beispiel #6
0
void KouhoWindow::ShowAt( BPoint revpoint, float height )
{
	BRect screenrect;
	BPoint point;
	int32 kouhowidth, kouhoheight;

	kouhowidth = Frame().IntegerWidth();
	kouhoheight = Frame().IntegerHeight();

	screenrect = BScreen( this ).Frame();
#ifdef DEBUG
SERIAL_PRINT(( "KouhoWindow: ShowAt activated. point x= %f, y= %f, height= %f", revpoint.x, revpoint.y, height ));
#endif
	//adjust to preferred position - considering window border & index
	//revpoint.y += WINDOW_BORDER_WIDTH;
	point.y = revpoint.y + height + WINDOW_BORDER_WIDTH_V;
	point.x = revpoint.x - indexView->Frame().IntegerWidth()
				- INDEXVIEW_SIDE_MARGIN;

	if ( point.y + kouhoheight > screenrect.bottom )
		point.y = revpoint.y - kouhoheight - WINDOW_BORDER_WIDTH_V;
//	else
//		point.y = revpoint.y + height;

	if ( point.x + kouhowidth > screenrect.right )
		point.x = point.x - (screenrect.right - (point.x + kouhowidth ));
//		point.x = revpoint.x
//			- ( revpoint.x + kouhowidth + WINDOW_BORDER_WIDTH - screenrect.right );
//	else
//		point.x = revpoint.x;

	MoveTo( point );
	ShowWindow();
}
Beispiel #7
0
CannaMethod::~CannaMethod()
{
	BLooper *looper = NULL;
	cannaLooper.Target( &looper );
	if ( looper != NULL )
	{
#ifdef DEBUG
	SERIAL_PRINT(( "CannaIM:Locking CannaLooper...\n" ));
#endif
		if ( looper->Lock() )
#ifdef DEBUG
	SERIAL_PRINT(( "CannaIM:CannaLooper locked. Calling Quit().\n" ));
#endif
			looper->Quit();
	}
	WriteSettings();
}
Beispiel #8
0
void
CannaLooper::SendInputStopped()
{
	BMessage* msg = new BMessage(B_INPUT_METHOD_EVENT);
	msg->AddInt32("be:opcode", B_INPUT_METHOD_STOPPED);
	EnqueueMessage(msg);

	SERIAL_PRINT(("CannaLooper: B_INPUT_METHOD_STOPPED has been sent\n"));
}
Beispiel #9
0
CannaMethod::CannaMethod()
	: BInputServerMethod("Canna", (const uchar*)kCannaIcon)
{
#ifdef DEBUG
	SERIAL_PRINT(( "CannaIM:Constructor called.\n" ));
#endif
	SetMenu(NULL, BMessenger());
	ReadSettings();
}
Beispiel #10
0
void
CannaLooper::SendInputStarted()
{
	BMessage* msg = new BMessage(B_INPUT_METHOD_EVENT);
	msg->AddInt32("be:opcode", B_INPUT_METHOD_STARTED);
	msg->AddMessenger("be:reply_to", BMessenger(NULL, this));
	EnqueueMessage(msg);

	SERIAL_PRINT(("CannaLooper: B_INPUT_METHOD_STARTED has been sent\n"));
}
Beispiel #11
0
KouhoWindow::KouhoWindow( BFont *font, BLooper *looper )
	:BWindow(	DUMMY_RECT,
				"kouho", B_MODAL_WINDOW_LOOK,
				B_FLOATING_ALL_WINDOW_FEEL,
				B_NOT_RESIZABLE | B_NOT_CLOSABLE |
				B_NOT_ZOOMABLE | B_NOT_MINIMIZABLE | B_AVOID_FOCUS |
				B_NOT_ANCHORED_ON_ACTIVATE )
{
	float fontHeight;
	BRect frame;
	BFont indexfont;

	cannaLooper = looper;
	kouhoFont = font;

	font_family family;
	font_style style;
	strcpy( family, "Haru" );
	strcpy( style, "Regular" );
	indexfont.SetFamilyAndStyle( family, style );
	indexfont.SetSize( 10 );

#ifdef DEBUG
SERIAL_PRINT(( "kouhoWindow: Constructor called.\n" ));
#endif

	//setup main pane
	indexWidth = indexfont.StringWidth( "W" ) + INDEXVIEW_SIDE_MARGIN * 2;
	minimumWidth = indexfont.StringWidth( "ギリシャ  100/100" );

	frame = Bounds();
	frame.left = indexWidth + 2;
	frame.bottom -= INFOVIEW_HEIGHT;
	kouhoView = new KouhoView( frame );
	BRect screenrect = BScreen( this ).Frame();
	kouhoView->SetTextRect( screenrect ); //big enough
	kouhoView->SetFontAndColor( kouhoFont );
	kouhoView->SetWordWrap( false );
	AddChild( kouhoView );
	fontHeight = kouhoView->LineHeight();

	frame = Bounds();
	frame.right = indexWidth;
	frame.bottom = frame.bottom - INFOVIEW_HEIGHT + 1;
	indexView = new KouhoIndexView( frame, fontHeight );
	indexView->SetFont( &indexfont );
	AddChild( indexView );

	frame = Bounds();
	frame.top = frame.bottom - INFOVIEW_HEIGHT + 1;
	infoView = new KouhoInfoView( frame );
	infoView->SetFont( &indexfont );
	infoView->SetAlignment( B_ALIGN_RIGHT );
	AddChild( infoView );
}
Beispiel #12
0
void 
BottomlineWindow::HandleInputMethodEvent(BMessage* event, EventList& newEvents)
{
	CALLED();

	PostMessage(event, fTextView);

	const char* string;
	bool confirmed;
	int32 opcode;
	if (event->FindInt32("be:opcode", &opcode) != B_OK
		|| opcode != B_INPUT_METHOD_CHANGED
		|| event->FindBool("be:confirmed", &confirmed) != B_OK
		|| !confirmed
		|| event->FindString("be:string", &string) != B_OK) 
		return;

	SERIAL_PRINT(("IME : %i, %s\n", opcode, string));
	SERIAL_PRINT(("IME : confirmed\n"));

	int32 length = strlen(string);
	int32 offset = 0;
	int32 nextOffset = 0;

	while (offset < length) {
		// this is supposed to go to the next UTF-8 character
		for (++nextOffset; (string[nextOffset] & 0xC0) == 0x80; ++nextOffset)
			;

		BMessage *newEvent = new BMessage(B_KEY_DOWN);
		if (newEvent != NULL) {
			newEvent->AddInt32("key", 0);
			newEvent->AddInt64("when", system_time());
			BString bytes(string + offset, nextOffset - offset);
			newEvent->AddString("bytes", bytes);
			newEvent->AddInt32("raw_char", 0xa);
			newEvents.AddItem(newEvent);
		}

		offset = nextOffset;
	}
}
Beispiel #13
0
void
CannaLooper::_HandleKeyDown(BMessage* msg)
{
	uint32 modifier;
	int32 key;
	msg->FindInt32("modifiers", (int32*)&modifier);
	msg->FindInt32("key", &key);

	if ((modifier & B_COMMAND_KEY) != 0) {
		EnqueueMessage(DetachCurrentMessage());
		return;
	}

	char character;
	msg->FindInt8("byte", (int8*)&character);

	// The if clause below is to avoid processing key input which char code
	// is 0x80 or more.
	// if mikakutei string exists, dispose current message.
	// Otherwise, send it to application as usual B_KEY_DOWN message.
	if ((character & 0x80) != 0) {
		if (fCanna->MikakuteiLength() != 0)
			delete DetachCurrentMessage();
		else
			EnqueueMessage(DetachCurrentMessage());

		return;
	}

	SERIAL_PRINT(("CannaLooper: HandleKeyDown() calling "
		"CannaInterface::KeyIn()...\n", result));

	uint32 result = fCanna->KeyIn(character, modifier, key);

	SERIAL_PRINT(("CannaLooper: HandleKeyDown() received result = %d from "
		"CannaInterface.\n", result));

	_ProcessResult(result);
}
Beispiel #14
0
status_t
CannaMethod::InitCheck()
{
#ifdef DEBUG
	SERIAL_PRINT(( "CannaIM:InitCheck() called.\n" ));
#endif
	CannaLooper *looper;
	status_t err;
	looper = new CannaLooper( this );
	looper->Lock();
	err = looper->Init();
	looper->Unlock();
	cannaLooper = BMessenger( NULL, looper );
#ifdef DEBUG
	if ( err != B_NO_ERROR )
	SERIAL_PRINT(( "CannaLooper::InitCheck() failed.\n" ));
	else
	SERIAL_PRINT(( "CannaLooper::InitCheck() success.\n" ));
#endif

	return err;
}
Beispiel #15
0
void passive_red_line_correct() {
	// only correct to red line if not backing up
	if (abs(y - RENDEZVOUS_Y) < GRID_WIDTH*0.5 && layers[active_layer].speed > 0) {
		digitalWrite(bottom_led, HIGH);
		if (on_line(CENTER)) cycles_on_red_line = 0;
		else if (on_line(RED) && !on_line(CENTER)) {
			++cycles_on_red_line;
			// navigate trying to get back to red line and x is far enough forward
			if (seeking_red_line && RENDEZVOUS_X - x < 3*RENDEZVOUS_CLOSE) {
				waypoint(LAYER_NAV);
			}
		}
		else if (!on_line(RED)) {
			// not false alarm
			if (cycles_on_red_line >= CYCLES_CROSSING_LINE && current_distance() - last_correct_distance > DISTANCE_CENTER_TO_RED_ALLOWANCE) {
				SERIAL_PRINT("RC");
				SERIAL_PRINTLN(current_distance() - last_correct_distance);
				// direction and signs are taken care of by sin and cos
				float offset_y = DISTANCE_CENTER_TO_RED * sin(theta);
				// avoid correcting when parallel to horizontal line
				int offset_x = abs((int)x) % GRID_WIDTH;
				if (abs(offset_y) > NEED_TO_HOPPER_CORRECT && (offset_x < INTERSECTION_TOO_CLOSE*0.5 || offset_x > GRID_WIDTH - INTERSECTION_TOO_CLOSE*0.5) && parallel_to_horizontal()) {
					SERIAL_PRINTLN("-RC");
					cycles_on_red_line = 0;
					last_correct_distance = current_distance();
					return;
				}

				y = RENDEZVOUS_Y;
				// between [-180,0] left while going left
				// x += DISTANCE_CENTER_TO_RED * cos(theta);
				if (theta < 0) offset_y -= HALF_LINE_WIDTH;
				else offset_y += HALF_LINE_WIDTH;

				y += offset_y;

				last_red_line_distance = current_distance();
				last_correct_distance = last_red_line_distance;
				if (side_of_board == SIDE_RIGHT) side_of_board = SIDE_LEFT;
				else if (side_of_board == SIDE_LEFT) side_of_board = SIDE_RIGHT;
			}

			cycles_on_red_line = 0;
		}
	}
	else {
		digitalWrite(bottom_led, LOW);
		cycles_on_red_line = 0;
	}
}
Beispiel #16
0
void follow_hopper_waypoints(byte h) {
	Hopper& hopper = hoppers[h];
	if (hopper.waypoint == 0) {
		SERIAL_PRINT("No waypoints:");
		SERIAL_PRINTLN(h);
		return;
	}
	
	add_target(hopper_waypoints[h][0].x, hopper_waypoints[h][0].y, hopper_waypoints[h][0].theta, TARGET_GET, true);

	for (byte w = 1; w < hopper.waypoint; ++w) {
		add_target(hopper_waypoints[h][w].x, hopper_waypoints[h][w].y, ANY_THETA);
	}
}
Beispiel #17
0
void
CannaMethod::ReadSettings()
{
	BMessage pref;
	BFile preffile( CANNAIM_SETTINGS_FILE, B_READ_ONLY );
	if ( preffile.InitCheck() == B_NO_ERROR && pref.Unflatten( &preffile ) == B_OK )
	{
		pref.FindBool( "arrowkey", &gSettings.convert_arrowkey );
		pref.FindPoint( "palette", &gSettings.palette_loc );
		pref.FindPoint( "standalone", &gSettings.standalone_loc );
#ifdef DEBUG
SERIAL_PRINT(( "CannaMethod: ReadSettings() success. arrowkey=%d, palette_loc=%d,%d standalone_loc=%d, %d\n", gSettings.convert_arrowkey, gSettings.palette_loc.x, gSettings.palette_loc.y, gSettings.standalone_loc.x, gSettings.standalone_loc.y ));
#endif
		return;
	}

	//set default values
#ifdef DEBUG
SERIAL_PRINT(( "CannaMethod: ReadSettings() failed.\n" ));
#endif
	gSettings.convert_arrowkey = true;
	gSettings.palette_loc.Set( 800, 720 );
	gSettings.standalone_loc.Set( 256, 576 );
}
Beispiel #18
0
void CannaMethod::WriteSettings()
{
	BMessage pref;
	BFile preffile( CANNAIM_SETTINGS_FILE,
			B_WRITE_ONLY | B_CREATE_FILE | B_ERASE_FILE );

	if ( preffile.InitCheck() == B_NO_ERROR )
	{
		pref.AddBool( "arrowkey", gSettings.convert_arrowkey );
		pref.AddPoint( "palette", gSettings.palette_loc );
		pref.AddPoint( "standalone", gSettings.standalone_loc );
		pref.Flatten( &preffile );
#ifdef DEBUG
SERIAL_PRINT(( "CannaMethod: WriteSettings() success. arrowkey=%d, palette_loc=%d,%d standalone_loc=%d, %d\n", gSettings.convert_arrowkey, gSettings.palette_loc.x, gSettings.palette_loc.y, gSettings.standalone_loc.x, gSettings.standalone_loc.y ));
#endif
	}
}
Beispiel #19
0
// return from hopper to rendezvous in reverse direction
void return_from_hopper() {
	byte h;
	if (active_hopper == HOPPER1) h = 0;
	else if (active_hopper == HOPPER2) h = 2;
	else if (active_hopper == HOPPER3) h = 3;
	else if (active_hopper == HOPPER4) h = 4;
	Hopper& hopper = hoppers[h];
	if (hopper.waypoint == 0) {
		SERIAL_PRINT("No waypoints:");
		SERIAL_PRINTLN(active_hopper);
		return;
	}
	add_target(RENDEZVOUS_X, RENDEZVOUS_Y, 0, TARGET_PUT);
	// skip the last target
	for (byte w = hoppers[h].waypoint - 1; w > 0; --w) {
		add_target(hopper_waypoints[h][w].x, hopper_waypoints[h][w].y);
	}

}
void *
hoardSbrk(long size)
{
    assert(size > 0);
    CTRACE(("sbrk: size = %ld\n", size));

    // align size request
    size = (size + hoardHeap::ALIGNMENT - 1) & ~(hoardHeap::ALIGNMENT - 1);

    // choose correct protection flags
    uint32 protection = B_READ_AREA | B_WRITE_AREA;
    if (__gABIVersion < B_HAIKU_ABI_GCC_2_HAIKU)
        protection |= B_EXECUTE_AREA;

    hoardLock(sHeapLock);

    // find chunk in free list
    free_chunk *chunk = sFreeChunks, *last = NULL;
    for (; chunk != NULL; chunk = chunk->next) {
        CTRACE(("  chunk %p (%ld)\n", chunk, chunk->size));

        if (chunk->size < (size_t)size) {
            last = chunk;
            continue;
        }

        // this chunk is large enough to satisfy the request

        SERIAL_PRINT(("HEAP-%ld: found free chunk to hold %ld bytes\n",
                      find_thread(NULL), size));

        void *address = (void *)chunk;

        if (chunk->size > (size_t)size + sizeof(free_chunk)) {
            // divide this chunk into smaller bits
            size_t newSize = chunk->size - size;
            free_chunk *next = chunk->next;

            chunk = (free_chunk *)((addr_t)chunk + size);
            chunk->next = next;
            chunk->size = newSize;

            if (last != NULL) {
                last->next = next;
                insert_chunk(chunk);
            } else
                sFreeChunks = chunk;
        } else {
            chunk = chunk->next;

            if (last != NULL)
                last->next = chunk;
            else
                sFreeChunks = chunk;
        }

        hoardUnlock(sHeapLock);
        return address;
    }

    // There was no chunk, let's see if the area is large enough

    size_t oldHeapSize = sFreeHeapSize;
    sFreeHeapSize += size;

    // round to next heap increment aligned size
    size_t incrementAlignedSize = (sFreeHeapSize + kHeapIncrement - 1)
                                  & ~(kHeapIncrement - 1);

    if (incrementAlignedSize <= sHeapAreaSize) {
        SERIAL_PRINT(("HEAP-%ld: heap area large enough for %ld\n",
                      find_thread(NULL), size));
        // the area is large enough already
        hoardUnlock(sHeapLock);
        return (void *)(sFreeHeapBase + oldHeapSize);
    }

    // We need to grow the area

    SERIAL_PRINT(("HEAP-%ld: need to resize heap area to %ld (%ld requested)\n",
                  find_thread(NULL), incrementAlignedSize, size));

    status_t status = resize_area(sHeapArea, incrementAlignedSize);
    if (status != B_OK) {
        // Either the system is out of memory or another area is in the way and
        // prevents ours from being resized. As a special case of the latter
        // the user might have mmap()ed something over malloc()ed memory. This
        // splits the heap area in two, the first one retaining the original
        // area ID. In either case, if there's still memory, it is a good idea
        // to try and allocate a new area.
        sFreeHeapSize = oldHeapSize;

        if (status == B_NO_MEMORY) {
            hoardUnlock(sHeapLock);
            return NULL;
        }

        size_t newHeapSize = (size + kHeapIncrement - 1) / kHeapIncrement
                             * kHeapIncrement;

        // First try at the location directly after the current heap area, if
        // that is still in the reserved memory region.
        void* base = (void*)(sFreeHeapBase + sHeapAreaSize);
        area_id area = -1;
        if (sHeapBase != NULL
                && base >= sHeapBase
                && (addr_t)base + newHeapSize
                <= (addr_t)sHeapBase + kHeapReservationSize) {
            area = create_area("heap", &base, B_EXACT_ADDRESS, newHeapSize,
                               B_NO_LOCK, protection);

            if (area == B_NO_MEMORY) {
                hoardUnlock(sHeapLock);
                return NULL;
            }
        }

        // If we don't have an area yet, try again with a free location
        // allocation.
        if (area < 0) {
            base = (void*)(sFreeHeapBase + sHeapAreaSize);
            area = create_area("heap", &base, B_RANDOMIZED_BASE_ADDRESS,
                               newHeapSize, B_NO_LOCK, protection);
        }

        if (area < 0) {
            hoardUnlock(sHeapLock);
            return NULL;
        }

        // We have a new area, so make it the new heap area.
        sHeapArea = area;
        sFreeHeapBase = (addr_t)base;
        sHeapAreaSize = newHeapSize;
        sFreeHeapSize = size;
        oldHeapSize = 0;
    } else
        sHeapAreaSize = incrementAlignedSize;

    hoardUnlock(sHeapLock);
    return (void *)(sFreeHeapBase + oldHeapSize);
}
Beispiel #21
0
void PrintValueComma(char val) {
  SERIAL_PRINT(val);
  comma();
}
Beispiel #22
0
void PrintValueComma(unsigned long val)
{
  SERIAL_PRINT(val);
  comma();
}
Beispiel #23
0
void PrintValueComma(byte val)
{
  SERIAL_PRINT(val);
  comma();
}
Beispiel #24
0
void PrintValueComma(long int val)
{
  SERIAL_PRINT(val);
  comma();
}
Beispiel #25
0
void sendSerialTelemetry() {
  switch (queryType) {
  case '=': // Reserved debug command to view any variable from Serial Monitor
    break;

  case 'a': // Send roll and pitch rate mode PID values
    PrintPID(RATE_XAXIS_PID_IDX);
    PrintPID(RATE_YAXIS_PID_IDX);
    PrintValueComma(rotationSpeedFactor);
    SERIAL_PRINTLN();
    queryType = 'X';
    break;

  case 'b': // Send roll and pitch attitude mode PID values
    PrintPID(ATTITUDE_XAXIS_PID_IDX);
    PrintPID(ATTITUDE_YAXIS_PID_IDX);
    PrintPID(ATTITUDE_GYRO_XAXIS_PID_IDX);
    PrintPID(ATTITUDE_GYRO_YAXIS_PID_IDX);
    SERIAL_PRINTLN(windupGuard);
    queryType = 'X';
    break;

  case 'c': // Send yaw PID values
    PrintPID(ZAXIS_PID_IDX);
    PrintPID(HEADING_HOLD_PID_IDX);
    SERIAL_PRINTLN((int)headingHoldConfig);
    queryType = 'X';
    break;

  case 'd': // Altitude Hold
    #if defined AltitudeHoldBaro || defined AltitudeHoldRangeFinder
      PrintPID(BARO_ALTITUDE_HOLD_PID_IDX);
      PrintValueComma(PID[BARO_ALTITUDE_HOLD_PID_IDX].windupGuard);
      PrintValueComma(altitudeHoldBump);
      PrintValueComma(altitudeHoldPanicStickMovement);
      PrintValueComma(minThrottleAdjust);
      PrintValueComma(maxThrottleAdjust);
      #if defined AltitudeHoldBaro
        PrintValueComma(baroSmoothFactor);
      #else
        PrintValueComma(0);
      #endif
      PrintPID(ZDAMPENING_PID_IDX);
    #else
      PrintDummyValues(10);
    #endif
    SERIAL_PRINTLN();
    queryType = 'X';
    break;

  case 'e': // miscellaneous config values
    PrintValueComma(aref);
    SERIAL_PRINTLN(minArmedThrottle);
    queryType = 'X';
    break;

  case 'f': // Send transmitter smoothing values
    PrintValueComma(receiverXmitFactor);
    for (byte axis = XAXIS; axis < LASTCHANNEL; axis++) {
      PrintValueComma(receiverSmoothFactor[axis]);
    }
    PrintDummyValues(10 - LASTCHANNEL);
    SERIAL_PRINTLN();
    queryType = 'X';
    break;

  case 'g': // Send transmitter calibration data
    for (byte axis = XAXIS; axis < LASTCHANNEL; axis++) {
      Serial.print(receiverSlope[axis], 6);
      Serial.print(',');
    }
    SERIAL_PRINTLN();
    queryType = 'X';
    break;

  case 'h': // Send transmitter calibration data
    for (byte axis = XAXIS; axis < LASTCHANNEL; axis++) {
      Serial.print(receiverOffset[axis], 6);
      Serial.print(',');
    }
    SERIAL_PRINTLN();
    queryType = 'X';
    break;

  case 'i': // Send sensor data
    for (byte axis = XAXIS; axis <= ZAXIS; axis++) {
      PrintValueComma(gyroRate[axis]);
    }
    for (byte axis = XAXIS; axis <= ZAXIS; axis++) {
      PrintValueComma(filteredAccel[axis]);
    }
    for (byte axis = XAXIS; axis <= ZAXIS; axis++) {
      #if defined(HeadingMagHold)
        PrintValueComma(getMagnetometerData(axis));
      #else
        PrintValueComma(0);
      #endif
    }
    SERIAL_PRINTLN();
    break;

  case 'j': // Send raw mag values
    #ifdef HeadingMagHold
      PrintValueComma(getMagnetometerRawData(XAXIS));
      PrintValueComma(getMagnetometerRawData(YAXIS));
      SERIAL_PRINTLN(getMagnetometerRawData(ZAXIS));
    #endif
    break;

  case 'k': // Send accelerometer cal values
    SERIAL_PRINT(accelScaleFactor[XAXIS], 6);
    comma();
    SERIAL_PRINT(runTimeAccelBias[XAXIS], 6);
    comma();
    SERIAL_PRINT(accelScaleFactor[YAXIS], 6);
    comma();
    SERIAL_PRINT(runTimeAccelBias[YAXIS], 6);
    comma();
    SERIAL_PRINT(accelScaleFactor[ZAXIS], 6);
    comma();
    SERIAL_PRINTLN(runTimeAccelBias[ZAXIS], 6);
    queryType = 'X';
    break;

  case 'l': // Send raw accel values
    measureAccelSum();
    PrintValueComma((int)(accelSample[XAXIS]/accelSampleCount));
    accelSample[XAXIS] = 0;
    PrintValueComma((int)(accelSample[YAXIS]/accelSampleCount));
    accelSample[YAXIS] = 0;
    SERIAL_PRINTLN ((int)(accelSample[ZAXIS]/accelSampleCount));
    accelSample[ZAXIS] = 0;
    accelSampleCount = 0;
    break;

  case 'm': // Send magnetometer cal values
    #ifdef HeadingMagHold
      SERIAL_PRINT(magBias[XAXIS], 6);
      comma();
      SERIAL_PRINT(magBias[YAXIS], 6);
      comma();
      SERIAL_PRINTLN(magBias[ZAXIS], 6);
    #endif
    queryType = 'X';
    break;

  case 'n': // battery monitor
    #ifdef BattMonitor
      PrintValueComma(batteryMonitorAlarmVoltage);
      PrintValueComma(batteryMonitorThrottleTarget);
      PrintValueComma(batteryMonitorGoingDownTime);
    #else
      PrintDummyValues(3);
    #endif
    SERIAL_PRINTLN();
    queryType = 'X';
    break;

  case 'o': // send waypoints
    #ifdef UseGPSNavigator
      for (byte index = 0; index < MAX_WAYPOINTS; index++) {
        PrintValueComma(index);
        PrintValueComma(waypoint[index].latitude);
        PrintValueComma(waypoint[index].longitude);
        PrintValueComma(waypoint[index].altitude);
      }
    #else
      PrintDummyValues(4);
    #endif
    SERIAL_PRINTLN();
    queryType = 'X';
    break;

  case 'p': // Send Camera values
    #ifdef CameraControl
      PrintValueComma(cameraMode);
      PrintValueComma(servoCenterPitch);
      PrintValueComma(servoCenterRoll);
      PrintValueComma(servoCenterYaw);
      PrintValueComma(mCameraPitch);
      PrintValueComma(mCameraRoll);
      PrintValueComma(mCameraYaw);
      PrintValueComma(servoMinPitch);
      PrintValueComma(servoMinRoll);
      PrintValueComma(servoMinYaw);
      PrintValueComma(servoMaxPitch);
      PrintValueComma(servoMaxRoll);
      PrintValueComma(servoMaxYaw);
      #ifdef CameraTXControl
        PrintValueComma(servoTXChannels);
      #endif
    #else
      #ifdef CameraTXControl
        PrintDummyValues(14);
      #else
        PrintDummyValues(13);
      #endif
    #endif
    SERIAL_PRINTLN();
    queryType = 'X';
    break;

  case 'q': // Send Vehicle State Value
    SERIAL_PRINTLN(vehicleState);
    queryType = 'X';
    break;

  case 'r': // Vehicle attitude
    PrintValueComma(kinematicsAngle[XAXIS]);
    PrintValueComma(kinematicsAngle[YAXIS]);
    SERIAL_PRINTLN(getHeading());
    break;

  case 's': // Send all flight data
    PrintValueComma(motorArmed);
    PrintValueComma(kinematicsAngle[XAXIS]);
    PrintValueComma(kinematicsAngle[YAXIS]);
    PrintValueComma(getHeading());
    #if defined AltitudeHoldBaro || defined AltitudeHoldRangeFinder
      #if defined AltitudeHoldBaro
        PrintValueComma(getBaroAltitude());
      #elif defined AltitudeHoldRangeFinder
        PrintValueComma(rangeFinderRange[ALTITUDE_RANGE_FINDER_INDEX] != INVALID_RANGE ? rangeFinderRange[ALTITUDE_RANGE_FINDER_INDEX] : 0.0);
      #endif
      PrintValueComma((int)altitudeHoldState);
    #else
      PrintValueComma(0);
      PrintValueComma(0);
    #endif

    for (byte channel = 0; channel < 8; channel++) { // Configurator expects 8 values
      PrintValueComma((channel < LASTCHANNEL) ? receiverCommand[channel] : 0);
    }

    for (byte motor = 0; motor < LASTMOTOR; motor++) {
      PrintValueComma(motorCommand[motor]);
    }
    PrintDummyValues(8 - LASTMOTOR); // max of 8 motor outputs supported

    #ifdef BattMonitor
      PrintValueComma((float)batteryData[0].voltage/100.0); // voltage internally stored at 10mV:s
    #else
      PrintValueComma(0);
    #endif
    PrintValueComma(flightMode);
    SERIAL_PRINTLN();
    break;

  case 't': // Send processed transmitter values
    for (byte axis = 0; axis < LASTCHANNEL; axis++) {
      PrintValueComma(receiverCommand[axis]);
    }
    SERIAL_PRINTLN();
    break;

  case 'u': // Send range finder values
    #if defined (AltitudeHoldRangeFinder)
      PrintValueComma(maxRangeFinderRange);
      SERIAL_PRINTLN(minRangeFinderRange);
    #else
      PrintValueComma(0);
      SERIAL_PRINTLN(0);
    #endif
    queryType = 'X';
    break;

  case 'v': // Send GPS PIDs
    #if defined (UseGPSNavigator)
      PrintPID(GPSROLL_PID_IDX);
      PrintPID(GPSPITCH_PID_IDX);
      PrintPID(GPSYAW_PID_IDX);
      queryType = 'X';
    #else
      PrintDummyValues(9);
    #endif
    SERIAL_PRINTLN();
    queryType = 'X';
    break;
  case 'y': // send GPS info
    #if defined (UseGPS)
      PrintValueComma(gpsData.state);
      PrintValueComma(gpsData.lat);
      PrintValueComma(gpsData.lon);
      PrintValueComma(gpsData.height);
      PrintValueComma(gpsData.course);
      PrintValueComma(gpsData.speed);
      PrintValueComma(gpsData.accuracy);
      PrintValueComma(gpsData.sats);
      PrintValueComma(gpsData.fixtime);
      PrintValueComma(gpsData.sentences);
      PrintValueComma(gpsData.idlecount);
    #else
      PrintDummyValues(11);
    #endif    
    SERIAL_PRINTLN();
    break;
 
  case 'z': // Send all Altitude data 
    #if defined (AltitudeHoldBaro) 
      PrintValueComma(getBaroAltitude()); 
    #else
      PrintValueComma(0);
    #endif 
    #if defined (AltitudeHoldRangeFinder) 
      SERIAL_PRINTLN(rangeFinderRange[ALTITUDE_RANGE_FINDER_INDEX]);
    #else
      SERIAL_PRINTLN(0); 
    #endif 
    break;
    
  case '$': // send BatteryMonitor voltage/current readings
    #if defined (BattMonitor)
      PrintValueComma((float)batteryData[0].voltage/100.0); // voltage internally stored at 10mV:s
      #if defined (BM_EXTENDED)
        PrintValueComma((float)batteryData[0].current/100.0);
        PrintValueComma((float)batteryData[0].usedCapacity/1000.0);
      #else
        PrintDummyValues(2);
      #endif
    #else
      PrintDummyValues(3);
    #endif
    SERIAL_PRINTLN();
    break;
    
  case '%': // send RSSI
    #if defined (UseAnalogRSSIReader) || defined (UseEzUHFRSSIReader) || defined (UseSBUSRSSIReader)
      SERIAL_PRINTLN(rssiRawValue);
    #else
      SERIAL_PRINTLN(0);
    #endif
    break;

  case 'x': // Stop sending messages
    break;

  case '!': // Send flight software version
    SERIAL_PRINTLN(SOFTWARE_VERSION, 1);
    queryType = 'X';
    break;

  case '#': // Send configuration
    reportVehicleState();
    queryType = 'X';
    break;

  case '6': // Report remote commands
    for (byte motor = 0; motor < LASTMOTOR; motor++) {
      PrintValueComma(motorCommand[motor]);
    }
    SERIAL_PRINTLN();
    queryType = 'X';
    break;

#if defined(OSD) && defined(OSD_LOADFONT)
  case '&': // fontload
    if (OFF == motorArmed) {
      max7456LoadFont();
    }
    queryType = 'X';
    break;
#endif

  }
}
Beispiel #26
0
void
CannaLooper::_ProcessResult(uint32 result)
{
	SERIAL_PRINT(("CannaLooper: _ProcessResult() processing result = %d\n",
		result));

	if ((result & GUIDELINE_APPEARED) != 0) {
		SERIAL_PRINT(("CannaLooper: _ProcessResult() processing "
			"GUIDELINE_APPEARED\n"));

		if (fCanna->MikakuteiLength() != 0) {
			// usual guideline i.e. kouho

			BMessage* msg = new BMessage(B_INPUT_METHOD_EVENT);
			msg->AddInt32("be:opcode", B_INPUT_METHOD_LOCATION_REQUEST);
			fOwner->EnqueueMessage(msg);

			SERIAL_PRINT(("CannaLooper: B_INPUT_METHOD_LOCATION_REQUEST has "
				"been sent\n"));
		} else {
			// guideline exists, but no mikakutei string - means extend mode
			// and such.
			SERIAL_PRINT(("  GUIDELINE_APPEARED: calling "
				"GenerateKouho()...\n"));

			fKouhoWindow->PostMessage(fCanna->GenerateKouhoString());
			SERIAL_PRINT(("  GUIDELINE_APPEARED: posting KouhoMsg to "
				"KouhoWindow %x...\n", fKouhoWindow));

			fKouhoWindow->PostMessage(KOUHO_WINDOW_SHOW_ALONE);
		}
	}

	if ((result & GUIDELINE_DISAPPEARED) != 0) {
		SERIAL_PRINT(("CannaLooper: _ProcessResult() processing "
			"GUIDELINE_DISAPPEARED\n"));
		fKouhoWindow->PostMessage(KOUHO_WINDOW_HIDE);
	}

	if ((result & MODE_CHANGED) != 0) {
		SERIAL_PRINT(("CannaLooper: _ProcessResult() processing "
			"MODE_CHANGED\n"));

		BMessage message(PALETTE_WINDOW_BUTTON_UPDATE);
		message.AddInt32("mode", fCanna->GetMode());
		fPaletteWindow->PostMessage(&message);

		SERIAL_PRINT(("CannaLooper: PALETTE_BUTTON_UPDATE has been sent. "
			"mode = %d\n", fCanna->GetMode()));
	}

	if ((result & GUIDELINE_CHANGED) != 0) {
		SERIAL_PRINT(("CannaLooper: _ProcessResult() processing "
			"GUIDELINE_CHANGED\n"));
		fKouhoWindow->PostMessage(fCanna->GenerateKouhoString());
	}

	if ((result & THROUGH_INPUT) != 0) {
		SERIAL_PRINT(("CannaLooper: _ProcessResult() processing "
			"THROUGH_INPUT\n"));
		EnqueueMessage(DetachCurrentMessage());
	}

	if ((result & NEW_INPUT_STARTED) != 0) {
		SERIAL_PRINT(("CannaLooper: _ProcessResult() processing "
			"NEW_INPUT_STARTED\n"));
		SendInputStarted();
	}

	if ((result & KAKUTEI_EXISTS) != 0) {
		SERIAL_PRINT(("CannaLooper: _ProcessResult() processing "
			"KAKUTEI_EXISTS\n"));

		BMessage* msg = new BMessage(B_INPUT_METHOD_EVENT);
		msg->AddInt32("be:opcode", B_INPUT_METHOD_CHANGED);

		msg->AddString("be:string", fCanna->GetKakuteiStr());
		msg->AddInt32("be:clause_start", 0);
		msg->AddInt32("be:clause_end", fCanna->KakuteiLength());
		msg->AddInt32("be:selection", fCanna->KakuteiLength());
		msg->AddInt32("be:selection", fCanna->KakuteiLength());
		msg->AddBool("be:confirmed", true);
		fOwner->EnqueueMessage(msg);

		SERIAL_PRINT(("CannaLooper: B_INPUT_METHOD_CHANGED (confired) has "
			"been sent\n"));

		// if both kakutei and mikakutei exist, do not send B_INPUT_STOPPED
		if (!(result & MIKAKUTEI_EXISTS))
			SendInputStopped();
	}

	if ((result & MIKAKUTEI_EXISTS) != 0) {
		SERIAL_PRINT(("CannaLooper: _ProcessResult() processing "
			"MIKAKUTEI_EXISTS\n" ));

		int32 start, finish;
		BMessage* msg = new BMessage(B_INPUT_METHOD_EVENT);
		msg->AddInt32("be:opcode", B_INPUT_METHOD_CHANGED);
		msg->AddString("be:string", fCanna->GetMikakuteiStr());

		if (fCanna->HasRev()) {
			fCanna->GetRevPosition( &start, &finish);
			msg->AddInt32("be:clause_start", 0);
			msg->AddInt32("be:clause_end", start);
			msg->AddInt32("be:clause_start", start);
			msg->AddInt32("be:clause_end", finish);
			msg->AddInt32("be:clause_start", finish);
			msg->AddInt32("be:clause_end", fCanna->MikakuteiLength());
		} else {
			start = finish = fCanna->MikakuteiLength();
			msg->AddInt32("be:clause_start", 0);
			msg->AddInt32("be:clause_end", fCanna->MikakuteiLength());
		}

		msg->AddInt32("be:selection", start);
		msg->AddInt32("be:selection", finish);
		//msg->AddBool("be:confirmed", false);
		fOwner->EnqueueMessage(msg);

		SERIAL_PRINT(("CannaLooper: B_INPUT_METHOD_CHANGED (non-confirmed) "
			"has been sent\n"));
	}

	if ((result & MIKAKUTEI_BECOME_EMPTY) != 0) {
		SERIAL_PRINT(("CannaLooper: _ProcessResult() processing "
			"MIKAKUTEI_BECOME_EMPTY\n" ));
		BMessage* msg = new BMessage(B_INPUT_METHOD_EVENT);
		msg->AddInt32("be:opcode", B_INPUT_METHOD_CHANGED);

		msg->AddString("be:string", B_EMPTY_STRING);
		msg->AddInt32("be:clause_start", 0);
		msg->AddInt32("be:clause_end", 0);
		msg->AddInt32("be:selection", 0);
		msg->AddInt32("be:selection", 0);
		msg->AddBool( "be:confirmed", true);
		fOwner->EnqueueMessage(msg);

		SERIAL_PRINT(( "CannaLooper: B_INPUT_METHOD_CHANGED (NULL, confired) "
			"has been sent\n"));

		SendInputStopped();
	}
}
Beispiel #27
0
void comma() {
  SERIAL_PRINT(',');
}
Beispiel #28
0
void
CannaLooper::MessageReceived(BMessage* msg)
{
	SERIAL_PRINT(("CannaLooper: Entering MessageReceived() what=%.4s\n",
		(char*)&msg->what));

	switch (msg->what) {
		case B_KEY_DOWN:
		case NUM_SELECTED_FROM_KOUHO_WIN:
			_HandleKeyDown(msg);
			break;

		case B_INPUT_METHOD_EVENT:
			uint32 opcode, result;
			msg->FindInt32("be:opcode", (int32*)&opcode);

			switch (opcode) {
				case B_INPUT_METHOD_LOCATION_REQUEST:
					_HandleLocationReply(msg);
					break;

				case B_INPUT_METHOD_STOPPED:
					SERIAL_PRINT(("CannaLooper: B_INPUT_METHOD_STOPPED "
						"received\n"));
					_ForceKakutei();
					break;
			}
			break;

		case CANNA_METHOD_ACTIVATED:
			SERIAL_PRINT(("CannaLooper: CANNA_METHOD_ACTIVATED received\n"));
			_HandleMethodActivated(msg->HasBool("active"));
			break;

		case MODE_CHANGED_FROM_PALETTE:
			_ForceKakutei();
			int32 mode;
			msg->FindInt32("mode", &mode);
			result = fCanna->ChangeMode(mode);
			_ProcessResult(result);
			break;

		case B_ABOUT_REQUESTED:
		{
			SERIAL_PRINT(("CannaLooper: B_ABOUT_REQUESTED received\n"));

			BAlert* panel = new BAlert( "", "Canna Input Method\n"
				"  by Masao Kawamura 1999\n\n"
				"Canna\n"
				"  Copyright 1992 NEC Corporation, Tokyo, Japan\n"
				"  Special thanks to T.Murai for porting\n",
				"OK");
			panel->Go();
			break;
		}

		case RELOAD_INIT_FILE:
			_ForceKakutei();
			fCanna->Reset();
			break;

		case ARROW_KEYS_FLIPPED:
		{
			BMenuItem* item = fMenu->FindItem(ARROW_KEYS_FLIPPED);
			gSettings.convert_arrowkey = !gSettings.convert_arrowkey;
			item->SetMarked(gSettings.convert_arrowkey);
			fCanna->SetConvertArrowKey(gSettings.convert_arrowkey);
			break;
		}

		default:
			BLooper::MessageReceived(msg);
			break;
	}
}
Beispiel #29
0
// correct passing a line not too close to an intersection
void passive_correct() {

	// still on cool down
	if (passive_status < PASSED_NONE) {++passive_status; return;}

	if (!far_from_intersection(x, y)) {
		if (passive_status > PASSED_NONE) passive_status = PASSED_NONE;
		return;
	}

	// SERIAL_PRINTLN(passive_status, BIN);
	// check if center one first activated; halfway there
	if (on_line(CENTER) && !(passive_status & CENTER)) {
		correct_half_distance = current_distance();
		SERIAL_PRINTLN("PH");
	}


	// activate passive correct when either left or right sensor FIRST ACTIVATES
	if ((on_line(LEFT) || on_line(RIGHT)) && passive_status == PASSED_NONE) {
		correct_initial_distance = current_distance();
		// only look at RIGHT LEFT CENTER
		passive_status |= (on_lines & ENCOUNTERED_ALL);
		SERIAL_PRINT("PS");
		SERIAL_PRINTLN(passive_status, BIN);

		// all hit at the same time, don't know heading
		if (passive_status == ENCOUNTERED_ALL) hit_first = CENTER;
		else if (passive_status & LEFT) hit_first = LEFT;
		else hit_first = RIGHT;
		
		// return;
	}

	if ((passive_status & LEFT) && !on_line(LEFT)) passive_status |= PASSED_LEFT;
	if ((passive_status & RIGHT) && !on_line(RIGHT)) passive_status |= PASSED_RIGHT;

	// check if encountering any additional lines
	passive_status |= (on_lines & ENCOUNTERED_ALL);

	// distance from first to center too far, probably too parallel to line
	if (passive_status > PASSED_NONE && !(passive_status & CENTER) && (current_distance() - correct_initial_distance > CORRECT_TOO_FAR)) {
		passive_status = PASSED_COOL_DOWN;
		SERIAL_PRINT("PP");
		SERIAL_PRINTLN(current_distance() - correct_initial_distance);
		return;
	}
	// already hit center, see if second half distance is too far from first half distance
	else if ((passive_status & CENTER) && 
		((current_distance() - correct_half_distance) >	// second half distance
		(correct_half_distance - correct_initial_distance + CORRECT_CROSSING_TOLERANCE))) { // first half distance plus some room for error

		SERIAL_PRINT("PD");
		SERIAL_PRINT(correct_half_distance - correct_initial_distance);
		SERIAL_PRINT(' ');
		SERIAL_PRINTLN(current_distance() - correct_half_distance);
		passive_status = PASSED_COOL_DOWN;
	} 
				
	// correct at the first encounter of line for each sensor
	if ((passive_status & ENCOUNTERED_ALL) == ENCOUNTERED_ALL) {

		// correct only if the 2 half distances are about the same
		if (abs((current_distance() - correct_half_distance) - (correct_half_distance - correct_initial_distance)) < CORRECT_CROSSING_TOLERANCE) {
			
			// distance since when passive correct was activated
			float correct_elapsed_distance = current_distance() - correct_initial_distance;
			// always positive
			float theta_offset = atan2(correct_elapsed_distance, SIDE_SENSOR_DISTANCE);

			// reverse theta correction if direction is backwards
			if (layers[get_active_layer()].speed < 0) theta_offset = -theta_offset; 
			float theta_candidate;
			// assume whichever one passed first was the first to hit
			if (passive_status & PASSED_LEFT) theta_candidate = (square_heading()*DEGS) + theta_offset;
			else if (passive_status & PASSED_RIGHT) theta_candidate = (square_heading()*DEGS) - theta_offset;
			else if (hit_first == LEFT) theta_candidate = (square_heading()*DEGS) + theta_offset;
			else if (hit_first == RIGHT) theta_candidate = (square_heading()*DEGS) - theta_offset;
			// hit at the same time?
			else theta_candidate = (square_heading()*DEGS);

			// check how far away correction is from current theta
			if (abs(theta - theta_candidate) > THETA_CORRECT_LIMIT) {
				SERIAL_PRINT("PO");
				SERIAL_PRINTLN(theta_candidate*RADS);
				passive_status = PASSED_COOL_DOWN;
				return;
			}
			// else correct to candidate value
			theta = theta_candidate;
			SERIAL_PRINT('P');
			SERIAL_PRINTLN(theta_offset*RADS);

		}
		// suspicious of an intersection
		else {
			SERIAL_PRINT("PI");
			SERIAL_PRINT(correct_half_distance - correct_initial_distance);
			SERIAL_PRINT(' ');
			SERIAL_PRINTLN(current_distance() - correct_half_distance);
		}

		// reset even if not activated on this line (false alarm)
		passive_status = PASSED_COOL_DOWN;
	}

}
Beispiel #30
0
// get ball behaviour, should only occur at hopper approach
void get_ball() {
	Layer& get = layers[LAYER_GET];
	if (!get.active) return;

	if (LAYER_GET == active_layer) {
		SERIAL_PRINT(layers[LAYER_GET].speed);
		SERIAL_PRINT('|');
		SERIAL_PRINTLN(layers[LAYER_GET].angle);
	}

	// either going forward or backward, always no angle
	// go forward until ball is detected or arbitrary additional distance travelled
	if (ball_status < CAUGHT_BALL) {
		if (caught_ball()) ++ball_status;

		get.speed = GET_SPEED;
		if (abs(boundaries[active_hopper].theta) < THETA_TOLERANCE) get.angle = 0;
		// turn slightly to face hopper
		else if (boundaries[active_hopper].theta < 0) get.angle = -GET_TURN;
		else get.angle = GET_TURN;

		if (ball_status == CAUGHT_BALL) {
			// got to the ball, can also correct for position to be near hopper
			correct_to_hopper();
			// then close servo gate
			close_gate();
			hard_break(LAYER_GET);
			get_initial_distance = tot_distance;
		}
	}
	// after securing ball, drive backwards 
	else if (ball_status == SECURED_BALL) {
		// initial kick to go straight
		static int kick_cycle = 0;
		if (get.speed > -GET_SPEED) {get.angle = 13; }
		else if (get.angle > 0) {
			if (kick_cycle <= 0) {
				if (get.angle < 7) kick_cycle = 7 - get.angle;
				--get.angle;
			}
			else --kick_cycle;
		}
	
		get.speed = -GET_SPEED;
		// get.angle = 0;
		if (paused) resume_drive(LAYER_GET);
		// back up until you hit a line to correct position
		if (on_line(CENTER)) {
			corrected_while_backing_up = true; 
			correct_to_grid();
			SERIAL_PRINTLN("CWB");
		}
		
		// backed up far enough
		if (tot_distance - get_initial_distance > 5*GET_DISTANCE) {
			// corrected_while_backing_up && 
			// after getting ball, return to rendezvous point
			corrected_while_backing_up = false;
			layers[LAYER_GET].active = false;
			close_hoppers();
			return_from_hopper();
			// hard_break(LAYER_GET, 3);
		}
	}
	// in the middle of closing the gate, wait a couple cycles
	else {
		++ball_status;
	}
}