How to handle read data with MCC generated i2c driver? - driver

I'm trying to use new (?) i2c driver for PIC18F45Q10. I don't understand how can I use it without modification. I just want to set my own function with state machine as callback to process incoming bytes.
I'm sending 2 bytes from Linux machine to microcontroller.
i2cset 1 0x12 0x01 0x02
Where:
1 is Linux I2C bus number
0x12 is 7-bit i2c address (my microcontroller)
0x01 is first byte of data
0x02 is second byte of data
My problem is that I2C2_SlaveRdCallBack(); is never being called (because rx buffer is always empty).
I2C configuration in MCC seems to be fine, because when I put a breakpoint at if(I2C2_SlaveIsRxBufFull()) line - it stops there and I see that i2c2RdData variable contains first byte of data. Linux machine can discover my microcontroller with i2cdetect command (i2cdetect sends all possible device addresses and when it receives ACK - it shows device as discovered).
How to use this driver? Is this code supposed to be working, or just some scaffolding / sample?
Main ISR handler from this driver:
static void I2C2_Isr()
{
I2C2_SlaveClearIrq();
// read SSPBUF to clear BF
i2c2RdData = I2C2_SlaveGetRxData(); // <- but there is my first ! (it reads hardware register)
if(I2C2_SlaveIsRead())
{
i2c2State = I2C2_TX;
}
else
{
i2c2State = I2C2_RX;
}
switch(i2c2State)
{
case I2C2_TX:
if(!I2C2_SlaveIsWriteCollision())
{
I2C2_SlaveWrCallBack();
}
else
{
I2C2_SlaveWrColCallBack();
I2C2_SlaveRestart();
}
i2c2NextState = I2C2_ADDR;
break;
case I2C2_RX:
if (I2C2_SlaveIsData()) <-- I have problem here
{
if(I2C2_SlaveIsRxBufFull()) <-- when the buffer is not full
{
I2C2_SlaveRdCallBack(); <-- read callback is not called
}
}
else
{
I2C2_SlaveAddrCallBack();
i2c2NextState = I2C2_ADDR;
}
break;
default:
break;
}
i2c2State = i2c2NextState;
I2C2_SlaveReleaseClock();
}
Full driver code:
/**
I2C2 Generated Driver File
#Company
Microchip Technology Inc.
#File Name
i2c2.c
#Summary
This is the generated driver implementation file for the I2C2 driver using PIC10 / PIC12 / PIC16 / PIC18 MCUs
#Description
This header file provides implementations for driver APIs for I2C2.
Generation Information :
Product Revision : PIC10 / PIC12 / PIC16 / PIC18 MCUs - 1.78.1
Device : PIC18F45Q10
Driver Version : 1.0.0
The generated drivers are tested against the following:
Compiler : XC8 2.10 and above or later
MPLAB : MPLAB X 5.30
*/
/*
(c) 2018 Microchip Technology Inc. and its subsidiaries.
Subject to your compliance with these terms, you may use Microchip software and any
derivatives exclusively with Microchip products. It is your responsibility to comply with third party
license terms applicable to your use of third party software (including open source software) that
may accompany Microchip software.
THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY
IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS
FOR A PARTICULAR PURPOSE.
IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP
HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO
THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL
CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT
OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS
SOFTWARE.
*/
#include "i2c2_slave.h"
#include <xc.h>
#define I2C2_SLAVE_ADDRESS 18
#define I2C2_SLAVE_MASK 127
/**
Section: Global Variables
*/
typedef enum
{
I2C2_ADDR,
I2C2_TX,
I2C2_RX
} i2c2_state_t;
static void I2C2_Isr(void);
static void I2C2_SlaveDefRdInterruptHandler(void);
static void I2C2_SlaveDefWrInterruptHandler(void);
static void I2C2_SlaveDefAddrInterruptHandler(void);
static void I2C2_SlaveDefWrColInterruptHandler(void);
static void I2C2_SlaveDefBusColInterruptHandler(void);
static void I2C2_SlaveRdCallBack(void);
static void I2C2_SlaveWrCallBack(void);
static void I2C2_SlaveAddrCallBack(void);
static void I2C2_SlaveWrColCallBack(void);
static void I2C2_SlaveBusColCallBack(void);
static inline bool I2C2_SlaveOpen();
static inline void I2C2_SlaveClose();
static inline void I2C2_SlaveSetSlaveAddr(uint8_t slaveAddr);
static inline void I2C2_SlaveSetSlaveMask(uint8_t maskAddr);
static inline void I2C2_SlaveEnableIrq(void);
static inline bool I2C2_SlaveIsAddr(void);
static inline bool I2C2_SlaveIsRead(void);
static inline void I2C2_SlaveClearBuff(void);
static inline void I2C2_SlaveClearIrq(void);
static inline void I2C2_SlaveReleaseClock(void);
static inline bool I2C2_SlaveIsWriteCollision(void);
static inline bool I2C2_SlaveIsTxBufEmpty(void);
static inline bool I2C2_SlaveIsData(void);
static inline void I2C2_SlaveRestart(void);
static inline bool I2C2_SlaveIsRxBufFull(void);
static inline void I2C2_SlaveSendTxData(uint8_t data);
static inline uint8_t I2C2_SlaveGetRxData(void);
static inline uint8_t I2C2_SlaveGetAddr(void);
static inline void I2C2_SlaveSendAck(void);
static inline void I2C2_SlaveSendNack(void);
static volatile i2c2_state_t i2c2State = I2C2_ADDR;
static volatile i2c2_state_t i2c2NextState = I2C2_ADDR;
volatile uint8_t i2c2WrData;
volatile uint8_t i2c2RdData;
volatile uint8_t i2c2SlaveAddr;
void I2C2_Initialize()
{
SSP2STAT = 0x40;
SSP2CON1 |= 0x06;
SSP2CON2 = 0x10;
SSP2CON1bits.SSPEN = 0;
}
void I2C2_Open()
{
I2C2_SlaveOpen();
I2C2_SlaveSetSlaveAddr(I2C2_SLAVE_ADDRESS << 1);
I2C2_SlaveSetSlaveMask(I2C2_SLAVE_MASK);
I2C2_SlaveSetIsrHandler(I2C2_Isr);
I2C2_SlaveSetBusColIntHandler(I2C2_SlaveDefBusColInterruptHandler);
I2C2_SlaveSetWriteIntHandler(I2C2_SlaveDefWrInterruptHandler);
I2C2_SlaveSetReadIntHandler(I2C2_SlaveDefRdInterruptHandler);
I2C2_SlaveSetAddrIntHandler(I2C2_SlaveDefAddrInterruptHandler);
I2C2_SlaveSetWrColIntHandler(I2C2_SlaveDefWrColInterruptHandler);
I2C2_SlaveEnableIrq();
}
void I2C2_Close()
{
I2C2_SlaveClose();
}
uint8_t I2C2_Read()
{
return I2C2_SlaveGetRxData();
}
void I2C2_Write(uint8_t data)
{
I2C2_SlaveSendTxData(data);
}
void I2C2_Enable()
{
I2C2_Initialize();
}
void I2C2_SendAck()
{
I2C2_SlaveSendAck();
}
void I2C2_SendNack()
{
I2C2_SlaveSendNack();
}
static void I2C2_Isr()
{
I2C2_SlaveClearIrq();
// read SSPBUF to clear BF
i2c2RdData = I2C2_SlaveGetRxData();
if(I2C2_SlaveIsRead())
{
i2c2State = I2C2_TX;
}
else
{
i2c2State = I2C2_RX;
}
switch(i2c2State)
{
case I2C2_TX:
if(!I2C2_SlaveIsWriteCollision())
{
I2C2_SlaveWrCallBack();
}
else
{
I2C2_SlaveWrColCallBack();
I2C2_SlaveRestart();
}
i2c2NextState = I2C2_ADDR;
break;
case I2C2_RX:
if (I2C2_SlaveIsData())
{
if(I2C2_SlaveIsRxBufFull())
{
I2C2_SlaveRdCallBack();
}
}
else
{
I2C2_SlaveAddrCallBack();
i2c2NextState = I2C2_ADDR;
}
break;
default:
break;
}
i2c2State = i2c2NextState;
I2C2_SlaveReleaseClock();
}
// Common Event Interrupt Handlers
void I2C2_SlaveSetIsrHandler(interruptHandler handler)
{
MSSP2_InterruptHandler = handler;
}
// Read Event Interrupt Handlers
void I2C2_SlaveSetReadIntHandler(interruptHandler handler) {
I2C2_SlaveRdInterruptHandler = handler;
}
static void I2C2_SlaveRdCallBack() {
// Add your custom callback code here
if (I2C2_SlaveRdInterruptHandler)
{
I2C2_SlaveRdInterruptHandler();
}
}
static void I2C2_SlaveDefRdInterruptHandler() {
i2c2RdData = I2C2_SlaveGetRxData();
}
// Write Event Interrupt Handlers
void I2C2_SlaveSetWriteIntHandler(interruptHandler handler) {
I2C2_SlaveWrInterruptHandler = handler;
}
static void I2C2_SlaveWrCallBack() {
// Add your custom callback code here
if (I2C2_SlaveWrInterruptHandler)
{
I2C2_SlaveWrInterruptHandler();
}
}
static void I2C2_SlaveDefWrInterruptHandler() {
I2C2_SlaveSendTxData(i2c2WrData);
}
// ADDRESS Event Interrupt Handlers
void I2C2_SlaveSetAddrIntHandler(interruptHandler handler){
I2C2_SlaveAddrInterruptHandler = handler;
}
static void I2C2_SlaveAddrCallBack() {
// Add your custom callback code here
if (I2C2_SlaveAddrInterruptHandler) {
I2C2_SlaveAddrInterruptHandler();
}
}
static void I2C2_SlaveDefAddrInterruptHandler() {
i2c2SlaveAddr = I2C2_SlaveGetAddr();
}
// Write Collision Event Interrupt Handlers
void I2C2_SlaveSetWrColIntHandler(interruptHandler handler){
I2C2_SlaveWrColInterruptHandler = handler;
}
static void I2C2_SlaveWrColCallBack() {
// Add your custom callback code here
if ( I2C2_SlaveWrColInterruptHandler)
{
I2C2_SlaveWrColInterruptHandler();
}
}
static void I2C2_SlaveDefWrColInterruptHandler() {
}
// Bus Collision Event Interrupt Handlers
void I2C2_SlaveSetBusColIntHandler(interruptHandler handler){
I2C2_SlaveBusColInterruptHandler = handler;
}
static void I2C2_SlaveBusColCallBack() {
// Add your custom callback code here
if ( I2C2_SlaveBusColInterruptHandler)
{
I2C2_SlaveBusColInterruptHandler();
}
}
static void I2C2_SlaveDefBusColInterruptHandler() {
}
static inline bool I2C2_SlaveOpen()
{
if(!SSP2CON1bits.SSPEN)
{
SSP2STAT = 0x40;
SSP2CON1 |= 0x06;
SSP2CON2 = 0x10;
SSP2CON1bits.SSPEN = 1;
return true;
}
return false;
}
static inline void I2C2_SlaveClose()
{
SSP2STAT = 0x40;
SSP2CON1 |= 0x06;
SSP2CON2 = 0x10;
SSP2CON1bits.SSPEN = 0;
}
static inline void I2C2_SlaveSetSlaveAddr(uint8_t slaveAddr)
{
SSP2ADD = slaveAddr;
}
static inline void I2C2_SlaveSetSlaveMask(uint8_t maskAddr)
{
SSP2MSK = maskAddr;
}
static inline void I2C2_SlaveEnableIrq()
{
PIE3bits.SSP2IE = 1;
}
static inline bool I2C2_SlaveIsAddr()
{
return !(SSP2STATbits.D_nA);
}
static inline bool I2C2_SlaveIsRead()
{
return (SSP2STATbits.R_nW);
}
static inline void I2C2_SlaveClearIrq()
{
PIR3bits.SSP2IF = 0;
}
static inline void I2C2_SlaveReleaseClock()
{
SSP2CON1bits.CKP = 1;
}
static inline bool I2C2_SlaveIsWriteCollision()
{
return SSP2CON1bits.WCOL;
}
static inline bool I2C2_SlaveIsData()
{
return SSP2STATbits.D_nA;
}
static inline void I2C2_SlaveRestart(void)
{
SSP2CON2bits.RSEN = 1;
}
static inline bool I2C2_SlaveIsTxBufEmpty()
{
return !SSP2STATbits.BF;
}
static inline bool I2C2_SlaveIsRxBufFull()
{
return SSP2STATbits.BF;
}
static inline void I2C2_SlaveSendTxData(uint8_t data)
{
SSP2BUF = data;
}
static inline uint8_t I2C2_SlaveGetRxData()
{
return SSP2BUF;
}
static inline uint8_t I2C2_SlaveGetAddr()
{
return SSP2ADD;
}
static inline void I2C2_SlaveSendAck()
{
SSP2CON2bits.ACKDT = 0;
SSP2CON2bits.ACKEN = 1;
}
static inline void I2C2_SlaveSendNack()
{
SSP2CON2bits.ACKDT = 1;
SSP2CON2bits.ACKEN = 1;
}
Header file:
/**
I2C2 Generated Driver API Header File
#Company
Microchip Technology Inc.
#File Name
i2c2_slave.h
#Summary
This is the generated header file for the I2C2 driver using PIC10 / PIC12 / PIC16 / PIC18 MCUs
#Description
This header file provides APIs for driver for I2C2.
Generation Information :
Product Revision : PIC10 / PIC12 / PIC16 / PIC18 MCUs - 1.78.1
Device : PIC18F45Q10
Driver Version : 1.0.0
The generated drivers are tested against the following:
Compiler : XC8 2.10 and above or later
MPLAB : MPLAB X 5.30
*/
/*
(c) 2018 Microchip Technology Inc. and its subsidiaries.
Subject to your compliance with these terms, you may use Microchip software and any
derivatives exclusively with Microchip products. It is your responsibility to comply with third party
license terms applicable to your use of third party software (including open source software) that
may accompany Microchip software.
THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY
IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS
FOR A PARTICULAR PURPOSE.
IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP
HAS BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO
THE FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL
CLAIMS IN ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT
OF FEES, IF ANY, THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS
SOFTWARE.
*/
#ifndef I2C2_SLAVE_H
#define I2C2_SLAVE_H
#include <stdbool.h>
#include <stdint.h>
typedef void (*interruptHandler)(void);
/**
* \brief Initialize I2C2 interface
* If module is configured to disabled state, the clock to the I2C2 is disabled
* if this is supported by the device's clock system.
*
* \return None
*/
void I2C2_Initialize(void);
/**
* \brief Open the I2C2 for communication. Enables the module if disabled.
*
* \return Nothing
*/
void I2C2_Open(void);
/**
* \brief Close the I2C2 for communication. Disables the module if enabled.
* Disables address recognition.
*
* \return Nothing
*/
void I2C2_Close(void);
/**
* \brief Read data from I2C2 communication.
*
* \return Read Data
*/
uint8_t I2C2_Read(void);
/**
* \brief Write data over the communication.
*
* \return None
*/
void I2C2_Write(uint8_t data);
/**
* \brief Enable the communication by initialization of hardware
*
* \return None
*/
void I2C2_Enable(void);
/**
* \brief Send the Ack Signal to Master
*
* \return None
*/
void I2C2_SendAck(void);
/**
* \brief Send the Nack Signal to Master
*
* \return None
*/
void I2C2_SendNack(void);
/**
* \brief The function called by the I2C2 Irq handler.
* Can be called in a polling loop in a polled driver.
*
* \return Nothing
*/
void I2C2_SlaveSetIsrHandler(interruptHandler handler);
void I2C2_SlaveSetAddrIntHandler(interruptHandler handler);
void I2C2_SlaveSetReadIntHandler(interruptHandler handler);
void I2C2_SlaveSetWriteIntHandler(interruptHandler handler);
void I2C2_SlaveSetBusColIntHandler(interruptHandler handler);
void I2C2_SlaveSetWrColIntHandler(interruptHandler handler);
void (*MSSP2_InterruptHandler)(void);
void (*I2C2_SlaveRdInterruptHandler)(void);
void (*I2C2_SlaveWrInterruptHandler)(void);
void (*I2C2_SlaveAddrInterruptHandler)(void);
void (*I2C2_SlaveBusColInterruptHandler)(void);
void (*I2C2_SlaveWrColInterruptHandler)(void);
#endif /* I2C2_SLAVE_H */

