안드로이드 초보자 입니다. 아래 코드 BaseSprayActivity 는 USB 시리얼 포트로 드론과 연결합니다.
결론적으로 드론과 통신하여 제어하게 됩니다.
문제는 윗분들이 드론과 통신하는 부분을 따로 MavLinkService 라는 클래스를 만들어서 거기다 옮기라고 하네요.
어떻게 할줄 몰라서 우선 개발할때 편의상 BaseSprayActivity 에다가 다 때려 박았습니다.
드론과 통신을 하기위해 usb-serial-for-android 라는 라이브러리를 사용하였습니다.
라이브러리 내부적으로 스레드가 장착되어 있어서 SerialInputOutputManager.Listener 만 장착하면 주기적으로
onNewData(data: ByteArray) 가 호출이되어 데이터를 보내줍니다.
큐에다가 데이터를 차례로 입력하고 큐에 있는 데이터를 처리하기 위해 readPaketThread()라는 스레드를 하나 만들었구요.
명령을 날릴때는 sendCmd(cmd: ByteArray?) 함수를 사용합니다.
근데 이모든걸 따로 다른 독립된 클래스로 옮겨야 하는 어떻게 하는지 초보라서 잘 모르겠습니다.
Connect() 접속하는 부분도 다른 클래스에서 구현할 수 있을까요?
또 스레드부분은 다른 클래스에서 서비스로 구현하나요 아니면 스레드로 구현하나요?
MavLinkService 이름보니까 서비스로 구현하라고 하는것 같기도하고.
지금까지 개발한 코드를 아주필수적인 부분만 추려서 붙여봤습니다.
고수님들의 도움이 필요합니다. 정말 감사합니다.
open class BaseSprayActivity : BaseActivity() , SerialInputOutputManager.Listener {
private var mavlinkpacketQueue = ArrayBlockingQueue<Byte>(4000)
private var isRunning = false
private val INTENT_ACTION_GRANT_USB: String = BuildConfig.APPLICATION_ID.toString() + ".GRANT_USB"
private val baudRate = 57600
private val withIoManager = true
private var broadcastReceiver: BroadcastReceiver? = null
private var mainLooper: Handler? = null
private var usbIoManager: SerialInputOutputManager? = null
private var usbSerialPort: UsbSerialPort? = null
private var usbPermission = UsbPermission.Unknown
private var connected = false
override fun onCreate(savedInstanceState: Bundle?) {
...
isRunning = true
val thread = readPaketThread()
thread.start()
}
public fun init_SerialPort() {
broadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (INTENT_ACTION_GRANT_USB == intent.action) {
usbPermission = if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) UsbPermission.Granted else UsbPermission.Denied
connect()
}
}
}
mainLooper = Handler(Looper.getMainLooper())
}
private fun connect() { // usb 시리얼 포트와 연결
....
usbSerialPort = driver.ports[0]
....
if (withIoManager) {
usbIoManager = SerialInputOutputManager(usbSerialPort, this)
usbIoManager!!.start()
}
connected = true
}
override fun onNewData(data: ByteArray) {
mainLooper!!.post {
receive(data)
}
}
private fun receive(data: ByteArray) {
val bufflen = data.size;
for(i in 0..bufflen-1) {
var ldata = data.get(i)
mavlinkpacketQueue.offer(ldata)
}
}
inner class readPaketThread: Thread() {
override fun run() {
var payload_len : Int = 0
var pack_size: Int = 0
while(isRunning) {
if(mavlinkpacketQueue.size < 1) continue
if(mavlinkpacketQueue.peek() == 0xFE.toByte())
{
pack_size = mavlinkpacketQueue.size
if(mavlinkpacketQueue.size < 2) continue
payload_len = mavlinkpacketQueue.elementAt(1).toInt()
if(payload_len < 0 || payload_len > 255) {
if(mavlinkpacketQueue.isNotEmpty()) {
mavlinkpacketQueue.poll()
continue
}
if(mavlinkpacketQueue.size < payload_len+8) continue
var data = ByteArray(payload_len+8)
for(j in 0..payload_len+8-1) {
if(mavlinkpacketQueue.isNotEmpty()) {
data[j] = mavlinkpacketQueue.poll()
}
}
parsingMavLinkTelemetry(data, payload_len, pack_size) // 파싱 하고 데이터 처리
} else {
if(mavlinkpacketQueue.isNotEmpty()) {
mavlinkpacketQueue.poll()
}
}
}
super.run()
}
}
fun sendCmd(cmd: ByteArray?) {
usbSerialPort!!.write(cmd, WRITE_WAIT_MILLIS)
}
override fun onResume() {
if (usbPermission == UsbPermission.Unknown || usbPermission == UsbPermission.Granted) mainLooper!!.post { connect() }
}
override fun onPause() {
if (connected) {
disconnect()
}
}
}