TC65 Dev
TC65 Dev
TC65 Development
Building programs for the TC65/TC65i
Florent Clairambault 9/6/2011
Table of Contents
1 Introduction ..................................................................................................................................... 5 1.1 1.2 1.3 2 About ....................................................................................................................................... 5 Waiting for your comments .................................................................................................... 5 Who am I ................................................................................................................................. 5
Why is this chip great ...................................................................................................................... 5 2.1 2.2 2.3 2.4 Java .......................................................................................................................................... 5 OTAP ........................................................................................................................................ 5 The big picture ......................................................................................................................... 6 Nobodys perfect ..................................................................................................................... 6 JVM .................................................................................................................................. 6 Storage............................................................................................................................. 6 Potential interfaces issues ............................................................................................... 6
Read the .......................................................................................................................................... 6 3.2 3.3 Java .......................................................................................................................................... 6 Installing the IDE ...................................................................................................................... 7 Which version? ................................................................................................................ 7 Installation of Netbeans + Cinterion WTK ....................................................................... 7 Installation with Netbeans 7.0 ........................................................................................ 9
Your first program ......................................................................................................................... 11 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 4.9 4.10 4.11 Create the project ................................................................................................................. 11 Type some code..................................................................................................................... 12 Check the connection ............................................................................................................ 13 Run it on the chip .................................................................................................................. 15 Set the autostart.................................................................................................................... 16 Only way to do things? .......................................................................................................... 16 AT Commands........................................................................................................................ 16 Settings .................................................................................................................................. 17 URC ........................................................................................................................................ 17 SMS Management ................................................................................................................. 17 Power management .............................................................................................................. 18 Why................................................................................................................................ 18 -1-
4.11.1
TC65Dev Florent Clairambault Webingenia v168 6 September 2011 4.11.2 4.12 4.13 How................................................................................................................................ 19
Serial ...................................................................................................................................... 19 GPIO ....................................................................................................................................... 19 Pin by pin (AT)................................................................................................................ 19 Port configuration (AT) .................................................................................................. 20 Port configuration (Java API) ......................................................................................... 20
I2C .......................................................................................................................................... 21 GPS......................................................................................................................................... 21 CommConnection with NMEA parsing .......................................................................... 21 URC with Position parsing ............................................................................................. 22
Upstream communication ............................................................................................................. 25 5.1 5.2 5.3 5.4 Introduction ........................................................................................................................... 25 SMS ........................................................................................................................................ 25 HTTP ...................................................................................................................................... 26 TCP connection ...................................................................................................................... 26 Text protocol ................................................................................................................. 26 Proprietary binary ......................................................................................................... 26 M2MP ............................................................................................................................ 26
Libraries ......................................................................................................................................... 26 6.1 6.2 6.3 Why ....................................................................................................................................... 26 Creating a library ................................................................................................................... 26 Using a library ........................................................................................................................ 28
Remotely upgrading your programs with OTAP............................................................................ 29 7.1 7.2 7.3 7.4 7.5 7.6 7.7 7.8 Introduction ........................................................................................................................... 29 Setting up the server ............................................................................................................. 30 Setting up the project ............................................................................................................ 30 Deploying............................................................................................................................... 32 Launching OTAP with an AT Command ................................................................................. 32 Debugging OTAP .................................................................................................................... 33 Launching OTAP with an SMS ................................................................................................ 33 Launching OTAP from your programs ................................................................................... 35 -2-
TC65Dev Florent Clairambault Webingenia v168 6 September 2011 7.9 8 Use the midlet version .......................................................................................................... 35
Going a little further ...................................................................................................................... 35 8.1 8.2 8.3 Compiler optimization ........................................................................................................... 35 Using the pre-processor ........................................................................................................ 35 Working with multiple chip versions ..................................................................................... 37 General consideration ................................................................................................... 37 Best effort ...................................................................................................................... 37 Java API or not? ............................................................................................................. 37 EGS5............................................................................................................................... 38
Signed / unsigned .................................................................................................................. 38 Obfuscating ........................................................................................................................... 38 Why................................................................................................................................ 38 Without obfuscation...................................................................................................... 39 Make your own kind of obfuscation.............................................................................. 41
Improving performances ....................................................................................................... 41 Introduction ................................................................................................................... 41 Reducing allocations ...................................................................................................... 41 Limiting AT calls ............................................................................................................. 41 Multithreading............................................................................................................... 41 Network stack ................................................................................................................ 42 I/O Blocking or not? ....................................................................................................... 42
Some personal advices .................................................................................................................. 43 9.1 9.2 9.3 9.4 9.5 Project management: Start simple........................................................................................ 43 Product: Limit human actions ............................................................................................... 43 Product: Find errors on the field ........................................................................................... 43 Software is important............................................................................................................ 43 Real time is very fine ............................................................................................................. 43 BONUS ....................................................................................................................................... 44 Sample code .......................................................................................................................... 44 Logging class .................................................................................................................. 44 Asynchronous HTTP requests ........................................................................................ 44 String splitting................................................................................................................ 47 BufferedReader ............................................................................................................. 48 -3-
10 10.1
TC65Dev Florent Clairambault Webingenia v168 6 September 2011 10.1.5 10.1.6 10.2 Launching an update from your program ..................................................................... 48 Watchdog on a TC65 v2 ................................................................................................. 49
M2MP specifications ............................................................................................................. 50 Introduction ................................................................................................................... 50 Why is it working like that? ........................................................................................... 50 Specifications ................................................................................................................. 51
FAQ ............................................................................................................................................ 53
-4-
1 Introduction
1.1 About
The purpose of this document is to help new or long-time TC65/TC65i developers to build programs for the TC65/TC65i chip but also leaders of M2M projects to understand how this chip could help them build better, faster and safer M2M projects. This document doesnt intend to replace by any mean the Cinterion documentation. You should see it as a complementary document for all the wonders you might have.
1.3 Who am I
Im a software engineer, and the co-owner of a small company named WebIngenia where we build complete M2M solutions: embedded software, server, web/mobile interfaces. Ive been working with the TC65 chips since the very first version. We offer TC65i / TC65 / XT65 development services. You can contact us to talk about your projects: http://webingenia.com/contact
2.1 Java
Java allows you to make fast and reliable programs. The Garbage Collector manages the memory of your programs. You cannot have memory leaks or bad pointer algorithmic unless you store unused objects in a container (vector, array, hastable, etc.)/ The exception catching mechanism allows you to build programs with some code parts that should work. That meaning roughly that if a component fails, your program could still perform well.
2.2 OTAP
OTAP stands for Over The Air Provisioning. You can update a program completely remotely without the need of implementing any sort of auto-update mechanism. This could be performed with a Hello World program updated to the next version Hello World v2 And what is even better is that obfuscated and compressed, TC65 jar files (containing your programs) are really small. You can have a complete, quite complex, multithreaded program weight less than 25 KB. It wont consume much of your data plan. You can add to your programs some auto-updating features. At startup, it could compare its midlet version (well talk about it later) to the official version required by the servers. You should also add some security mechanisms to prevent auto-updating loops.
-5-
These issues are undocumented but I personally highly suspect they exist.
3.2 Java
You should have done some java before. Thats pretty much the complete knowledge you should have.
-6-
TC65Dev Florent Clairambault Webingenia v168 6 September 2011 Whether you have done some J2ME or J2SE before doesnt really matter. What matters is that you are able to write some clean code.
Press Next
Press Next
Press Next
Press Next
Press Yes
-7-
Press Next
Press Next
Press Next
Press Install
Press Finish
Press Next
Press Next
Select Serial or USB depending If you choose serial, you will on what connections you have have to choose the serial port. on the chip.
And the speed. You should Let the IP address as is unless No need to select 115 200 bps. you network already has this debugging port numbering scheme.
change
the
-8-
Press Next
Press Yes
Press Finish
Press Finish
And the installation is over. You are ready to build your first program. 3.3.3 Installation with Netbeans 7.0 Ill let you install Netbeans 7.0. You should choose the biggest version as this is the only one that supports the Mobile Environment. In Netbeans, you will need to: Open the Tools / Java Platforms menu
-9-
TC65Dev Florent Clairambault Webingenia v168 6 September 2011 You should see a window close to this one. You have no reference no any kind of TC65i SDK. Thats your issue. To fix this, you will click on the Add Platform button
Then you will ll have to select the Cinterion SDK. Its in C:\Program files\Cinterion\CMTK\TC65i\WTK. If you have a 64bits system, Program files will be replaced by Program files (x86).
You can click next, next, finish and you will have a new java platform.
Then you can open any previous project you have. But you might have a warning on it.
- 10 -
TC65Dev Florent Clairambault Webingenia v168 6 September 2011 If this happen, you can do a right click on the project, select properties and let the IDE select the good Device. You press OK and
- 11 -
TC65Dev Florent Clairambault Webingenia v168 6 September 2011 You created the structure of a TC65 Midlet.
- 12 -
TC65Dev Florent Clairambault Webingenia v168 6 September 2011 In your main HelloWorld.java file, you just add to add this variable to keep a reference to the Core instance, start it in startApp and stop it (if you want) in destroyApp. You have the added code written in bold:
private Core _core; public void startApp() throws MIDletStateChangeException { System.out.println("startApp"); System.out.println("Loading core..."); _core = new Core(); System.out.println("Launching core..."); _core.start(); } public void destroyApp(boolean cond) { System.out.println("destroyApp(" + cond + ")"); _core.stop(); notifyDestroyed(); }
Once youre connected to the chip, you can send some AT Commands to check that the chip responds:
Then in your workstation view, open the properties of the Module and set its port to the right one (COM1 in my case). - 13 -
- 14 -
To run the program, the SDK will in fact deploy it locally. You should see something like that:
Jad URL for OTA execution: http://localhost:8082/servlet/org.netbeans.modules.mobility.project.jam.JAMServlet/ C%3A/TC65projs/hello/dist//HelloSample.jad Starting emulator in execution mode ========================================================================= Starting TC65I emulator for running application. Please wait ... =========================================================================
Using following ini file for debugging session: "C:\Documents and Settings\Administrateur\Application Data\Cinterion\CMTK\TC65I\WM_Debug_config.ini" COM port used for "emulator session": COM1 Used baud rate for the module "115200 baud"... >>> Starting Download of Jar and Jad file... <<<
Downloading "C:\TC65projs\hello\dist\nbrun48365\HelloSample.jad"... ...finished Downloading "C:\TC65projs\hello\dist\nbrun48365\HelloSample.jar"... ...finished Start Java program inside the module...
Java program is started inside the module without debugging. Emulator is closed, while the java program is running inside the module.
You can get the output on the same port you used to deploy (ASC0 here), on another port (ASC1 or USB for instance), on a file (FILE) or remotely (UDP) by debugging it or not. The options are described on the AT Command set document, page 79.
Constructor startApp Loading core... Launching core... Main code running... Main code running... Main code running...
- 15 -
AT^SCFG=Userware/Autostart/Delay,100
Note: On TC65 (before the TC65i), the maximum delay was defined to 25s. You set the autostart program to hellosample.jad :
AT^SCFG=Userware/Autostart/AppName,,a:/hellosample.jad
AT^SCFG="Userware/Autostart","","1"
The empty parameter () stand for an empty password setup. Unless you are really sure about what you are doing, dont set a password. If you forget it, you will have to burn a new firmware to reset it. You can check all these settings by typing AT^SCFG?. The interesting part will look like that:
^SCFG: "Userware/Autostart","1" ^SCFG: "Userware/Autostart/AppName","a:/hellosample.jad" ^SCFG: "Userware/Autostart/Delay","100"
This is it! You have your first program, ready to be used in a production environment.
4.7 AT Commands
ATCommand object allow you interact with the AT command layer of the chip. The main rules, about how to instantiate and use this class, are: You can only instantiate a limited number of them If you share ATCommand instances between threads, you have to synchronize them yourself - 16 -
TC65Dev Florent Clairambault Webingenia v168 6 September 2011 When you stop using an ATCommand instance, you need to release it by calling the release method.
You can also register a class to some event and then connect one or more receiver to an ATCommand to receive event from this ATCommand through the ATCommandListener interface. These event messages are the URC. They can be used to detect a change of GPIO state of the reception of an SMS.
4.8 Settings
You can use the embedded RecordStore object to store data into the TC65. Thought, I dont recommend using this. It doesnt make things simpler, it has been reported to get corrupted and it will be harder to analyze afterwards. You should try as much as possible to keep a simple text file so that your technicians and end-users can modify the settings easily.
4.9 URC
The Unsolicited Result Codes are codes sent by the TC65 core to the program using the AT Command format. They can give you a lot of data, like changes in the quality of the GSM signal, in the state of the battery, in the state of the GPIO. You can see an example of URC management for detecting SMS arrival in 4.10 SMS Management. One of the most useful URC is this one:
AT+CMER=2,0,0,2,0
- 17 -
- 18 -
TC65Dev Florent Clairambault Webingenia v168 6 September 2011 4.11.2 How When you know you wont require doing anything on your chip, you can put it in complete sleep mode; you must put all your threads in sleep or waiting mode (see 0 for sample waiting code) and then set the sleep mode by sending on an ATCommand:
AT+CFUN=0
If you want to go a little bit further, you should also disable the GSM to avoid any GSM related consumption. This can be easily done by putting the chip in plane mode:
AT^SCFG=MEopMode/Airplane,1
4.12 Serial
A Serial port is handled like any other pair of InputStream and OutputStream connection :
CommConnection comm = (CommConnection) Connector.open(comm:com0;baudrate=115200;blocking=on); InputStream is = comm.getInputStream(); OutputStream os = comm.getOutputStream();
Then, you can do anything you want with it. Well anything ok, but you might not know where to start from. In most the case, you only need some basic string parsing.
4.13 GPIO
GPIO is one of the most commonly used communication part of the TC65. And it is really simple to handle. You should keep in mind that the GPIO cant detect electrical changes occurring for less than 50ms. You can control it using one AT Command or through the API (available only since the TC65i) through InPort and OutPort classes. If you only have some TC65i chips, you should stick to the java API.
You can use the GPIO bin by bin or setup a port where you combine the bins. The value you can send to the created port depends on the number of pins. For 2 pins, you can set/read values from 0 to 2. For 10 pins, you can set/read values from 0 to 1024. To use it, you must activate the GPIO bus:
AT^SPIO=1
4.13.1 Pin by pin (AT) The setup some Input and Output pin, lets say GPIO 3 in input and GPIO 4 in output
AT^SCPIN=1,2,0 AT^SCPIN=1,3,1
- 19 -
TC65Dev Florent Clairambault Webingenia v168 6 September 2011 This will return you this in case of high state:
^SGIO: 1 OK
4.13.2 Port configuration (AT) Lets say we now want GPIO 5,6,7,8 to make a 4 bits port. It means we will be able to send values between 0 and 16 (24). We will send this:
AT^SCPIN=1,4,0 AT^SCPIN=1,5,0 AT^SCPIN=1,6,0 AT^SCPIN=1,7,0 AT^SCPORT=4,5,6,7
The created port can be considered like any other GPIO except that you can receive (and send) more values than just 0 and 1. Here reading values from this port can be done by sending:
AT^SGIO=112
4.13.3 Port configuration (Java API) Doing in the java API is really easy:
Vector pins = new Vector(); pins.addElement("GPIO5"); pins.addElement("GPIO6"); pins.addElement("GPIO7"); pins.addElement("GPIO8"); InPort inport = new InPort(pins); System.out.println( Value of the port : + inport.getValue() );
If you want to manage it as an event, you can create a listener by implementing the InPortListener interface that basically just make you add the void portValueChanged( int value ) method.
- 20 -
TC65Dev Florent Clairambault Webingenia v168 6 September 2011 Note that once you use the GPIOs from the java interface, you cannot use them anymore through the AT Command interface.
4.14 I2C
Its clearly explained in the I2cBusConnection javadoc. The most important part for me is the example given:
// Open I2C connection and data streams: i2cConnection cc = (I2cBusConnection) Connector.open("i2c:0;baudrate=100"); int baudrate = cc.getBaudRate(); InputStream inStream = cc.openInputStream(); OutputStream outStream = cc.openOutputStream(); // Write Transfer Frame, where a = message ID, AE = Slave Address and write // request: String data = "<aAE000102030405060708090A0B0C0E0F>"; outStream.write(data.getBytes(), 0, data.length()); outStream.flush();
What isnt really explained is how you are supposed to parse messages. You basically need to get the part between the < char and the > char by reading each char one by one.
4.15 GPS
GPS can be handled by an external chip connected on a serial port or by the chip itself (if you have an XT65 chip). Theres no XT65i chip. In terms of evolution, the XT65 v2 has the same features as the TC65 v3. So, its quite close to the TC65i. As written in the XT65 rel2 java documentation: The on-board GPS functionality can be accessed in 4 different ways from a Java application. - AT commands via ATCommand - Java API JSR179 - Transparent via CommConnection - Transparent via ATCommand I personally used two modes: with positions sent by URC - Really easy to setup but the URC can sometimes be missed by the chip. You might miss some position if you choose short period URC (every 2 seconds or less). This will be ok if you dont need real-time tracking. CommConnection - This is a little bit more complex because it requires parsing NMEA-0183. But with it you can have some real-time tracking (meaning you wont lose any data coming from the chip) and extract some other data.
ATCommand
4.15.1 CommConnection with NMEA parsing I wont get into the details because parsing NMEA needs a complete parsing library (I built my own), you need to: Get each line from the CommConnection with your own BufferedReader (see 10.1.4). - 21 -
TC65Dev Florent Clairambault Webingenia v168 6 September 2011 Parse each line using the NMEA-0183 protocol Create a position object from the parsed NMEA sentences
4.15.2 URC with Position parsing You need to create a class implementing the ATCommandListener interface and send to the ATCommand class that you will connect to the following commands :
AT^SGPSS=1,0 AT^SGPSP=5
Then you will receive in your ATCommandListener class some events like this :
2008/09/28,13:14:27,48.8438389,N,002.2863598,E,498,000.00,000.00,0
This can be almost parsed as is by splitting the comma separated values. Here is the Position object you could have with the correct ParseXTText that can be used to parse URC string (like the one above):
public class Position { public double lat, /** lon, /** speed, /** alt; /** public long date;
public static Position ParseXTText( String str ) { Position pos = new Position(); String[] spl = Common.strSplit( ',', str ); pos.date = XTDateToTimestamp( spl[ 0 ], spl[ 1 ] ); pos.lat = Double.parseDouble( spl[ 2 ] ); if ( spl[ 3 ].compareTo( "S" ) == 0 ) pos.lat *= -1; pos.lon = Double.parseDouble( spl[ 4 ] ); if ( spl[ 5 ].compareTo( "W" ) == 0 ) pos.lon *= -1; pos.alt = Double.parseDouble( spl[ 6 ] ); pos.speed = Double.parseDouble( spl[ 7 ] ); return pos; } public static long XTDateToTimestamp( String sDate, String sTime ) { int YY = Integer.parseInt( sDate.substring( 0, 4 ) ), MM = Integer.parseInt( sDate.substring( 5, 7 ) ), DD = Integer.parseInt( sDate.substring( 8, 10 ) ), hh = Integer.parseInt( sTime.substring( 0, 2 ) ), mm = Integer.parseInt( sTime.substring( 3, 5 ) ), ss = Integer.parseInt( sTime.substring( 6, 8 ) ); java.util.Calendar cal = new CalendarImpl(); cal.set( java.util.Calendar.DAY_OF_MONTH, DD ); cal.set( java.util.Calendar.MONTH, MM - 1 );
- 22 -
4.17 Watchdog
From Wikipedia: A watchdog timer is a computer hardware or software timer that triggers a system reset if the main program, due to some fault condition, such as a hang, neglects to regularly service the watchdog (writing a "service pulse" to it, also referred to as "kicking the dog"). The intention is to bring the system back from the nonresponsive state into normal operation. The watchdog was brought with the TC65 v3 firmware (available on the TC65 v2 hardware). Before, it was possible to use it through an unofficial piece of code described in 10.1.6 Watchdog on a TC65 v2. It must be configured by an AT command. It is recommended to set it to restart mode:
AT^SCFG="Userware/Watchdog","1"
And then, within your java code, you will use the com.siemens.icm.misc.Watchdog class to use it. Lets say we want to do a watchdog code. We will start from the Core thread class of 4.2 Type some code:
public class Watchdog implements Runnable { private Thread _thread = new Thread( this, "watchdog" ); private boolean _loop;
- 23 -
public void start() { Watchdog.start( 60 ); _loop = true; _thread.start(); } public void stop() { _loop = false; _thread.join(); } public boolean checkProgramState() { return true; // This is where you should check that your program // is working fine } public void run() { while (_loop) { try { System.out.println("Watchdog still running..."); if ( checkProgramState ) Watchdog.kick(); Thread.sleep(30000); } catch (Exception ex) { System.err.println("Exception " + ex.getClass() + " : " + ex.getMessage()); } } } }
In every program where I implement the M2MP protocol, in the checkProgramState method, one of the things my programs usually check is if the last data received from the server was less than 30 minutes ago.
4.18 Date
What is this to write about the date management on the TC65/TC65i? Well theres something you should know and that might surprise you. The TC66 internal clock isnt synchronized with the JVM clock. The java clock is synchronized with the internal clock at startup and then they go separate ways. You cant change the JVM clock and the TC65/TC65i clock (AT+CCLK command) doesnt have any effect on the JVM clock. So what can you do about that? You can restart the chip everytime you need to change your java clock You can use the internal clock everytime you need it. That way you only use one clock. This requires you to parse the result of the AT+CCLK command. It will be quite slow due to the ATCommand usage and the string parsing. You can define an offset between the real time and the JVM clock. This is by far the best solution it is fast and it allows to resync your clock anytime you want.
- 24 -
TC65Dev Florent Clairambault Webingenia v168 6 September 2011 This is how you can set the offset from a simple time server:
long timeOffset_;
5 Upstream communication
5.1 Introduction
This is the key point of this chip. Its a machine to machine chip, its supposed to exchange with the world through a server or other chips. But on most of the M2M projects, this aspect is looked over and they use an inefficient way of reporting data to their organization.
5.2 SMS
SMS is simple, quite reliable, two-way but inefficient.
- 25 -
5.3 HTTP
The HTTP protocol is the most used because its easy to setup both on the client and the server side. But this protocol consumes a lot of bandwidth and doesnt allow two way communication unless you implement some http comet (this is what is used by long-polling ajax website like gmail chat or facebook chat).
6 Libraries
6.1 Why
Libraries can be used in some situations: You want to have a set of shared classes among some projects You can sell classes without having to give their sources Since the TC65i, you download separately the libraries (liblet) and the main midlet to avoid downloading too much data at each program update
- 26 -
TC65Dev Florent Clairambault Webingenia v168 6 September 2011 You create a new project. This one has to be a mobile class library
You choose a name for your library. In our case we choose com.webingenia.demolib.
- 27 -
TC65Dev Florent Clairambault Webingenia v168 6 September 2011 Then you can create a package within your project. In our case we just created com.webingenia.demolib. And you should add at least one class. We called ours DemoClass. Our DemoClass object wont be too complex:
package com.webingenia.demolib; public class DemoClass { private final String _companyName = "Webingenia"; private String ourCompanyName() { return _companyName; } /** * Get the company name * @return Name of the company */ public String getCompany() { return ourCompanyName(); } }
You should know that the library can be: Compressed Obfuscated up to level 8 Optimized
Then we can load our previous project com.webingenia.com and its jar file:
- 28 -
If you now want to use the DemoClass of the library, you just need to type in the file where you will use it the following code:
import com.webingenia.demolib.DemoClass;
This is the basics but you can do anything you want with your library. Nothing prevents you from creating threads, allocating ATCommand or opening sockets within the scope of your library.
TC65Dev Florent Clairambault Webingenia v168 6 September 2011 WARNING: As described in the FAQ, if you restart the chip when the destroyApp is called, the OTAP SMS method wont work because your chip will restart when the update process will begin. If you are in this situation, you can still save the day: You launch two updates, one to restart the chip (and leave your programs) and one when your chip is restarting so that the SMS OTAP is executed before your program runs. If you made the (wrong) choice of defining the setting Userware/Autostart/Delay to 0, you might be totally stuck.
You need to change the deployment instance or create a new one so that it actually uploads to your server:
- 30 -
So here I selected the webingenia.com FTP server with user www and choose to upload in the /hello directory. Then you need to go into the Application Descriptor category and select the address of your server:
So here the target server address is http://webingenia.com:8080/hello/, the ${dist.jar} parameter will be replaced by the name of your jar file.
- 31 -
7.4 Deploying
This is the simple part, you right-click on your project and select deploy.
And the jar file has to have the same size as dscribed in the jad file:
-rw-r--r-- 1 www www-data 285 jun -rw-r--r-- 1 www www-data 2051 jun 5 17:26 HelloSample.jad 5 17:26 HelloSample.jar
- 32 -
TC65Dev Florent Clairambault Webingenia v168 6 September 2011 Please note that the OTAP parameters are stored in memory. They cant be overridden by an OTAP SMS.
This is what you will get: (The lines I sent are in bold)
AT^SJOTAP=,http://webingenia.com:8080/hello/HelloSample.jad,a:,,,gprs,m2minternet,, ,,, OK AT^SJOTAP OK AT^SCFG="Trace/Syslog/OTAP","1" SYSLOG ENABLED [OTAP] GPRS connection established. [OTAP] Try to get http://webingenia.com:8080/hello/HelloSample.jad ... [OTAP] Connected. [OTAP] Transfer finished. [OTAP] Try to get http://webingenia.com:8080/hello/HelloSample.jar ... [OTAP] Connected. [OTAP] Transfer finished. [OTAP] JAM status: 900 Success. [OTAP] Reboot now. ^SYSSTART
- 33 -
And you even have an integrated update message generator in Message / Build TC65 Update Message:
You should take care of the security of your update process. I dont recommend you setup a specific URL address as it could change (can you really predict how will be your IT infrastructure in 5 years?). But you should definitely setup a password. A password should be used to update with OTA (SMS Authentication) Parameters should be set to fixed values (AT^SJOTAP) whenever possible so that they cannot be changed over the air. The HTTP server should be secure. (e.g. Access control via basic authentication).
You should note that you can debug SMS launched OTAP the same way you can debug AT Command launched OTAP. You just need to activate the OTAP logging on the chip because you send it some SMS.
- 34 -
The state of the variable like Logger.E_VERBOSE is defined by the value of Logger.loggingLevel, it will be set to true if Logger.loggingLevel is superior or equal to 4. These variables have the final keyword; it means they cannot be changed at runtime. So when you change the loggingLevel, you change the state of Logger.E_VERBOSE. The java compiler knows if the code that follows the condition on if( Logger.E_VERBOSE) will ever be executed or not. If you have activated the optimizations, the compiler will NOT add the code that will never be executed. It means that you program will weigh less, contain less debugging information and run faster.
- 35 -
TC65Dev Florent Clairambault Webingenia v168 6 September 2011 Lets say I want to create a version of my library with a reduced logging level. I will create a new Configuration for the project:
So, I know will override some (but only SOME) of the settings of my DefaultConfiguration project. I will leave most of the options to the DefaultConfiguration ones by keeping the Use Values from DefaultConfiguration option checked. Most of them except the Compiling tab where I will change the debug block level from debug to warn and the creating jar where I will change the JAD and JAR file name by appending a _warn at the end of their name.
You could for example make an automated build of your code in 4 different versions: one for each of your project configuration, which actually are each of your chips and deploy them at the same time. I can now make some specific code, like:
/** Build logging level */ public static final int buildLoggingLevel = //#if DefaultConfiguration E_DEBUG; //#elif LoggerLevelWarning //# E_NOTICE; //#endif
If I change the configuraton to LoggerLevelWarning, this code will automatically switch to:
/** Build logging level */ public static final int buildLoggingLevel = //#if DefaultConfiguration //# E_DEBUG; //#elif LoggerLevelWarning E_NOTICE; //#endif
- 36 -
TC65Dev Florent Clairambault Webingenia v168 6 September 2011 You could also have written it like that:
/** Build logging level */ public static final int buildLoggingLevel = //#if DebugLevel=="debug" E_DEBUG; //#elif DebugLevel=="warn" //# E_NOTICE; //#endif
One very interesting pre-processing command is the #debug warn, #mdebug warn, #enddebug warn. But it doesnt support else conditions. So it cant be used everywhere. For more details on how to use the pre-processor on J2ME, you should read this page: http://antenna.sourceforge.net/wtkpreprocess.php And the best part is that you can automatically deploy your two configurations using the batch deploy right-click menu. If you chose to deploy it using FTP, you will actually deploy the two jars with their jad files automatically.
- 37 -
TC65Dev Florent Clairambault Webingenia v168 6 September 2011 8.3.4 EGS5 With the EGS5, Cinterion decided to switch the namespaces of all the classes to com.siemens to com.cinterion. This mean you have almost no effort to port it but you cant EASILY make the same program work on both platforms. If you really wanted to do that, I guess you could create a base class with two implementations, one that use some com.siemens namespace classes and one that use the com.cinterion namespaces classes. But you would have to rewrite one base class and two proxy classes for each class of the TC65is SDK. Thats a LOT of stupid work to do. If you are faced with this situation, I would recommend using the preprocessor to create a chip specific import code. You could add the sdkns (like SDK Namespace) capacity, and create a project configuration with siemens value and the other with the cinterion value. Then it would look like that:
//#if sdkns=="siemens" import com.siemens.icm.io.ATCommandListener; //#elif sdkns=="cinterion" //# import com.cinterion.io.ATCommandListener; //#endif
8.5 Obfuscating
8.5.1 Why When you upload a program into a TC65 chip, it wont be possible to download the .jar file. In fact any directory of file ending with .jar wont be accessible from java code or external interface. In the Java User Guide, you can read this: The copy protection rules for Java applications prevent opening, reading, copying, moving or renaming of JAR files. It is not recommended that the name of a Java application (for example <name>.jar) be used for a directory, since the copy protection will refuse access to open, copy or rename such directories.
- 38 -
TC65Dev Florent Clairambault Webingenia v168 6 September 2011 So you dont need to obfuscate programs that will be deployed only once. When you want to upgrade the program of your chips, you need to make it available. Somehow, someone could have access to your (compiled) program. That means that they could easily decompile and reuse your code as their own. I wanted to add support for a tracking program on the Globalsat TR-102. I used an update the company gave and their site and it took me something like two days to fully understand and actually port my program to their Figure 3 : Choosing obfuscation level hardware. You can choose the obfuscation level in your project properties in the Build / Obfuscating category. The obfuscation level can be between 0 (no obfuscation) and 9 (full obfuscation). I recommend you set 0 for debugging & tests and 9 for production. If you decide to build libraries for the TC65i, you should not set it to more than 8, because beyond that point every public classes except Midlets are renamed. 8.5.2 Without obfuscation The code below is too simple to make a good example of code obfuscation. But still, it will show you how easily code can be extracted from your .jar files. So here is the main code of the first Midlet we built :
public class Core implements Runnable { private Thread _thread = new Thread( this, "core" ); private boolean _loop; public void start() { _loop = true; _thread.start(); } public void stop() { _loop = false; } public void run() { while (_loop) { try { Thread.sleep(1000); System.out.println("Main code running..."); } catch (Exception ex) { System.err.println("Exception " + ex.getClass() + " : " + ex.getMessage()); } } } }
- 39 -
TC65Dev Florent Clairambault Webingenia v168 6 September 2011 We take the very good JD (Java Decompiler) available here: http://java.decompiler.free.fr/ to decompile the code and we get:
public class Core implements Runnable { private Thread _thread; private boolean _loop; public Core() { this._thread = new Thread(this, "core"); } public void start() { this._loop = true; this._thread.start(); } public void stop() { this._loop = false; } public void run() { while (this._loop) { try { Thread.sleep(1000L); System.out.println("Main code running..."); } catch (Exception ex) { System.err.println("Exception " + ex.getClass() + " : " + ex.getMessage()); } } } }
Well, what do you think about that? Private variable are initialized in the constructor, they are all appended by this. But other than that, your code is exactly the same. Now, if we obfuscate, we get that:
public final class a implements Runnable { private Thread jdField_a_of_type_JavaLangThread = new Thread(this, "core"); private boolean jdField_a_of_type_Boolean; public final void a() { this.jdField_a_of_type_Boolean = true; this.jdField_a_of_type_JavaLangThread.start(); } public final void b() { this.jdField_a_of_type_Boolean = false; } public final void run() { while (this.jdField_a_of_type_Boolean)
- 40 -
Here we have a very simple 30 lines code and its getting quite hard to read. Imagine what it would be with any project containing 400 lines of code. And most of the projects contain a lot more than that. 8.5.3 Make your own kind of obfuscation Still, if you want to protect how you will handle GPIO, pulse counter or serial port, this wont be enough. You need to add some lines of dumb code that look like the real code. User searching for GPIO AT commands wont be able to find the right one.
TC65Dev Florent Clairambault Webingenia v168 6 September 2011 But most of the times you wont in fact execute more than one a thread in the same time. Most of the time, you need to create thread to handle slow or even blocking I/O operations. Multithreading, and particularly in java, isnt complex. You have to think how your programs will behave when doing two (or more) things in the same time and how you want these threads to communicate. You can see an example of basic asynchronous request sending in 0. To understand the code you basically need to see where the communication on the two threads is done. You should try to lock as few objects as possible. 8.6.5 Network stack The network stack of the TC65 is quite basic. In a TCP connection, the TC65 waits for the acknowledge packet of the last data packet sent before sending the next one. This simplifies the network implementation and reduces the stack memory footprint. This mean that the minimum time between two packets of information is the time it takes to send a data packet and receive its acknowledge packet. 8.6.6 I/O Blocking or not? For all the sources you can open an input stream from, you can choose if they are blocking or not. If you open your source (say a CommConnection as seen in 4.12) in blocking mode, each time you request a character that is not yet available, your thread will be blocked. You can avoid being blocked by using the InputStream::available method to check if there are some bytes to read.
If that happens, your device is bricked. My guess is the perfect way to destroy your NVRAM is to change your settings often and to restart often (like more than once a day). So just dont do it.
- 42 -
- 43 -
10 BONUS
10.1 Sample code
10.1.1 Logging class
/** * Logging class * @author Florent Clairambault / www.webingenia.com */ public class Logger { // This dirty code has a purpose, it allows compile time optimization // jar file size depends on these options /** Logging level */ public static final int loggingLevel = 3; /** Shows everything */ public static final boolean E_DEBUG = (loggingLevel >= 5); /** Shows verbose logging */ public static final boolean E_VERBOSE = (loggingLevel >= 4); /** Shows notice logging */ public static final boolean E_NOTICE = (loggingLevel >= 3); /** Shows warning logging */ public static final boolean E_WARNING = (loggingLevel >= 2); /** Shows critical logging */ public static final boolean E_CRITICAL = (loggingLevel >= 1); /** * Logs anything * @param str String sent to logging */ public static void log( String str ) { synchronized ( System.out ) { System.out.println( Thread.currentThread().getName() + " : " + str ); } } /** * Logs exception * @param str String sent to logging * @param ex Exception caught */ public static void log( String str, Exception ex ) { log( str + " ex : " + ex.getClass() + " : " + ex.getMessage()
);
// If we have an exception thrown in loop, we prefer that it doesn't slows down // the other threads Thread.yield(); } }
- 44 -
private final String _webUrl = "http://test.webingenia.com/asyncHttpRequest"; private Vector _queue = new Vector(); private Thread _thread = new Thread(this, "AsyncHttpThread"); public AsyncHttpRequests() { // We want this thread to run in the lowest priority possible _thread.setPriority(Thread.MIN_PRIORITY); _thread.start(); } public void run() { String data = null; // This is the data we will get from the queue try { synchronized (_queue) { // We need to make sure we won't try { // While there's nothing to send while (_queue != null && _queue.size() == 0) { // We put the thread on hold _queue.wait(); } data = (String) _queue.firstElement(); } catch (InterruptedException ex) { ex.printStackTrace(); } } // We're sending the main data if (sendData(data)) { synchronized (_queue) { // We lock the queue to remove one of its elements _queue.removeElement(data); } } else { Thread.sleep(2000); } } catch (Exception ex) { ex.printStackTrace(); } } /** * Adds some data * @param data Data to add */ public void addData(String data) { synchronized (_queue) { _queue.addElement(data); _queue.notify(); } } private boolean sendData(String data) { return (httpPost(_webUrl, data.getBytes()) != null); }
- 45 -
If you want your code to actually work, you need to add these methods:
/** * Send some data by posting them * @param url Url to send the data * @param data Content of the POST data * @return data returned */ private static String httpPost(String url, byte[] data) { if (data == null) { data = new byte[0]; } HttpConnection conn = null; InputStream is = null; OutputStream os = null; try { // Test HTTP connection // We prepare the POST request conn = (HttpConnection) Connector.open(url); conn.setRequestMethod(HttpConnection.POST); conn.setRequestProperty("Content-Type", "application/x-www-formurlencoded"); os = conn.openOutputStream(); os.write(data); // We display the generated content return inputStreamReadToEnd(conn.openInputStream()); } catch (Exception ex) { ex.printStackTrace(); return null; } // Whatever happens, we close everything finally { try { if (is != null) { is.close(); } if (os != null) { os.close(); } if (conn != null) { conn.close(); } } catch (Exception ex) { if (Logger.E_CRITICAL) { Logger.Log(36830, "Common.httpPost.2", ex); } } } } private static String inputStreamReadToEnd(InputStream is) throws IOException { StringBuffer sb = new StringBuffer(); int ch; while ((ch = is.read()) != -1) { sb.append((char) ch); }
- 46 -
In case you havent understood how you are supposed to use this class, well here is who we do it :
AsyncHttpRequests sender = sender.addData(toto); // // sender.addData(tata); // sender.addData(titi); // // new AsyncHttpRequests() ; Were queuing data, and wakinup the thread but nothing is blocking us Were adding some data to the queue Were still adding some data to the queue The senders thread will continue its work
- 47 -
10.1.4 BufferedReader
/** * Cheap implementation of an ASCII stream reader * @author Florent Clairambault / www.webingenia.com */ public class BufferedReader { InputStream _is; public BufferedReader(InputStream is) { _is = is; } private StringBuffer _buffer = new StringBuffer(); public String readLine() { int i; char c; try { while ( (i = _is.read()) != -1 ) { c = (char) i; if ( c == '\n' || c == '\r' ) { String str = _buffer.toString(); _buffer.setLength(0); return str; } else _buffer.append( c ); } } catch (IOException ex) { ex.printStackTrace(); } return null; }
- 48 -
10.1.6 Watchdog on a TC65 v2 In TC65 v2, there was a way to activate the watchdog and it is explained here, but it is officially supported by Cinterion. Here is the code:
private void configureHardwareWatchDog( final boolean active ) { ATCommand cmd = null; OutputStream os = null; InputStream is = null; try { cmd = new ATCommand( false ); Logger.log( "configureHardwareWatchDog", cmd.send( "AT^SSPI=0000,A000,A000\r" ) ); os = cmd.getDataOutputStream(); is = cmd.getDataInputStream(); if ( active ) { os.write( "<a200102050078001E>".getBytes() ); } else { os.write( "<a200102000078001E>".getBytes() ); } os.flush(); Thread.sleep( 50 ); os.write( "<a200202>".getBytes() ); os.flush(); Thread.sleep( 50 ); os.write( "#".getBytes() ); // Read the response. final byte[] buff = new byte[100]; byte length = 0; int ch = is.read(); while ( ch > 0 ) { buff[length] = (byte) ch; length++; ch = is.read(); } Logger.log( "configureHardwareWatchDog", new String( buff, 0, length ) ); } catch ( final Throwable t ) { Logger.log( "configureHardwareWatchDog", "Unexpected error: " + t ); } finally { if ( os != null ) { try { // According to the documentation, closing the output // stream doesn't have any real effect. // But this might change in the future, so closing it // doesn't hurt. os.close(); os = null; } catch ( final IOException ignored ) { // Ignore this exception. } } if ( is != null ) { try {
- 49 -
If you feel like the one and two bytes sized messages are useless, you can freely only implement the four bytes sized messages. 10.2.2 Why is it working like that? The world changed with Googles bigdata paradigm. Google managed to create incredibly great applications with a new kind of database: Every table contained only one key and an unlimited number of columns for each key. I think its one of the challenges of all software architecture, keeping a simple basis that will allow you to evolve and managed thousands of devices around many projects without any problem. If you think about it, the M2MP protocol is quite similar; you can send messages that are in the form of:
String channelName, Byte[] value or String channelName, Byte[][] value
- 50 -
TC65Dev Florent Clairambault Webingenia v168 6 September 2011 With that basis, you can send any message. Here are some samples. 10.2.2.1 Low level (best one) This is the best way to handle things; you can save bandwidth and easily manage your data. To send that the GPIO 5 changed to 1, you could either send:
send( gpio:10, new byte[] { 1 } );
or
send( gpio, new byte[] { 10, 1 } );
or
send( gpio, new byte[] { 5 + (1 << 7) } );
It pretty much doesnt matter, you have many ways to encode this. I would advice you to choose the first solution as it is very easy to parse as string. And as the channel name doesnt change. 10.2.2.2 Simple text
send( gpio:10, new byte[] { 1 } );
or
send(gpio, new byte[][] { 10.getBytes(), 1.getBytes() });
10.2.2.3 Encapsulation You can encapsulate any other format, like JSON. Instead of making JSON request and getting JSON response. You could have a bidirectional JSON protocol
void sendJson( JSONObject json ) { StringWriter sw = new StringWriter(); JSONWriter writer = new JSONWriter(sw); this.toJSONWriter(writer); jsonStr = sw.toString(); send(json, jsonStr.getBytes() ); }
You can do exactly the same thing with XML as you can guess. 10.2.2.4 Relaying messages Nothing prevents you from relaying all the data to another input stream, like a serial connection. 10.2.3 Specifications These are the specifications: Identification The client sends its name: 1 [ 1 ] { 0x01 } // Identification request header 2 [ 1 ] { 0x05 } // Size of the identification 3 [ 5 ] { 't', 'r', '1', '2', '3' } // Identifier - 51 -
TC65Dev Florent Clairambault Webingenia v168 6 September 2011 The server replies ok or not ok 1 [ 1 ] { 0x01 } // Identification response 2 [ 1 ] { 0x01 } // 0x01 for OK, 0x00 for not ok Ping / Keep alive Client sends a ping request: 1 [ 1 ] { 0x02 } // client ping request header 2 [ 1 ] { 0x15 } // the number (here 0x15) can be incremented or random Server answers the ping request: 1 [ 1 ] { 0x02 } // client ping server response header 2 [ 1 ] { 0x15 } // where 0x15 is the number of the ping request Server sends a ping request: 1 [ 1 ] { 0x03 } // server ping request header 2 [ 1 ] { 0x16 } // the number (here 0x16) can be incremented or random Client answers the ping request: 1 [ 1 ] { 0x03 } // server ping client response header 2 [ 1 ] { 0x16 } // where 0x16 is the 0x16 number of the ping request Defining a named channel This applies to both client to server and server to client communication. 1 2 3 4 [ 1 ] { 0x20 } // channel definition frame header [ 1 ] { 0x0D } // where 13 is the size of the following message [ 1 ] { 0x03 } // where 3 is the id of the channel [ 12 ] { 'c', 'h', 'a', 'n', 'n', 'e', 'l', ' ', 'n', 'a', 'm', 'e' } // the name of the channel : "channel name"
Sending some data This applies to both client to server and server to client communication. For 0 to 254 sized messages: 1 2 3 4 [ 1 ] { 0x21 } // one byte sized data transmission frame header [ 1 ] { 0x06 } // size of the data [ 1 ] { 0x03 } // where 3 is the id of the channel [ 5 ] { 0x01, 0x02, 0x03, 0x04, 0x05 } // data transmitted on the channel
For 255 to 65534 sized data messages: 1 2 3 4 [ 1 ] { 0x41 } // two bytes sized data transmission frame header [ 2 ] { 0x00, 0x06 } // size of the data [ 1 ] { 0x03 } // where 3 is the id of the channel [ 5 ] { 0x01, 0x02, 0x03, 0x04, 0x05 } // data transmitted on the channel
- 52 -
TC65Dev Florent Clairambault Webingenia v168 6 September 2011 For 65 535 octets to 4 294 967 294 sized data messages: 1 2 3 4 [ 1 ] { 0x61 } // four bytes sized data transmission frame header [ 4 ] { 0x00, 0x00, 0x00, 0x06 } // size of the data [ 1 ] { 0x03 } // where 3 is the id of the channel [ 5 ] { 0x01, 0x02, 0x03, 0x04, 0x05 } // data transmitted on the channel
For data array transmission, its the same except frame header are 022, 042, 062 instead of 021, 041, 061. If you transmit data array like this one Byte[][] data = { { 001, 002 }, { 003, 004, 005 }, { 006, 007, 008, 009 } } : 1 2 3 4 5 6 7 8 9 [ 1 ] { 0x22 } // one byte sized data transmission frame header [ 1 ] { 0x0D } // size of the data [ 1 ] { 0x03 } // where 3 is the id of the channel [ 1 ] { 0x02 } // size of the first array [ 2 ] { 0x01, 0x02 } [ 1 ] { 0x03 } // size of the second array [ 3 ] { 0x03, 0x04, 0x05 } [ 1 ] { 0x04 } // size of the third array [ 4 ] { 0x06, 0x07, 0x08, 0x09 }
For bigger arrays, you need to define: 1 2 3 4 5 6 7 8 9 [ 1 ] { 0x42 } // two bytes sized data transmission frame header [ 1 ] { 0x10 } // size of the data (16) [ 1 ] { 0x03 } // where 3 is the id of the channel [ 2 ] { 0x00, 0x02 } // size of the first array [ 2 ] { 0x01, 0x02 } [ 2 ] { 0x00, 0x03 } // size of the second array [ 3 ] { 0x03, 0x04, 0x05 } [ 2 ] { 0x00, 0x04 } // size of the third array [ 4 ] { 0x06, 0x07, 0x08, 0x09 }
And so on: 1 2 3 4 5 6 7 8 9 [ 1 ] { 0x62 } // four bytes sized data transmission frame header [ 1 ] { 0x16 } // size of the data (22) [ 1 ] { 0x03 } // where 3 is the id of the channel [ 4 ] { 0x00, 0x00, 0x00, 0x02 } // size of the first array [ 2 ] { 0x01, 0x02 } [ 4 ] { 0x00, 0x00, 0x00, 0x03 } // size of the second array [ 3 ] { 0x03, 0x04, 0x05 } [ 4 ] { 0x00, 0x00, 0x00, 0x04 } // size of the third array [ 4 ] { 0x06, 0x07, 0x08, 0x09 }
11 FAQ
These are all the questions that you might ask yourself. This is just a copy/past/format of my blog.
Where can I find technical support for the TC65? You have to ask your TC65 supplier. It will redirect you to a company in charge in your region.
- 53 -
Do you offer support / development services ? Yes through my company. Can i use a GPRS connection with both a running java program and my PC ? No. The chip either does java or modem. You could eventually simulate a modem within a java app. But I doubt that it would be very useful.
How can I upgrade a program remotly? You can: - Execute an AT^SJOTAP command triggered by an SMS, a network command or any special event you want - Send an OTAP SMS. This will launch the update on any chip you want. You can do that by using my little software and another GPRS modem.
Can I prevent the chip from shutting down and not waking up ? This problem of the chip shutting down with the ^SHUTDOWN URC and not waking up is a big one but I think it only occurs on TC65 v1 chips. Some people send a restart command in the destroyApp method. It has the obvious drawback of preventing the chip of being remotly upgraded. In fact you CAN upgrade your program even with this fix. You have to set your chip to wait for the maximum time before program starts (AT^SCFG=Userware/Autostart/Delay,250 ie 25 seconds) at startup. You make the chip restart with a first OTAP SMS (or any other restart command) and then send an other OTAP SMS within this 25 seconds restart time.
1 ^EXIT 00010000,008e504c4b4d4552522c353030333a306334303a65303130204d6f6e61636f3a2053504f5254733a204
Like most of these errors, it only means something to some few people within Cinterion (Siemens). Its a know issue with the first version of the v3.0 firmware. You should flash your chip.
I have this error: This one comes from Marcin Mazurek on a TC65i
- 54 -
This is likely to be caused by the use of an opened SpiConnection class instance and the GPIO at the same time. You should avoid to use SPI and GPIO at the same time and if youre using a multi-threaded program, you should synchronize the access to these elements.
This can be hex translated to: 1 hist_task.c,10000,abpmmm.c,1272,Mode Manager:Block 2000 NVRAM read failure or Data corrupt
It seems your NVRAM (and your TC65 chip) is out of order. You might have changed too many times some settings with the AT^SCFG command.
Debugging on TC65 doesnt work First of all, make sure you debug with the tools intended for your chip. Debugging might not work or work weirdly (no variable state visible for instance) with incompatible versions. You also have to make sure the remote debugging connection works fine. Everytime you change something in your configuration, make sure to use Cinterion (or Siemens) setup utility to repair the debugging connection.
How can I get a .jar file from the TC65 You cant. As you may not know, jar files can be very easily decompiled and even obfuscated reveal the logic of your chip. This is a very basic and powerful way to prevent your software from being reverse-engineered. You can upload jar file on the chip but never download jar file from the TC65.
Can we save a lot of data on the chip ? I has 1.7 MB of memory. Chances are you are only using 5 to 100 kB for your java code. So it enables you to save a lot of data. Note : I have never been faced wit this problem but the memory used by the TC65 chip is limited to approximatively 100 000 read/writes. So you should avoid to write things too often. What you can and you should save are settings required to communicate with the chip.
Can we use an SD-Card or any kind of flash storage system with the TC65 ? In the SDK documentation, the AN_17_FOTA.pdf file describes this. You have to use an Flash storage system connected to the SPI port. It is in this document related to the Firmware Over The Air update process, but you can use it for anything else.
Why cant I use the TC65 or/and AT commands when a program is launched ? The TC65 can act in two modes : Modem or software execution. In modem, it supports AT commands on any port (ASC0, ASC1, USB). In software execution mode, all the ports (ASC0, ASC1, USB) can only be used for communications. In this mode, you execute AT commands within your software, using the ATCommand class.
Why is MES not working ? Its very likely that is for one of these reasons : - You didnt set a fixed baudrate (at+ipr=115200 for 115200 bps for instance)
- 55 -
Can I use a serial over USB converter ? Yes, but for transfers, you need MES to work. The only serial over USB converter that are proven to work are the ones embedding an FTDI chip. I also have an other converter, based on a CP210x chip, it wont work for transfers.
I have the TC65 but my supplier didnt give me the SDK. What should I do ? This happens a lot. Some suppliers dont even know that the TC65 can be programmed in java. You can ask them (because they are the one supposed to give it) or download it here.
Can I make my developments on a Linux hosts ? Not officially but you can. Someone made a page on TC65 Development on a Linux host about this. Ive never tested it thought. Ricardo also gave some programs and files to use MES on Linux on the javacint group files (I havent tested it).
o o
In AT Commands : Socket, FTP, HTTP, POP3, SMTP In Java environment : Socket, SSL, HTTP/HTTPS, UDP
If you need FTP, you cant do it in java directly unless you implement the FTP protocol in your code.
How can we make the chip go in sleep mode ? For the chip to be able to sleep, you have to make all your threads die, sleep or wait for an I/O to be performed. The chip really goes in sleep mode 30 seconds after everything is ready to make it sleep.
How can we save settings on the TC65 ? The best way is to save your parameters in a file using a settings abstraction class. Ive seen people saving parameters in the SIM Card, its very constrictive and you lose everything when you need to change the SIM card. I think this is totally useless.
How are we supposed to manage the life programs lifecycle ? Behind the wheels, the JVM will load your jar file, uncompress id, load the main class, instantiate it and - The midlets starts in the startApp method and it should let the startApp call end by creating a new thread. - When the destroyApp method is called by the system, you have 5 seconds to close everything and call notifyDestroyed. If you dont, your program will quit and it will display a warning on the console. - The pauseApp method (and its notifyPaused linked method) are optionnal. In the TC65, Ive never seen them being used. But I dont know everything. Keeping the programs loop in the startApp method is wrong. It creates update problems because the destroyApp method is called when the startApp method is still running. Letting the startApp method call finish is a good thing. Creating new threads is not a requirements, you could handle everything through URC and ATCommandListener.
- 56 -
The OTAP process is working fine but how can I remotely enable the AutoStart on brand new TC65 chips ? I havent figured this out yet. Im not sure there is a solution. I personally built a little program that check for new TC65 chip presence on the serial ports and setup them. This isnt much of a problem thought because I like to detect & test the chips on a PC to identify it.
How can I identify each chip ? You can identify each chip with the AT+GSN AT command. you can identify its SIM card with the the AT+CIMI AT command.
Is there any recommendation around the use of files with the TC65 flash memory storage ? The flash memory is approximately limited to 100 000 R/W cycles. You should save data in RAM memory as much as possible. But when absolutely required, you can still write things on flash storage. There are no official specifications on how the flash storage is managed. The worst case scenario would be: Lets say you save a tiny file (less than one block long) each 20 minutes and each file save makes 2 R/W cycles. We get 100 000 / 2 * 20 = 1 000 000 minutes of life. That means 1 000 000 / 60 / 24 = 694 days. That means a little bit less than 2 years. Thats not very long, so this isnt too good. But its quite likely that theres some hardware level wear leveling. Meaning that write operations are dispatched along the the way. If this wear leveling mechanism is used, the same thing would give a lifetime of 100 years to your chip (see discussion 2 for more details). Discussions around the subject: 1, 2
Can we build TC65 programs with Windows Vista or Windows 7 ? Yes but the Module Exchange Suite windows explorer doesnt seem to work with x64 versions. But you can use JObexFTP (from Ricardo Schmidt) if that happens.
Java program starts with the chip, how can I disable it ? When autostart is enabled and the autostart delay is set to 0, you cannot disable the autostart by AT Command. You have to use the Switch Autostart off program given with the TC65 SDK. As described in the Java User Guide document:
Using the graphical autoexec_off.exe tool: 1. Connect the module to the PC 2. Make sure, that the module is switched off 3. Start the Autoexec_Off program 4. Select the COM-Port 5. Press the AutoExec Off button
How can the TC65 switch on automatically as soon as it is powered ? It seems connecting the ignition input (IGT_IN) to the power input works. But the TC65 HW Description file says :
- 57 -
How can we get the source code from a TC65 jar file ? Any java decompiler can do the trick How do we use I2C I2C java API only exists since TC65i. If you need some I2C using AT Command please read the AT Command doc. The SDK documentation on that matter is pretty clear. The documentation even has a pretty simple example, here it is with some comments added : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
/*** Open I2C connection and data streams: ***/ i2cConnection cc = (I2cBusConnection) Connector.open("i2c:0;baudrate=100"); // Bus 0 (ther int baudrate = cc.getBaudRate(); InputStream inStream = cc.openInputStream(); OutputStream outStream = cc.openOutputStream();
/*** Write Transfer Frame, where a = message ID, AE = Slave Address and write request: ***/ String data = "<aAE000102030405060708090A0B0C0E0F>"; outStream.write(data.getBytes(), 0, data.length()); // This is acceptable here (because al can make 2 bytes). outStream.flush();
Read response message: {a+} where a = message ID: byte[] inBuf = new byte[<size>]; if (inStream.available()) int inBufLen = inStream.read(inBuf); // Here, the generated string is in : new String( i // But to get some real code, you have to do some standard InputStream processing // It means basically that you have to wait for the '>' or '}' char ( == byte here) before /* Note that the read method blocks the thread until at least one byte has been read. To avoid blocking infinitely in case the I2C bus does not respond, check please first if there is data available. If the bus sends a big amount of data, the data will be read in pieces and the implementation has to poll until the end of the data. */ /*** Close data streams and connection: ***/ inStream.close(); outStream.close(); cc.close();
How can I protect my source code from being stolen and still distribute jar file ? Activate the compiler optimizations, and set the maximum obfuscation level. Can we use an emulator for the TC65/TC65i ? No you cant, sometimes it is referred to a simulator but in fact it always relies on the chip. You should note that you could potentially emulate the chip by launching the midlet on a J2ME mobile device emulator and recreating all the Cinterions classes. But that wouldnt be very interesting as most of the development work done on the TC65 is around the hardware handling.
How can I get and send back to a server the stack trace of an exception ? You cant directly do it from the java code as the J2ME doesnt allow to export the stack trace
- 58 -
How can I use socket connection ? This is very well explained in the I2CBusConnection class javadoc. This can implemented very quickly, you just have to create an I2C message parser, the most important part being to get the message between the { and the } braces. You could also make it handle the retransmission of unsent I2C messages.
How can I send mail with the TC65 ? As a general architecture pattern, its often more appropriate to use the server as an alerter that will send SMS, mail or anything else depending on the received messages. But still You could use the mail AT commands but that will lead you to some very poor maintainability. If youve already handle some simple text protocol, it will be quite easy to communicate with the SMTP server. This is what it looks like : <--" for received and "--> for sent 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 <---> <---> <---> <---> <---> --> --> --> --> --> <---> <-220 ns301797.ovh.net ESMTP Postfix (Debian/GNU) HELO TC65/toto 250 ns301797.ovh.net MAIL FROM: <[email protected]> 250 2.1.0 Ok RCPT TO: <[email protected]> 250 2.1.5 Ok DATA 354 End data with <CR><LF>.<CR><LF> From: <[email protected]> To: [email protected] Subject: This is a simple mail Here is the content of the mail . 250 2.0.0 Ok: queued as C3C323401B QUIT 221 2.0.0 Bye
If you need to send attachments, this is a little bit more complex but not that much. You need to add some headers to send mail as multipart messages (meaning that it will contain more than one part). And you need to add some Base64 encoding method so that you could put the content of the file you wish to send into a base64 encoded format.
- 59 -