You shoud not do this line in "I2C2_Isr()"
i2c2RdData = I2C2_SlaveGetRxData(); // <- but there is my first !
(it reads hardware register)
It will copy data from hardware register then this register will be empty.
So that why your " I2C2_SlaveRdCallBack();" is never be called.
This default handle will be auto call.
static void I2C2_SlaveDefRdInterruptHandler() {
i2c2RdData = I2C2_SlaveGetRxData();
}
So if you want to get data then copy to your variable, you should be do here
static void I2C2_SlaveRdCallBack() {
// Add your custom callback code here
if (I2C2_SlaveRdInterruptHandler)
{
I2C2_SlaveRdInterruptHandler();
}
// Copy i2c data to your variable here
}
Sorry for my poor English

Related

proper video streaming with rxjava

To handle a video stream from a webcam (delivered by opencv) i am considering to use RxJava.
I am hoping to achieve the following:
being able to control the frames per second to be delivered
to be able to handle different inputs - e.g. a life webcam, a video or even a still picture
being able to switch to a picture-by-picture handling under the control of a gui
I have been experimenting a bit with RxJava but i am confused about the debounce, throttleFirst and async operators
Examples like https://stackoverflow.com/a/48723331/1497139 show some code but I am missing more detailed explanation.
Where could I find a decent example for video processing or something similar along the needs mentioned above?
The code below does some non async logic at this time - please let me know if i could build on it:
ImageFetcher
import org.opencv.core.Mat;
import org.opencv.videoio.VideoCapture;
import rx.Observable;
import rx.functions.Action1;
import rx.functions.Func0;
import rx.functions.Func1;
/**
* fetcher for Images
*
*/
public class ImageFetcher {
// OpenCV video capture
private VideoCapture capture = new VideoCapture();
private String source;
protected int frameIndex;
public int getFrameIndex() {
return frameIndex;
}
/**
* fetch from the given source
*
* #param source
* - the source to fetch from
*/
public ImageFetcher(String source) {
this.source = source;
}
/**
* try opening my source
*
* #return true if successful
*/
public boolean open() {
boolean ret = this.capture.open(source);
frameIndex=0;
return ret;
}
/**
* fetch an image Matrix
*
* #return - the image fetched
*/
public Mat fetch() {
if (!this.capture.isOpened()) {
boolean ret = this.open();
if (!ret) {
String msg = String.format(
"Trying to fetch image from unopened VideoCapture and open %s failed",
source);
throw new IllegalStateException(msg);
}
}
final Mat frame = new Mat();
this.capture.read(frame);
frameIndex++;
return !frame.empty() ? frame : null;
}
#Override
protected void finalize() throws Throwable {
super.finalize();
}
/**
* convert me to an observable
* #return a Mat emitting Observable
*/
public Observable<Mat> toObservable() {
// Resource creation.
Func0<VideoCapture> resourceFactory = () -> {
VideoCapture capture = new VideoCapture();
capture.open(source);
return capture;
};
// Convert to observable.
Func1<VideoCapture, Observable<Mat>> observableFactory = capture -> Observable
.<Mat> create(subscriber -> {
boolean hasNext = true;
while (hasNext) {
final Mat frame = this.fetch();
hasNext = frame!=null && frame.rows()>0 && frame.cols()>0;
if (hasNext) {
String msg = String.format("->%6d:%4dx%d", frameIndex, frame.cols(), frame.rows());
System.out.println(msg);
subscriber.onNext(frame);
}
}
subscriber.onCompleted();
});
// Disposal function.
Action1<VideoCapture> dispose = VideoCapture::release;
return Observable.using(resourceFactory, observableFactory, dispose);
}
}
ImageSubscriber
import org.opencv.core.Mat;
import rx.Subscriber;
public class ImageSubscriber extends Subscriber<Mat> {
public Throwable error;
public int cols = 0;
public int rows=0;
public int frameIndex=0;
public boolean completed = false;
public boolean debug = false;
#Override
public void onCompleted() {
completed = true;
}
#Override
public void onError(Throwable e) {
error = e;
}
#Override
public void onNext(Mat mat) {
cols = mat.cols();
rows = mat.rows();
frameIndex++;
if (cols==0 || rows==0)
System.err.println("invalid frame "+frameIndex);
if (debug) {
String msg = String.format("%6d:%4dx%d", frameIndex, cols, rows);
System.out.println(msg);
}
}
};

