Wireless communication with Android tablet

Hello guys,

I have some news for you :slight_smile: I was playing a little with bluetooth module attached to DS203. For the demonstration I have made small android application which connects to it and then grabs waveform and displays it on phone/tablet screen. It is only an experiment and the application currently does not have many features, but I would like to invite the android developers to participate in this projectā€¦

Here is a detailed tutorial how to get it working:
https://github.com/gabonator/DS203/tree/master/Man/SerialOutput

Here is the application DsoQuad.apk (click ā€œrawā€ to download the apk):
https://github.com/gabonator/DS203/blob/master/Resources/AndroidApk/DsoQuad.apk

Project for eclipse is placed here:
https://github.com/gabonator/DS203/tree/master/Resources/AndroidProject

And latest firmware can be downloaded from this link:
https://github.com/gabonator/DS203/tree/master/Bin

This is how it looks:

Have fun!
Gabriel

Very nice!

I should learn Android programming some time, but I hate Java too much :smiley:

Very nice job once again Gabriel, congratulations !
I wish someone would come out with a USB/COM stack for the Quad so that we donā€™t need to drill holes in the case (I have niiiiice aluminum case :wink:) or use the usbdisk/socket hackā€¦

Cheers,

Fred.

I have been thinking for a while that Chibios could be a nice option for the Quad. It already has an USB driver for the STM32F1, and because we have the 256 kB of extra flash waiting for us, the size is not a concern either.

In fact the situation for software development on the Quad seems now better than ever. There is plenty of examples and starting points, the flash size situation has been solved, FPGA can be programmed, and there is even the competition with cash prizes. Only thing holding us back is the number of hours in a day :slight_smile:

There also is a USB Virtual Com Port example for STM32 available on ST Microelectronics website.
Iā€™ve downloaded it if youā€™re interested, but Iā€™m not skilled enough to evaluate if integrating it in Quadā€™s BIOS is feasibleā€¦

Actually, I donā€™t like java either :slight_smile: I just used code from this guy:
projectproto.blogspot.com/2010/0 ā€¦ scope.html

It seems that he is not very familiar with java too, because his project is heavily based on Bluetooth Chat example from android webpage. I simplified his project, removed all the controls and placed there only three buttons which send simple commands over bluetooth to expression evaluator. The commands looks like normal C language functions:

Beep(100);
Print(ā€˜Helloā€™);
CH1::Resolution=2;
OSC.GetDataView();

It should be easy to extend the functionality of the evaluator and make a java application providing full control over oscilloscope.

About the aluminium casing - I was wondering, who the hell would like to buy such thing. At first I thought that they sell it because they had problems with exploding battery, to prevent the user from injury :slight_smile:

That was only a joke :slight_smile: Ok, this leads me to a different idea. We could use the USB connector for connection to the bluetooth module. It has 5 pins, the extra pin could be used for powering the module and USB lines could be shared with UART module. I have experience with PIC microcontrollers and some of them had very nice feature which allowed to remap internal peripherals to different MCU pins. I was looking at the datasheet I found out that pins PA11 and PA12 can be mapped as following:
PA11: USART1_CTS / USB D- / CAN_RX / TIM1_CH4
PA12: USART1_RTS / USB D+ / CAN_TX / TIM1_ETR

Sad, but itā€™s still possible to implement the USART in bit-banging way, where the PA11/PA12 pins can be used as digital I/O pins. Stupid and slow but it should work.

And finally - multiple endpoints for USB descriptor, this should be nice feature. But I donā€™t want to damage my device by messing up the USB driver, because I dont have any JTAG programmerā€¦ So I will wait until someone will implement this. Anyway, bluetooth connections is safer, the oscilloscope is galvanically isolated from PC/tablet and you donā€™t have to face ground loop problems.

I DO love Java ! :wink:
Actually, I am a Java developer at work.
Gabriel you might have noticed that C++ is not the language I am the most used to :slight_smile:ā€¦
Anyway if you guys need help with Java/Android, donā€™t hesitate to ask !

The aluminum case suits the Quad very well ! :wink:
It feels nice and sturdy, and Iā€™m sure it helps with EM shielding.

Youā€™re right about the galvanic isolation provided by the bluetooth connection, thatā€™s a good point.

Iā€™ve been using PICs for quite some time too, and remapable ports is a really nice feature for sure !..

There isnā€™t much risk. The bootloader seems to have a separate USB driver, so you can always reprogram if you mess up SYS / APP.