Glib - interrupt foreach

I have very long collection - GList (huge amount of samples). For validation of every sample I am using g_list_foreach. The processing of the whole list lasts long. Sometimes it would be very useful to interrupt processing (via system signal SIGINT). Is there any way to interrupt foreach function?
It's trivial to implement something like g_list_foreach which would check a flag on each iteration, then you just need to install a signal handler to set the flag.
Here is the entire implementation of g_list_foreach:
void
g_list_foreach (GList *list,
GFunc func,
gpointer user_data)
{
while (list)
{
GList *next = list->next;
(*func) (list->data, user_data);
list = next;
}
}
How to install the handler will depend on how you want to structure your application, but if nothing else you could use a GOnce to install the handler, so something like:
static volatile gboolean my_flag = FALSE;
static void
handle_sigint(int id) {
my_flag = TRUE;
}
static gpointer
install_handler(gpointer data)
{
signal(SIGINT, handle_sigint);
return NULL;
}
/* Returns FALSE if interrupted, TRUE otherwise. */
gboolean
my_g_list_foreach (GList *list,
GFunc func,
gpointer user_data)
{
static GOnce handler_once = G_ONCE_INIT;
g_once(&handler_once, install_handler, NULL);
my_flag = FALSE;
while (list)
{
if (flag)
return FALSE;
GList *next = list->next;
(*func) (list->data, user_data);
list = next;
}
return TRUE;
}

App Error 104 uncaught : runtime exception while running blackberry application

I have created one application to get My location coordinates using GPS after deploying my code in simulator i am getting above error with explanation -
uncaught exception:pushmodalscreen called by a non-event thread
I am not able to figure out whats going wrong.
/**
* GPSDemo.java
*
* Copyright © 1998-2011 Research In Motion Ltd.
*
* Note: For the sake of simplicity, this sample application may not leverage
* resource bundles and resource strings. However, it is STRONGLY recommended
* that application developers make use of the localization features available
* within the BlackBerry development platform to ensure a seamless application
* experience across a variety of languages and geographies. For more information
* on localizing your application, please refer to the BlackBerry Java Development
* Environment Development Guide associated with this release.
*/
package com.gps;
import java.util.*;
import javax.microedition.location.*;
import net.rim.device.api.command.*;
import net.rim.device.api.gps.*;
import net.rim.device.api.system.*;
import net.rim.device.api.ui.*;
import net.rim.device.api.ui.component.*;
import net.rim.device.api.ui.container.*;
import net.rim.device.api.util.*;
import net.rim.blackberry.api.invoke.*;
import net.rim.blackberry.api.maps.*;
import net.rim.blackberry.api.menuitem.*;
/**
* This application acts as a simple travel computer, recording route
* coordinates, speed and altitude. Recording begins as soon as the
* application is invoked.
*/
public class GPSScreen extends UiApplication
{
// Represents the number of updates over which altitude is calculated, in seconds
private static final int GRADE_INTERVAL = 5;
private static final long ID = 0x5d459971bb15ae7aL;
// Represents period of the position query, in seconds
private static int _interval = 1;
private double _latitude;
private double _longitude;
private LocationProvider _locationProvider;
private GPSDemoScreen _screen;
private MapView _mapview = new MapView();
/**
* Entry point for application
*
* #param args Command line arguments (not used)
*/
public static void main(String[] args)
{
// Create a new instance of the application and make the currently
// running thread the application's event dispatch thread.
new GPSScreen().enterEventDispatcher();
}
/**
* Create a new GPSDemo object
*/
public GPSScreen()
{
_screen = new GPSDemoScreen();
_screen.setTitle("GPS Demo");
// Attempt to start the location listening thread
if(startLocationUpdate())
{
_screen.setState(_locationProvider.getState());
}
// Render the screen
pushScreen(_screen);
}
/**
* Invokes the Location API with Standalone criteria
*
* #return True if the <code>LocationProvider</code> was successfully started, false otherwise
*/
private boolean startLocationUpdate()
{
boolean returnValue = false;
if(!(GPSInfo.getDefaultGPSMode() == GPSInfo.GPS_MODE_NONE))
{
try
{
Criteria criteria = new Criteria();
criteria.setCostAllowed(false);
_locationProvider = LocationProvider.getInstance(criteria);
if(_locationProvider != null)
{
/*
* Only a single listener can be associated with a provider,
* and unsetting it involves the same call but with null.
* Therefore, there is no need to cache the listener
* instance request an update every second.
*/
_locationProvider.setLocationListener(new LocationListenerImpl(), _interval, -1, -1);
returnValue = true;
}
else
{
invokeLater(new Runnable()
{
public void run()
{
Dialog.alert("Failed to obtain a location provider, exiting...");
System.exit(0);
}
});
}
}
catch(final LocationException le)
{
invokeLater(new Runnable()
{
public void run()
{
Dialog.alert("Failed to instantiate LocationProvider object, exiting..." + le.toString());
System.exit(0);
}
});
}
}
else
{
invokeLater(new Runnable()
{
public void run()
{
Dialog.alert("GPS is not supported on this device, exiting...");
System.exit(0);
}
});
}
return true;
}
/**
* Implementation of the LocationListener interface. Listens for updates to
* the device location and displays the results.
*/
private class LocationListenerImpl implements LocationListener
{
/**
* #see javax.microedition.location.LocationListener#locationUpdated(LocationProvider,Location)
*/
public void locationUpdated(LocationProvider provider, Location location)
{
if(location.isValid())
{
_longitude = location.getQualifiedCoordinates().getLongitude();
_latitude = location.getQualifiedCoordinates().getLatitude();
_mapview.setZoom(Integer.parseInt("0.1"));
try
{
int latitude = (int) (100000 * _latitude);
int longitude = (int) (100000 * _longitude);
if (latitude > 9000000 || latitude < -9000000 || longitude >= 18000000 || longitude < -18000000)
{
throw new IllegalArgumentException ();
}
_mapview.setLatitude(latitude);
_mapview.setLongitude(longitude);
// Invoke BlackBerry Maps application with provided MapView object.
Invoke.invokeApplication(Invoke.APP_TYPE_MAPS, new MapsArguments(_mapview));
}
catch(RuntimeException re)
{
// An exception is thrown when any of the following occur :
// Latitude is invalid : Valid range: [-90, 90]
// Longitude is invalid : Valid range: [-180, 180)
// Minus sign between 2 numbers.
Dialog.alert("Temporary Unavailable Service");
}
}
}
/**
* #see javax.microedition.location.LocationListener#providerStateChanged(LocationProvider, int)
*/
public void providerStateChanged(LocationProvider provider, int newState)
{
if(newState == LocationProvider.TEMPORARILY_UNAVAILABLE)
{
provider.reset();
}
_screen.setState(newState);
}
}
/**
* The main screen to display the current GPS information
*/
private final class GPSDemoScreen extends MainScreen
{
TextField _statusTextField;
/**
* Create a new GPSDemoScreen object
*/
GPSDemoScreen()
{
// Initialize UI
_statusTextField = new TextField(Field.NON_FOCUSABLE);
}
/**
* Display the state of the GPS service
*
* #param newState The state to display
*/
public void setState(final int newState)
{
UiApplication.getUiApplication().invokeLater(new Runnable()
{
/**
* #see java.lang.Runnable#run()
*/
public void run()
{
switch(newState)
{
case LocationProvider.AVAILABLE:
_statusTextField.setText("Available");
break;
case LocationProvider.OUT_OF_SERVICE:
_statusTextField.setText("Out of Service");
break;
case LocationProvider.TEMPORARILY_UNAVAILABLE:
_statusTextField.setText("Temporarily Unavailable");
break;
}
}
});
}
/**
* #see net.rim.device.api.ui.Screen#close()
*/
public void close()
{
if(_locationProvider != null)
{
_locationProvider.reset();
_locationProvider.setLocationListener(null, -1, -1, -1);
}
super.close();
}
}
}
I've seen that error when Dialog.alert() is used outside of the event thread. Looking at your code, I see LocationListenerImpl.locationUpdated assumes it is running on the event thread. If it is not, the UI update code would throw an exception, and then your exception handler will try to display a dialog, and that will fail as well.