But yeah, bluetooth is nicer for itā€™s wireless characteristicsā€¦ I think if you switch to a bit smaller battery, there is enough space for bluetooth module in the battery bay.

AAAND, regarding the exploding batteries, my battery puffed up just a week ago (did not explode though) :slight_smile: Though it may have been because I have a habit of leaving my quad near the fan exhaust of my laptop where it gets quite hot.

Fantastic.
Iā€™m only an end user and i wonder if in the future it will be possible to control by remote the DSO in all its functionsā€¦

You can totally save/restore FW via UART port. No need JTAG.

I build it internal
The Bluetooth modul fits next to the Battery
I used a cheap modul from ebay
IMG_6928.JPG
IMG_6927.JPG

Nice job Tom77. Thats what I wanted to do but the bluetooth module I had in stock was to long to fit there.

Hello, I added new functions to the SDK, now it is even more simple to add new functions/constants/variables:

Here are the extended functions:

			// R/W variables
			{ "CH1.Enabled", CEvalToken::PrecedenceVar, _Ch1Enabled },
			{ "CH1.Coupling", CEvalToken::PrecedenceVar, _Ch1Coupling },
			{ "CH1.Resolution", CEvalToken::PrecedenceVar, _Ch1Resolution },
			{ "CH1.Probe", CEvalToken::PrecedenceVar, _Ch1Probe },
			{ "CH1.Position", CEvalToken::PrecedenceVar, _Ch1Position },
			{ "CH1.Color", CEvalToken::PrecedenceVar, _Ch1Color },
			
			{ "CH2.Enabled", CEvalToken::PrecedenceVar, _Ch1Enabled },
			{ "CH2.Coupling", CEvalToken::PrecedenceVar, _Ch1Coupling },
			{ "CH2.Resolution", CEvalToken::PrecedenceVar, _Ch1Resolution },
			{ "CH2.Probe", CEvalToken::PrecedenceVar, _Ch1Probe },
			{ "CH2.Position", CEvalToken::PrecedenceVar, _Ch1Position },
			{ "CH2.Color", CEvalToken::PrecedenceVar, _Ch1Color },

			{ "CH3.Enabled", CEvalToken::PrecedenceVar, _Ch3Enabled },
			{ "CH3.Polarity", CEvalToken::PrecedenceVar, _Ch3Polarity },
			{ "CH3.Position", CEvalToken::PrecedenceVar, _Ch3Position },
			{ "CH3.Color", CEvalToken::PrecedenceVar, _Ch3Color },

			{ "CH4.Enabled", CEvalToken::PrecedenceVar, _Ch4Enabled },
			{ "CH4.Polarity", CEvalToken::PrecedenceVar, _Ch4Polarity },
			{ "CH4.Position", CEvalToken::PrecedenceVar, _Ch4Position },
			{ "CH4.Color", CEvalToken::PrecedenceVar, _Ch4Color },

			{ "TIME.Resolution", CEvalToken::PrecedenceVar, _TimeResolution },

			{ "TRIG.Sync", CEvalToken::PrecedenceVar, _TrigSync },
			{ "TRIG.Type", CEvalToken::PrecedenceVar, _TrigType },
			{ "TRIG.Source", CEvalToken::PrecedenceVar, _TrigSource },
			{ "TRIG.State", CEvalToken::PrecedenceVar, _TrigState },
			{ "TRIG.Level", CEvalToken::PrecedenceVar, _TrigLevel },

			{ "DISP.Axes", CEvalToken::PrecedenceVar, _DispAxes },
			{ "DISP.Draw", CEvalToken::PrecedenceVar, _DispDraw },
			{ "DISP.Average", CEvalToken::PrecedenceVar, _DispAverage },
			{ "DISP.Persist", CEvalToken::PrecedenceVar, _DispPersist },
			{ "DISP.Grid", CEvalToken::PrecedenceVar, _DispGrid },
			{ "DISP.Axis", CEvalToken::PrecedenceVar, _DispAxis },

			{ "SPEC.Window", CEvalToken::PrecedenceVar, _SpecWindow },
			{ "SPEC.Display", CEvalToken::PrecedenceVar, _SpecDisplay },
			{ "RUN.Backlight", CEvalToken::PrecedenceVar, _RunBacklight },
			{ "RUN.Volume", CEvalToken::PrecedenceVar, _RunVolume },

			// functions
			{ "About", CEvalToken::PrecedenceFunc, _About },
			{ "Help", CEvalToken::PrecedenceFunc, _Help },

			{ "WND.Message", CEvalToken::PrecedenceFunc, _WndMessage },
			{ "WND.Dump", CEvalToken::PrecedenceFunc, _WndDump },			// output only through uart
			{ "ADC.Transfer", CEvalToken::PrecedenceFunc, _AdcTransfer },	// output only through uart

			// constants
			{ "WND::WmPaint", CEvalToken::PrecedenceConst, _WndWmPaint },
			{ "WND::WmKey", CEvalToken::PrecedenceConst, _WndWmKey },
			{ "WND::WmTick", CEvalToken::PrecedenceConst, _WndWmTick },
			{ "WND::WmBroadcast", CEvalToken::PrecedenceConst, _WndWmBroadcast },
			{ "WND::WsHidden", CEvalToken::PrecedenceConst, _WndWsHidden },
			{ "WND::WsVisible", CEvalToken::PrecedenceConst, _WndWsVisible },
			{ "WND::WsNoActivate", CEvalToken::PrecedenceConst, _WndWsNoActivate },
			{ "WND::WsModal", CEvalToken::PrecedenceConst, _WndWsModal },
			{ "WND::WsTick", CEvalToken::PrecedenceConst, _WndWsTick },
			{ "WND::WsListener", CEvalToken::PrecedenceConst, _WndWsListener },
			{ "KEY::Left", CEvalToken::PrecedenceConst, _KeyLeft },
			{ "KEY::Right", CEvalToken::PrecedenceConst, _KeyRight },
			{ "KEY::Up", CEvalToken::PrecedenceConst, _KeyUp },
			{ "KEY::Down", CEvalToken::PrecedenceConst, _KeyDown },
			{ "KEY::Enter", CEvalToken::PrecedenceConst, _KeyEnter },
			{ "KEY::Escape", CEvalToken::PrecedenceConst, _KeyEscape },
			{ "KEY::F1", CEvalToken::PrecedenceConst, _KeyF1 },
			{ "KEY::F2", CEvalToken::PrecedenceConst, _KeyF2 },
			{ "KEY::F3", CEvalToken::PrecedenceConst, _KeyF3 },
			{ "KEY::F4", CEvalToken::PrecedenceConst, _KeyF4 },

			// others
			{ "SET.Core.bUartTest", CEvalToken::PrecedenceVar, _SetCoreUartTest },
			{ "SET.Core.bUartEcho", CEvalToken::PrecedenceVar, _SetCoreUartEcho },
			{ "MENU.Item", CEvalToken::PrecedenceVar, _MenuItem },
			
			{ "SET.Save", CEvalToken::PrecedenceFunc, _SetSave },
			{ "SET.Load", CEvalToken::PrecedenceFunc, _SetLoad },
			{ "SET.Reset", CEvalToken::PrecedenceFunc, _SetReset },

			{ "ADC.Update", CEvalToken::PrecedenceFunc, _AdcUpdate },
			{ "TRIG.Update", CEvalToken::PrecedenceFunc, _TrigUpdate },
			{ "CORE.Update", CEvalToken::PrecedenceFunc, _CoreUpdate },
			{ "GEN.Update", CEvalToken::PrecedenceFunc, _GenUpdate2 },
			{ "LCD.Update", CEvalToken::PrecedenceFunc, _LcdUpdate },

			{ "ADC.ResetWritePtr", CEvalToken::PrecedenceFunc, _AdcResetWritePtr },
			{ "ADC.GetWritePtr", CEvalToken::PrecedenceFunc, _AdcGetWritePtr },
			{ "ADC.Enabled", CEvalToken::PrecedenceVar, _AdcEnabled },

			{ "BIOS.Get", CEvalToken::PrecedenceFunc, _BiosGet },
			{ "BIOS.Set", CEvalToken::PrecedenceFunc, _BiosSet },

Later I will add some comments how to use them. Now it is possible to send keystrokes to the app and control the cursor:
WND.Message( WND::WmKey, KEY::Down);
or set the menu item:
MENU.Item=4;
WND.Dump dumps all the window tree as json string
Help(); lists all of possible commands.

I am using Putty to connect to the DSO and then set SET.Core.bUartEcho=1 to see what I am typing, then SET.Core.bUartTest=0 to stop sending test messages every second. Becuase all strings are terminated only with \n, in putty I set Change Settingsā€¦->Terminal->Implicit CR in every LF to get readable result

Implementation of these new commands can be found here:
https://github.com/gabonator/DS203/blob/master/Source/Core/SdkV1.h