boost::asio and boost::bind errors

This questions is a bit annoying, I can't get the following code to compile. You will have to compile the code below.
I am having some trouble with boost asio, I am trying to abstract the logic of accepting connections into a uniform abstraction so that I can initiate connection for windows named-pipes and Unix domain sockets uniformly with regular TCP/IP.
There are 3 classes shown in the code below, the first 2 are the implementations of acceping TCP connections, and the third class below is a generic class that is implemented in terms of the first 2. I am having troubles with boost::bind calls. The trouble probably lies with my understanding of the semantics.
If I make TcpDestinationAcceptor::handle_accept a regular member function (--i.e., not a template member function) which results in me not passing the AcceptHandler parameter. The code compiles fine. Note: I do not remove the template function status from TcpDestinationAcceptor::StartAccepting.
Note: I have already started on a different design, still I would like to pursue this design if possible.
Self contained code:
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/bind.hpp>
#include <boost/asio/placeholders.hpp>
class TcpDestinationConnection
{
public:
typedef boost::asio::ip::tcp::socket t_io_object;
TcpDestinationConnection(boost::asio::io_service & io_s)
: m_io_object(io_s) {} ;
t_io_object & io_object() { return m_io_object; }
private:
t_io_object m_io_object;
};
class TcpDestinationAcceptor
{
public:
typedef boost::asio::ip::tcp::acceptor t_acceptor;
typedef boost::shared_ptr<TcpDestinationConnection> t_connection_ptr;
TcpDestinationAcceptor( boost::asio::io_service & io_s)
: m_io_service(io_s),
m_acceptor(io_s)
{
m_acceptor.open(boost::asio::ip::tcp::v4());
}
TcpDestinationAcceptor( boost::asio::io_service & io_s ,
const boost::asio::ip::tcp::endpoint & endpoint)
: m_io_service(io_s),
m_acceptor(io_s, endpoint)
{
m_acceptor.open(boost::asio::ip::tcp::v4());
}
t_acceptor & acceptor() { return m_acceptor; }
template<typename AcceptHandler>
void StartAccepting(AcceptHandler h)
{
t_connection_ptr new_session(new TcpDestinationConnection(m_io_service));
m_acceptor.async_accept( new_session->io_object(),
boost::bind( &TcpDestinationAcceptor::handle_accept<AcceptHandler>, this,
boost::asio::placeholders::error, new_session, h));
}
template<typename AcceptHandler>
void handle_accept(const boost::system::error_code & err, t_connection_ptr cur, AcceptHandler h) {
}
private:
boost::asio::io_service & m_io_service;
boost::asio::ip::tcp::acceptor m_acceptor;
};
template<typename t_acceptor>
class ConnectionOracle
{
public:
ConnectionOracle()
: m_io_service(),
m_acceptor(m_io_service) {}
typename t_acceptor::t_acceptor & native_acceptor() { return m_acceptor.acceptor(); }
boost::asio::io_service & io_service() { return m_io_service; }
void StartConnection( typename t_acceptor::t_connection_ptr connection,
boost::system::error_code & error)
{
}
void Begin()
{
m_acceptor.StartAccepting( boost::bind( &ConnectionOracle::StartConnection,this,
_1,
boost::asio::placeholders::error));
m_io_service.run();
}
private:
boost::asio::io_service m_io_service;
t_acceptor m_acceptor;
};
int main()
{
ConnectionOracle<TcpDestinationAcceptor> ConOracle;
ConOracle.native_acceptor().
bind(boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(),50000));
ConOracle.Begin();
return 0;
}

In Gobject, how to override parent class's method belong to an interface?

GObject class A implements interface IA, B is a derived class of A. How can B override A's method that is part of the interface IA?
Or, is this possible in GObject?
I know how to override parent class methods, but when inheritance meets interface, things seems to be more complicated.
Thanks a lot!
Yes, it is possible: just reimplement the interface as it was the first time, either using G_IMPLEMENT_INTERFACE() or manual initializing it in your get_type() function.
The real pain is if you need to chain up the old method. In this case, you should play with
g_type_interface_peek_parent to get the previous interface class.
Here is a test case:
/* gcc -otest `pkg-config --cflags --libs gobject-2.0` test.c */
#include <glib-object.h>
/* Interface */
#define TYPE_IFACE (iface_get_type())
typedef void Iface;
typedef struct {
GTypeInterface parent_class;
void (*action) (Iface *instance);
} IfaceClass;
GType
iface_get_type(void)
{
static GType type = 0;
if (G_UNLIKELY(type == 0)) {
const GTypeInfo info = {
sizeof(IfaceClass), 0,
};
type = g_type_register_static(G_TYPE_INTERFACE, "Iface", &info, 0);
}
return type;
}
void
iface_action(Iface *instance)
{
G_TYPE_INSTANCE_GET_INTERFACE(instance, TYPE_IFACE, IfaceClass)->
action(instance);
}
/* Base object */
#define TYPE_BASE (base_get_type())
typedef GObject Base;
typedef GObjectClass BaseClass;
static void
base_action(Iface *instance)
{
g_print("Running base action on a `%s' instance...\n",
g_type_name(G_TYPE_FROM_INSTANCE(instance)));
}
static void
base_iface_init(IfaceClass *iface)
{
iface->action = base_action;
}
G_DEFINE_TYPE_WITH_CODE(Base, base, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE(TYPE_IFACE, base_iface_init));
static void
base_class_init(BaseClass *klass)
{
}
static void
base_init(Base *instance)
{
}
/* Derived object */
#define TYPE_DERIVED (derived_get_type())
typedef Base Derived;
typedef BaseClass DerivedClass;
static void
derived_action(Iface *instance)
{
IfaceClass *iface_class, *old_iface_class;
iface_class = G_TYPE_INSTANCE_GET_INTERFACE(instance, TYPE_IFACE, IfaceClass);
old_iface_class = g_type_interface_peek_parent(iface_class);
g_print("Running derived action on a `%s' instance...\n",
g_type_name(G_TYPE_FROM_INSTANCE(instance)));
/* Chain up the old method */
old_iface_class->action(instance);
}
static void
derived_iface_init(IfaceClass *iface)
{
iface->action = derived_action;
}
G_DEFINE_TYPE_WITH_CODE(Derived, derived, TYPE_BASE,
G_IMPLEMENT_INTERFACE(TYPE_IFACE, derived_iface_init));
static void
derived_class_init(DerivedClass *klass)
{
}
static void
derived_init(Derived *instance)
{
}
int
main()
{
GObject *object;
g_type_init();
object = g_object_new(TYPE_BASE, NULL);
iface_action((Iface *) object);
g_object_unref(object);
object = g_object_new(TYPE_DERIVED, NULL);
iface_action((Iface *) object);
g_object_unref(object);
return 0;
}
I think a better solution would be to make A's method virtual, rather than have B re-implement the interface A is attached to (this may require more work than just redefining one function), which you can do like this (example should be complete other than the fooable interface definition):
#include <glib-object.h>
#include "fooable.h"
typedef struct {GObject parent;} A;
typedef struct {
GObjectClass parent;
gint (*foo) (Fooable *self, gdouble quux);
} AClass;
#define TYPE_A (a_get_type())
#define A_CLASS(cls) (G_TYPE_CHECK_CLASS_CAST((cls), TYPE_A, AClass))
#define A_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TYPE_A, AClass))
gint a_foo_real (Fooable *self, gdouble quux) {
g_print("a_foo_real(%g)\n", quux);
return 5;
}
gint a_foo (Fooable *self, gdouble quux) {
return A_GET_CLASS(self)->foo(self, quux);
}
void implement_fooable (FooableIface *iface) {iface->foo = a_foo;}
void a_class_init (AClass *cls) {cls->foo = a_foo_real;}
void a_init (A *self) {}
G_DEFINE_TYPE_WITH_CODE(A, a, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE(TYPE_FOOABLE, implement_fooable));
/* derive class B from A */
typedef struct {A parent;} B;
typedef struct {AClass parent;} BClass;
#define TYPE_B (b_get_type())
gint b_foo_real (Fooable *self, gdouble quux) {
g_print("b_foo_real(%g)\n", quux);
return 55;
}
void b_class_init (BClass *cls) {A_CLASS(cls)->foo = b_foo_real;}
void b_init (B *self) {}
G_DEFINE_TYPE(B, b, TYPE_A);
int main () {
g_type_init();
A *a = g_object_new(TYPE_A, NULL);
B *b = g_object_new(TYPE_B, NULL);
fooable_foo(FOOABLE(a), 87.0); // a_foo_real(87.0) and returns 5
fooable_foo(FOOABLE(b), 32.0); // b_foo_real(32.0) and returns 55
return 0;
}
That's as brief of an example as I can make it. When you call fooable_foo() the function will look at its vtable for the function defined when you implemented the interface which is a_foo() which looks at A class's vtable to determine which function to actually call. The B class definition overrides A class's a_foo_real() with its own. If you need B class's b_foo_real to chain up, that's an easy enough (use A_CLASS(b_parent_class)->foo() which is defined for you in the G_DEFINE_TYPE macro)

Resources