PDA

Просмотр полной версии : CITROEN-ARDUINO


Страницы : [1] 2

T_r_D
14.07.2015, 00:46
Народ, а кто нить дружил Citroen с Arduino (http://duino.ru/arduino.html)+CAN Shield?

Толи я чего-то не понимаю, толи я что-то не правильно делаю.
#include <SPI.h>
#include "mcp_can.h"
MCP_CAN CAN(10);
unsigned char len = 0;
unsigned char buf[8];
INT32U canId = 0x000;

void setup()
{
Serial.begin(115200);

START_INIT:

if(CAN_OK == CAN.begin(CAN_500KBPS,MCP_8MHz))
{
Serial.println("Init OK!");
}
else
{
Serial.println("Init fail");
delay(100);
goto START_INIT;
}
}


void loop()
{
if(CAN_MSGAVAIL == CAN.checkReceive()) // check if data coming
{
CAN.readMsgBuf(&len, buf);

canId = CAN.getCanId();
// unsigned long canId = CAN.getCanId();

Serial.print("<");Serial.print(canId);Serial.print(",");

for(int i = 0; i<len; i++)
{
Serial.print(buf[i]);Serial.print(",");
}
Serial.print(">");
Serial.println();
}
}

Пытаюсь отловить обороты. Но получаю на выходе при чтение что-то типо
8 : 1C F0 32 0 4C 30 0 32
68 : 0 0 FF
D : 0 0 0 0 0 0 0 B
8 : 1C F0 31 0 4C 30 0 32
48 : 0 30 2 42 C8 3 1 0
5 : 7F FF 0 5 58 0
5 : 7F FF 1 85 D9 0
8 : 1C F0 31 0 4C 30 0 32
32 : 81 5B 48 FE 0 0
68 : 0 0 FF
D : 0 0 0 0 0 0 0 C
92 : 0 0 0
8 : 1C F2 31 0 4C 30 0 32
48 : 0 30 2 42 C8 3 1 0
5 : 7F FF 0 5 6B 0
12 : 73 20 1 3D 0
4D : 0 0 0 0 0 0 0 0

И не одного упоминания о 0C Обороты двигателя (Engine RPM)!
И почему такие короткие ID у сообщений?
Я чего-то не дописал или у ситроенов обороты под другим ID?

Поделитесь кто что знает!
Я в этом совсем новенький.

Bersenev
14.07.2015, 13:23
В общем ты путаешь два понятия:

первое - это протокол по которому общаются устройства в твой машине, и он в каждой машине свой ( иногда даже разный в машинах одной и той же марки ), именно его ты и привёл в качестве примера.

второе - это OBD II протокол, то есть диагностический протокол, который должен быть реализован в каждой машине, но из практики могу сказать, что есть он почти во всех новых машинах, но не во всех реализован в полном объёме. Данный протокол работает по запросу, то есть ты сначала запрашиваешь у диагностического устройства с ид 7DF, то что тебе нужно, а потом получаешь ответ от устройства с ид. 7E8 ( возможны варианты от 7E8 до 7EF). Вот именно в этом протоколе 0C это обороты двигателя. Более подробно читаем здесь https://en.wikipedia.org/wiki/OBD-II_PIDs#Mode_1_PID_1C

Теперь по поводу твоего протокола, как я и говорил у каждой машины он свой, допустим в грузовиках ISUZU мы получаем такое сообщение

<217056256,240,125,126,188,18,0,255,255,>

вот именно в сообщениях с идентификатором 217056256 в 4-м и 5-м байтах находятся обороты двигателя, при чём для получения нужного числа надо (18*256+188)/8 = 599,5 об/мин

твой протокол слишком короткий, что бы точно сказать, что именно именно передаёт обороты двигателя, но скорее всего обороты здесь

8 : 1C F2 31 0 4C 30 0 32

Причем вычисляется так 31 это 49 десятичное, F2 - 242.
(49*256+242)/16 = 799,125 об/мин.

Если конечно прокол снимался на холостых оборотах.

T_r_D
14.07.2015, 21:34
Bersenev спасибо тебе огромное.
В моём протоколе это лишь кусок.
У меня есть два лога- один без запуска двигателя, а второй с запуском и работой на ХХ.
Ту часть которую привёл это с запуском.
Но похоже это не тот ID поскольку на незапущенном двигателе он тоже меняется.
Если поможешь, то могу выслать два лога.

Какой программой можно анализировать траффик с ком порта?
А то эта угадайка на долго.

И если не сложно объясните мне как при помощи ардуины OBD II запросы слать и принимать ответы.
лог без запуска (выборка по ID с убиранием повторяющихся сообщений)

также попробовал написать
if (canId = 8)
{
C = (buf[3]*256+buf[2])/16;
Serial.println(C);
}
И получил пляшущие цифры ни малейшим образом не намекающие на обороты!

T_r_D
15.07.2015, 22:09
Короче понятно.
Нужно идти стандартным путём- ELM327+Arduino

Bersenev
15.07.2015, 23:28
И если не сложно объясните мне как при помощи ардуины OBD II запросы слать и принимать ответы.

Для тех кому лень читать WIKI (а там всё очень подробно описано), вот пример как запрашивать скорость автомобиля по OBDII

#include <mcp_can.h>
#include <SPI.h>

INT32U canId = 0x000;

unsigned char len = 0;
unsigned char buf[8];
char str[20];
boolean IsSend = false;

unsigned long IsSend_millis = 0;

unsigned char vspeed[8] = {2, 1, 13, 0, 0, 0, 0, 0};

unsigned char count = 0;

MCP_CAN CAN0(10);

void setup()
{
Serial.begin(9600);

START_INIT:

if(CAN0.begin(CAN_500KBPS) == CAN_OK)
{
Serial.println("CAN BUS Shield init ok!");
}
else
{
Serial.println("CAN BUS Shield init fail");
Serial.println("Init CAN BUS Shield again");
delay(100);
goto START_INIT;
}

pinMode(18, INPUT);

}

void loop()
{
if(!IsSend)
{
CAN0.sendMsgBuf(0x7DF, 0, 8, vspeed);
IsSend = true;
IsSend_millis = millis();
}
if(!digitalRead(18))
{
CAN0.readMsgBuf(&len, buf);
canId = CAN0.getCanId();

if( (canId == 0x7E8) && (buf[0] == 3) && (buf[1] == 0x41) && (buf[2] == 0xD))
{
Serial.println(buf[3]);
IsSend_millis = millis()-2500;
Serial.print("Speed: ");
Serial.println(buf[3]);
}
}
if( IsSend )
{
if( IsSend_millis + 3000 < millis() )
{
Serial.print("----");
IsSend = false;
IsSend_millis = millis();
}
}
}

Скетч посылает запросы раз в три секунды, пока не придёт первый ответ. После этого посылается два запроса в секунду.

Только номера пинов надо задать свои.

Bersenev
15.07.2015, 23:39
также попробовал написать
if (canId = 8)
{
C = (buf[3]*256+buf[2])/16;
Serial.println(C);
}
И получил пляшущие цифры ни малейшим образом не намекающие на обороты!

И не удивительно,

C = (buf[3]*256+buf[2])/16;

Я не знаю тип переменной C , но в принципе это и не важно.

buf[3]*256 - байт умножается на 256 и сохраняется в байт, то есть всегда равно 0. Теперь к нулю прибавляем байт buf[2] и делим на 16 в результате значения от 0 до 15.

а надо так, если C имеет тип unsigned int, то

C = buf[3];
C = (C*256+buf[2])/16;

То есть сначала байт преобразуем в unsigned int, а уже потом выполняем все действия, вот тогда получим правильное значение

Bersenev
15.07.2015, 23:54
Какой программой можно анализировать траффик с ком порта?
А то эта угадайка на долго.


А это как повезёт, по работе приходится искать в протоколах в основном скорость и уровень топлива, иногда на это уходит часов шесть, а иногда 5 минут.

Я сделал себе программу для анализа протокола, протокол формирует этот скетч.

#include <mcp_can.h>
#include <SPI.h>

INT32U canId = 0x000;

unsigned char len = 0;
unsigned char buf[8];
char str[20];
int count = 0;

MCP_CAN CAN0(10);

void setup()
{
Serial.begin(38400);
while(!Serial){}

START_INIT:

if(CAN0.begin(CAN_500KBPS) == CAN_OK)
{
Serial.println("CAN BUS Shield init ok!");
}
else
{
Serial.println("CAN BUS Shield init fail");
Serial.println("Init CAN BUS Shield again");
delay(100);
goto START_INIT;
}

pinMode(18, INPUT);
}

void loop()
{

if(!digitalRead(18))
{
CAN0.readMsgBuf(&len, buf);
canId = CAN0.getCanId();

Serial.print("<");Serial.print(canId);Serial.print(",");
for(int i = 0; i<len; i++)
{
Serial.print(buf[i]);Serial.print(",");
}
Serial.print(">");
Serial.println();
}
}

Так что можешь сделать файл этим скетчем, отправь мне, а я посмотрю.

Только для того что бы найти обороты надо сделать следующее:

Подключить шилд к машине, запустить монитор ком порта, включить зажигание секунд на пять, потом завести машину, потом медленно давить на газ что бы обороты плавно подымались, а потом также плавно опускать обороты до холостых. После этого глушим машину и сохраняем протокол. Вот тогда что бы найти обороты понадобится минут десять.

Для скорости почти тоже самое, только надо равномерно разогнать машину километров до 40 - 50-ти, а потом также спокойно остановиться.

Для уровня топлива нужны протоколы до и после заправок.

T_r_D
16.07.2015, 00:59
С имеет тип unsigned int. Задаётся в начале поэтому и небыло в куске.
С байт ты прав, но там числа получались до 65000.
Можно попробовать ещё раз.

Твой скетч тоже что и мой, только вывод строк в другом формате.
у меня в хексе и без всяких скобок и разделителей кроме ":" между ID и сообщением, а у тя с доп символами.
Ща перепишу свой чтоб выводилось в твоём формате.

С посылкой по OBD II ща попробую сам разобраться :)
Реально мне с ардуиной пока очень сложно так как опыта программирования МК у меня нет.

PS А что делает строчка?
INT32U canId = 0x000;
и отличается ли она от моей
unsigned char canId = CAN.getCanId();

Bersenev
16.07.2015, 08:00
также попробовал написать
if (canId = 8)
{
C = (buf[3]*256+buf[2])/16;
Serial.println(C);
}
И получил пляшущие цифры ни малейшим образом не намекающие на обороты!

и ещё по этому куску, речь действительно шла про 2 и 3-ий байты, но индексы в скетче у них 1 и 2, то есть правильно это должно выглядеть так

C = buf[2];
C = (C*256+buf[1])/16;

Bersenev
16.07.2015, 08:10
PS А что делает строчка?
INT32U canId = 0x000;
и отличается ли она от моей
unsigned char canId = CAN.getCanId();

Объявляет переменную canId, только в твоём случае она динамическая, так как создаётся внутри цикла.

Но самое главное у тебя здесь ошибка, так как идентификаторы могут быть 11-ти или 29-битные (в зависимости от системы адресации в конкретной can шине), а ты выделяешь под него один байт, то есть всего восемь бит.

Правильно должно быть так

unsigned long canId = CAN.getCanId();

или так

INT32U canId = CAN.getCanId();

Bersenev
16.07.2015, 22:16
Идентификатор 520, байты 0 и 1

C = buf[0];
C = (C*256+buf[1])/8;

Только файлы можно просто прикреплять к сообщению, а не вставлять их в текст

T_r_D
16.07.2015, 23:37
Bersenev
Как ты это делаешь шаман? :)
Какой прогой анализируешь?
Спасибо огромное!

Кстати по запросу через OBD II я так ни чего и не понял, но попробую ещё подумать.
Вики я всю пересмотрел.

PS. А что ещё можно извлечь из данного лога?

И проверил ща в машине.
Там опять какая-то каша!
Без запуска двигателя кажет
<CUT>

Скетч приобрёл вид
#include <SPI.h>
#include "mcp_can.h"
MCP_CAN CAN(10);
unsigned char len = 0;
unsigned char buf[8];
unsigned int RPM;
INT32U canId = 0x000; // идентификаторы могут быть 11-ти или 29-битные

void setup()
{
Serial.begin(115200);

START_INIT:

if(CAN_OK == CAN.begin(CAN_500KBPS,MCP_8MHz))
{
Serial.println("Init OK!");
}
else
{
Serial.println("Init fail");
delay(100);
goto START_INIT;
}
}

void loop()
{
if(CAN_MSGAVAIL == CAN.checkReceive()) // check if data coming
{
CAN.readMsgBuf(&len, buf);
canId = CAN.getCanId();
if (canId = 520)
{
RPM = buf[0];
RPM = (RPM*256+buf[1])/8;
Serial.print("Engine RPM: ");
Serial.println(RPM);
}
}
}

Bersenev
17.07.2015, 00:01
Какой прогой анализируешь?

Своей, так как постоянно приходится вскрывать протоколы разной техники, пришлось написать для себя программку


PS. А что ещё можно извлечь из данного лога?

Из этого лога только обороты, так как для них он и делался, вроде ещё попалась температура ОЖ, но не факт. Для всего есть своя методика, но меня по работе интересует в основном скорость и уровень топлива

Bersenev
17.07.2015, 00:04
if (canId = 520)


А надо

if (canId == 520)

T_r_D
17.07.2015, 00:28
Bersenev всё- заработало, ещё раз спасибо!
А остальные цифры в 520 что-то значат?
Возможно ли что в одном ID два параметра находятся?

А в принципе видимо из этих данных можно выловить всё о машине что касается двигателя?

Как сделать лог для всего остального?
Ну например той же температуры ОЖ, скорости, напряжения, уровня топлива и самое главное расхода топлива?

И можно ли каким-то стандартным софтом анализировать протокол?
Хочу хоть примерно понять.

PS. Температура ОЖ там врядли была. она ровнялась температуре окружающей среды :)

Bersenev
17.07.2015, 00:59
Bersenev всё- заработало, ещё раз спасибо!
А остальные цифры в 520 что-то значат?
Возможно ли что в одном ID два параметра находятся?


Конечно возможно, даже в одном байте разные биты могут отвечать за разные датчики.

А в принципе видимо из этих данных можно выловить всё о машине что касается двигателя?

Можно, но сложно, если нет описания протокола.

Как сделать лог для всего остального?
Ну например той же температуры ОЖ, скорости, напряжения, уровня топлива и самое главное расхода топлива?

Для ОЖ просто зависти машину и ждать подъёма температуры градусов на десять. Для скорости равномерно разогнать машину до 40 - 50 км/ч и также спокойно остановиться. Напряжение не искал, но я бы просто померял его с помощью ардуино. Для топлива снимаем протокол, потом заливаем 10-20 литров и снова снимаем, для верности ещё заливаем и ещё раз снимаем протокол, потом анализируем три протокола. Расхода топлива в протоколе нет, его надо рассчитывать на основе других данных.

И можно ли каким-то стандартным софтом анализировать протокол?
Хочу хоть примерно понять.

я не знаю такого софта, все канхакеры, что находилось в сети, мне не подошли.

PS. Температура ОЖ там врядли была. она ровнялась температуре окружающей среды :)

ид 1362 , байт 1 и 2. формула скорее всего такая

(buf[1]*256 + buf[2])/256

то есть в байте 1 температура в градусах, а в байте 2 значение после запятой. У тебя в логе она поднялась с 37.8 до 39.2

T_r_D
17.07.2015, 01:36
Конечно возможно, даже в одном байте разные биты могут отвечать за разные датчики.

ТОгда нужно будет проконтролить не идёт ли чего нить ещё с оборотами вместе.


ид 1362 , байт 1 и 2. формула скорее всего такая

(buf[1]*256 + buf[2])/256

то есть в байте 1 температура в градусах, а в байте 2 значение после запятой. У тебя в логе она поднялась с 37.8 до 39.2

Завтра проверю.

И если будет время запишу лог разгона и торможения.

По поводу напряжения- хочется всётаки понять где оно там спрятано.

По поводу топлива- алгоритм-то понятен. Надо только лейку найти и доехать в канистру 20л бензина налить, вот только как потом ровно по 10 литров налить?
А второй канистры нету.

По поводу расхода- понятно. Там наверняка берётся из расчёта времени открытия форсунок и может быть давления в рампе.

T_r_D
17.07.2015, 21:11
Снял лог.
Разгон 0-60 и потом 60-0 с отпущенным газом.
Файл приложил.
В архиве txt

Про температуру.
Вчера ты написал

ид 1362 , байт 1 и 2. формула скорее всего такая

(buf[1]*256 + buf[2])/256

то есть в байте 1 температура в градусах, а в байте 2 значение после запятой. У тебя в логе она поднялась с 37.8 до 39.2

Скорее всего не 37.8, а 18.9 так как тепмература на улице не могла быть 40 градусов :)
Ща схожу проверю в машине.

Bersenev
17.07.2015, 23:38
ид 1101 скорость в 0 и 1, 2 и 3, 4 и 5, 6 и 7 байтах, но судя по всему в первых трёх парах скорость в милях, а в последней в километрах

Если разгонялся до 60 км/ч, то формула такая

(buf[6]*256 + buf[7])/200

Но это ещё надо разбираться, возможно что скорость в км именно в 0 и 1 байтах, тогда

(buf[0]*256 + buf[1])/100

что именно верно надо уже проверять экспериментально.

также скорость в ид 909 байт 0 и 1

(buf[0]*256 + buf[1])/100

В моторной шине скорость часто идёт с разными ид.

Но лучше их брать с шины которая идёт на панель приборов., там она всегда одна.

а ид 1362 ночно не температура ОЖ

T_r_D
17.07.2015, 23:49
Bersenev
1362 это какой-то таймер и обновляется раз в секунду.

По поводу скорости- я примерно до 60 разогнался. Может чуть меньше.

в 909 скорость в милях?

В итоге всётаки выходит что мне проще читать через OBD II данные.
Мне на самом деле нужно просто повторить показания на экране бортового компа.
А всё остальное это уже баловство.
А на экране отображается
1 Расход на 100
2 Моментальный расход
3 Расстояние которое можно проехать до заправки
4 Трип счётчик

Из всего что мне нужно- расход на 100 и моментальный.
Как я понимаю дёрнуть из протокола ситра будет это очень не просто.

Так что думаю что сделаю проще.
В диаг разъём вставлю ELM, а с него уже буду брать данные.
Так проще и про ELM всё рассказано уже.

А свой CAN Shield переделаю на комфорт шину и оттуда буду читать температуру за бортом, нажатие кнопок на магнитоле и руле и сообщения от магнитолы на дисплей.

То что ты расшифровал в логе по скорости- проверю.

Bersenev
18.07.2015, 00:19
В итоге всётаки выходит что мне проще читать через OBD II данные.
Мне на самом деле нужно просто повторить показания на экране бортового компа.
А всё остальное это уже баловство.
А на экране отображается
1 Расход на 100
2 Моментальный расход
3 Расстояние которое можно проехать до заправки
4 Трип счётчик



Ничего этого в OBDII нет, всё это вычисляется на основании других показаний. А вот выудить эти данные из кан шины которая идёт на родной монитор вполне возможно, если только бортовой компьютер реализован не в самом мониторе. Если же в мониторе, но в шине ничего этого не будет.

T_r_D
19.07.2015, 01:19
Bersenev А это мы скоро узнаем :)
TJA1054T уже давно заказана и едет из китая.
Переделаю шилд под комфорт шину и буду ловить дальше пакеты и надеюсь расшифровывать их при твоём участие.
И тут ещё у народа наработки есть. Так что думаю всё получится.

А про то что данных которые мне нужны нету в шинах это я понимаю.
Но одно дело искать в небольшом количестве данных, а другое выуживать это из тонны.

Я пришёл к мнению что данные о машине и трипе буду снимать torque, а с комфорт шины перехватывать сообщения для дисплея чтоб его заменить без потерь и нажатие разных кнопок в машине.

В итоге цель выглядит так:
Выкинуть дисплей на котором отображаются
Параметры машины что писал выше (по одному параметру и меняются при нажатии кнопки на лепестке дворников). Если torque их покажет, то не нужны.
Градусник. Тоже если torque покажет, то не нужен.
Текстовые сообщения от систем автомобиля (открытая дверь, риск обледенения и так далее)
Текстовые сообщения от магнитолы (хотя я думаю что это один и тот же пакет или несколько пакетов)

Отлавливание нажатий кнопок на руле и подрулевых.
Отлавливание нажатия кнопок на магнитоле.

Штатная голова пока останется в машине в виде радио и усилителя для планшета. Планшету будет выделена функция утраченного дисплея бортовика+ torque+ навигация+ музыки с флешки.
Если приём радио меня устроит или я дойду до покупки внешнего FM USB приёмника, то голову тоже вытащу и спаяю усилитель.

T_r_D
19.07.2015, 16:31
TJA1054 приехала.
Время ща нет, но в следующее воскресенье вытравлю платку и соединю с шилдом.
Подключу к машине или не успею- не знаю.

T_r_D
01.08.2015, 12:35
Пока ни как не собирусь с платой. Время совсем нет.
Но покопал инет пока жду elm327 и пишут что он не умеет читать с ситроена данные по топливу.

Поэтому созрела идея, но найти ни чего путного не могу.
Короче что нужно FT раскапывать- понятно.
Там всё это есть и чувствует себя хорошо.
Но что делать с софтом? Не смотреть же это через терминал!
И тут пришла идея! А можно ли сделать так, чтоб ардуина прикинулась elm327 для планшета и torque?
Тогда можно torque кормить любой инфой которой пожелаешь!

autowp
11.08.2015, 23:04
Приветствую.

Я тут мимо проходил и заметил, что могу быть полезным:
http://autowp.github.io/ - я тут насобирал кой чего по CAN Comfort ... в 0x221 расход упоминается (правда не уверен, что тот, который надо, это все-таки расход по выбранному режиму треккомпа, но как отправная точка сгодится)

Ну и это, если есть чего добавить, you are welcome https://github.com/autowp/autowp.github.io

T_r_D
15.08.2015, 09:52
autowp Я видел твои изыскания.
Очень помогут.
Ща правда новая работа и время ноль и второе- не хочу гадить шилд за 700р переделкой. Так что закажу дешёвые can-bus платки и на них перепаяю.

Пришёл ELM327. Проверил.
В принципе он всё показывает. Немного не совпадает с бортовиком, но это где-то можно подкорректировать.
Выдаёт кучу ненужных мне параметров, но в их числе и нужные.
Такие как мгновенный расход и расход на 100. Ещё из полезного температуру охлаждайки показывает и напряжение.

От комфорт шины теперь требуются кнопки, температура окружающей среды и то что сыпет магнитола на экран. Плюс всякие ништяки типо открытых дверей, ICE Alert.

Второй вопрос уже более актуальный- как связаться с ардуиной с андройда?
Причём чипы USB у китайских CH341.
Я с андройдом ну совсем не друг и понять не могу не фига.

Нужно будет написать мелкую прогу чтоб отображалась полосой на экране на которой будет собственно сообщения от магнитолы, о открытых дверях, температуре и так далее.

autowp
15.08.2015, 15:29
Сообщения ICE и т.п. ты видел в моём файле. Показывать их легко. Но надо будет предварительно снять дисплей и забрутфорсить весь спиок, потому что передаются они дисплею кодами, а текст зашит в нём самом. Я свой и еще один забрутфорсил, но от машины к машине список меняется (дополняется).

Взаимодействовать с андроидом достаточно не сложно. На китайском usb-uart ещё не пробовал, но под ft232 код готовый есть.

T_r_D
06.09.2015, 22:47
Чего-то фигня с почтой России какая-то!
Очень долго всё идёт.
Уже попробовать хочется!

По поводу софтины. Нашёл вот такую
http://www.danielespinetti.it/2012/11/android-arduino-leds-control.html
Сорри за сторонний ресурс.

Время попробовать опять таки нет.

autowp
Я кстати хотел узнать как передаётся инфа дисплею, а ты уже ответил. :)
Кстати какая распиновка на дисплее разъёма? CAN шину хочу для экспериментов с его разъёма взять.

Дисплей я и так сниму. Новая рамка всётаки почтой пришла. Ща потихоньку планшет туда приделываю.

Как его брутофорсить? У меня стандартный строчечный.
Скорее не от машине к машине, а от типа дисплея к типу.
И скорее всего по шине идут все данные, а то замена дисплеев была бы не возможна.

autowp
06.09.2015, 23:55
Как его брутофорсить? У меня стандартный строчечный.
Скорее не от машине к машине, а от типа дисплея к типу.


Да прям так: поочередно выставлять на шине каждый код сообщения об ошибке. Благо, их всего 255 и большинство я уже внёс в таблицу.

>>И скорее всего по шине идут все данные, а то замена дисплеев была бы не возможна.

Не исключено, что она и невозможна, формально. Просто самые базовые коды сообщений пересекаются, а различия в редких никто и не замечает на практике.

T_r_D
08.09.2015, 13:07
Ну чтож- всё приехало!
Ура.
Собственно список:
Ардуина: http://www.ebay.com/itm/MINI-USB-Nano-V3-0-ATmega328P-CH340G-5V-16M-Micro-controller-board-Arduino-/161403910939?hash=item25946c3b1b
TJA1054: http://www.ebay.com/itm/380556314485?_trksid=p2060353.m2749.l2649&ssPageName=STRK%3AMEBIDX%3AIT
CAN шилд: http://www.ebay.com/itm/311379482437?_trksid=p2060353.m2749.l2649&ssPageName=STRK%3AMEBIDX%3AIT
Платка для TJA: http://www.ebay.com/itm/281675279651?_trksid=p2060353.m2749.l2649&var=580680568078&ssPageName=STRK%3AMEBIDX%3AIT

Спаяно всё вместе, перепаяна TJA1050 на TJA1054. Здесь платка очень помогла!
Комп показал INIT OK. В машине ещё не проверял.

Надо узнать какого цвета провода CAN на магнитоле.

PS. С той Программой не завелась на Андройде она только для UNO, а вот с UNO работает нормально.
Завелась с этой http://www.wch.cn/download/CH341SER_ANDROID_ZIP.html
Но что делать дальше я не знаю совсем под андройдом.

ещё есть вот такая:
https://github.com/mik3y/usb-serial-for-android
Но пока под андройд я писать ни чего не умею.

autowp
08.09.2015, 13:46
Лучше бы TJA1055 брал. Обратно совместима, но с некоторым улучшениями.

Лучше распиновку смотреть, а не по цвету ориентироваться.
http://citroens-club.ru/forum/index.php?showtopic=8919

xmetal
08.09.2015, 15:41
Спаяно всё вместе, перепаяна TJA1050 на TJA1054. Здесь платка очень помогла!Платку можно насадить и припаять на пины H/L Кан шилда, перевернув ее микросхемой вниз, получится компактно. Я себе так сделал.

T_r_D
09.09.2015, 12:55
autowp да ктож знал!
А Вообще пофиг. Она чисто под проект бралась.

T_r_D
03.10.2015, 16:22
Пока до машины не добрался, но пришла ардуина Pro micro.
Модифицировал файлы HID.cpp и USBAPI.h чтоб заработали мультимедиа функции.
http://stefanjones.ca/blog/arduino-leonardo-remote-multimedia-keys/

Зашил скетч
void setup() {
Serial.begin(19200);
}

void loop() {
delay(5000);
Remote.play();
Remote.clear();
Serial.println("I work!");

}
и о чудо- плеер начинает воспроизведение, а в порт пишется надпись.
Тоесть то что мне и нужно!
Далее делать буду на этой ардуине, но я уже спаял всё вместе на nano так что снифить CAN буду на ней.

T_r_D
07.10.2015, 12:28
Итак.
Добрался до машины, подключился и снял два лога.
Первый это лог с включённым зажиганием, а второй просто магнитола.

На готовых логах мне кто объяснит как прочитать сообщение на экране от магнитолы? В логе сверху написано что было на дисплее в этот момент.

Лог снят скетчем из сообщения 7 http://www.pccar.ru/showpost.php?p=332906&postcount=7
(первое число ID а далее сообщение)


autowp За табличку отдельное спасибо!

Ловите скетч который я правлю и пишу. Там всё передаётся в сериал порт и соответственно всё подписано.


#include <SPI.h>
#include "mcp_can.h"
MCP_CAN CAN(10);
unsigned char len = 0;
unsigned char buf[8];
INT32U canId = 0x000; // идентификаторы могут быть 11-ти или 29-битные
int incomingByte = 0;
int Y = 1;

//Все проверенные параметры
float Themperature = 0;
int RPM = 0;
int ARCFL = 0;
float Speed = 0;
float ILPK = 0;
int Odometr = 0;

//Кнопки на руле
char* SEERINGWHILEMESSAGE[] = {"All release","VOLUME DOWN","VOLUME UP","VOLUME MUTE","TRACK FORWARD"};
int SWK = 0;
int SWSV = 0;

//Кнопки на магнитоле
char* RADIOKEY[] = {"All release","MENU","MODE","DARK","ESC","UP","DOWN","LEFT","RIGHT"};
int RK = 0;

//Частота и бэнды
char* RADIOBAND[] = {"FM1","FM2","FM AST","AM"};
int RB = 0;
float RFR = 0;

//Магнитола ON/OFF
char* RADIOPOWER[] = {"OFF","ON"};
int RP = 0;

//Источник радио
char* RADIOSOURCE[] = {"Radio","CD","CD Changer"};
int RS = 0;

//Громкость
int VOL = 0;

void setup()
{
Serial.begin(115200);

START_INIT:

if(CAN_OK == CAN.begin(CAN_125KBPS,MCP_8MHz))
{
Serial.println("Init OK!");
}
else
{
Serial.println("Init fail");
delay(100);
goto START_INIT;
}
Serial.println("a = All mesage");
Serial.println("b = Speed");
Serial.println("c = RPM");
Serial.println("d = Instant fuel consumption /100Km");
Serial.println("e = Run on current fuel level");
Serial.println("f = Themperature");
Serial.println("g = Steering while Scroll value");
Serial.println("h = Steering while");
Serial.println("i = Radio key");
Serial.println("j = Radio ON/OFF");
Serial.println("k = Radio source");
Serial.println("l = Radio band and frequency");
Serial.println("m = Volume");
}


void loop()
{
if (Serial.available() > 0)
{incomingByte = Serial.read();}

if (incomingByte == 97)
{
if(CAN_MSGAVAIL == CAN.checkReceive()) // check if data coming
{
CAN.readMsgBuf(&len, buf);
canId = CAN.getCanId();
Serial.print("<");
Serial.print(canId);
Serial.print(",");
for(int i = 0; i<len; i++)
{
Serial.print(buf[i]);
Serial.print(",");
}
Serial.println(">");
}
}


else
{
if(CAN_MSGAVAIL == CAN.checkReceive()) // check if data coming
{
CAN.readMsgBuf(&len, buf);
canId = CAN.getCanId();

if(canId == 246) //0F6
{
Themperature = buf[6];
Themperature = (Themperature / 2) - 39.5;

Odometr = ((int)buf[2] * 256 | buf[3]);
Odometr = ((int)Odometr * 256 | buf[4]);

if (Odometr != Y)
{
Serial.print("Odometr: ");
Serial.print(Odometr);
Serial.print(" ");
Serial.print(buf[2]);
Serial.print(" ");
Serial.print(buf[3]);
Serial.print(" ");
Serial.println(buf[4]);
Y = Odometr;
}
}

//Обороты и скорость
if(canId == 182) //0B6
{
RPM = (int)buf[0] << 5 | buf[1] >> 3;
Speed = ((int)buf[2] << 8 | buf[3]);
Speed = Speed / 100;
}

//Километры на остатке топлива и моментальный расход
if(canId == 545) //221
{
ARCFL = (int)buf[3] << 8 | buf[4];
ILPK = ((int)buf[1] << 8 | buf[2]);
ILPK = ILPK / 10; // Если -1 то показаний нет

// Serial.print("Rest of run to finish: ");
// Serial.println((int)buf[5] << 8 | buf[6]);
}

//Кнопки на руле справа
if(canId == 543) //21F
{
SWSV = buf[1];
if(buf[0] == 0){SWK = 0;}
if(buf[0] == 4){SWK = 1;}
if(buf[0] == 8){SWK = 2;}
if(buf[0] == 12){SWK = 3;}
if(buf[0] == 128){SWK = 4;}
}

//Кнопки магнитолы
//последнии два байта какой-то мусор
//проподает при выключении магнитолы
if(canId == 997) //3E5
{
if(buf[0] == 0 && buf[1] == 0 && buf[2] == 0 && buf[5] == 0){RK = 0;}
if(buf[0] == 64){RK = 1;} //Menu 64
if(buf[1] == 16){RK = 2;} //Mode 16
if(buf[2] == 4){RK = 3;} //Dark 4
if(buf[2] == 16){RK = 4;} //Esc 16
if(buf[5] == 64){RK = 5;} //UP 64
if(buf[5] == 16){RK = 6;} //DOWN 16
if(buf[5] == 1){RK = 7;} //LEFT 1
if(buf[5] == 4){RK = 8;} //RIGHT 4
}

//Включено или нет радио, источник на радио
if(canId == 357) //165
{
if (buf[0] == 192){RP = 1;} else {RP = 0;}
if (buf[2] == 16){RS = 0;}
if (buf[2] == 32){RS = 1;}
if (buf[2] == 48){RS = 2;}
}

//Банды и частота радио
//первые 2 меняются иногда, последнии 3 незнамо что (мусор или уровень сигнала),
//частота и мусор не пропадают при отключении магнитолы
if(canId == 549) //225
{
if(buf[2] == 16){RB = 0; RFR = buf[3] * 256 + buf[4];RFR = RFR / 20 + 50;}//FM1
if(buf[2] == 32){RB = 1; RFR = buf[3] * 256 + buf[4];RFR = RFR / 20 + 50;}//FM2
if(buf[2] == 64){RB = 2; RFR = buf[3] * 256 + buf[4];RFR = RFR / 20 + 50;}//FM AST
if(buf[2] == 80){RB = 3; RFR = buf[3] * 256 + buf[4];} //AM
}

if(canId == 421) //1A5
{
VOL = buf[0];
}

//Выводим данные.
if (incomingByte == 98){;Serial.print("Speed: "); Serial.println(Speed);}
if (incomingByte == 99){Serial.print("RPM: "); Serial.println(RPM);}
if (incomingByte == 100){Serial.print("Instant fuel consumption /100Km: "); Serial.println(ILPK);}
if (incomingByte == 101){Serial.print("Run on current fuel level: "); Serial.println(ARCFL);}
if (incomingByte == 102){Serial.print("Themperature: "); Serial.println(Themperature);}
if (incomingByte == 103){Serial.print("Steering while Scroll value: "); Serial.println(SWSV);}
if (incomingByte == 104){Serial.print("Steering while: "); Serial.println(SEERINGWHILEMESSAGE[SWK]);}
if (incomingByte == 105){Serial.print("Radio key: "); Serial.println(RADIOKEY[RK]);}
if (incomingByte == 106){Serial.print("Radio ON/OFF: "); Serial.println(RADIOPOWER[RP]);}
if (incomingByte == 107){Serial.print("Radio source: "); Serial.println(RADIOSOURCE[RS]);}
if (incomingByte == 108){Serial.print("Radio band and frequency: "); Serial.print(RADIOBAND[RB]); Serial.print(" "); Serial.println(RFR);}
if (incomingByte == 109){Serial.print("Volume: "); Serial.println(VOL);}
}
}
}

autowp
07.10.2015, 17:33
Нулевой байт. Ну да- это обороты, но меньше в 33 раза
Так что нужно умножать на 33. Для того чтоб вычислить это 33 пришлось ELM327 подключать.

Повнимательнее.

Ну нулевой байт, а первые 13 бит. Ну и уже если первый байт, то не 33, а 32 (2^5)

autowp
07.10.2015, 19:01
У меня это ID 246 в DEC и само сообщение 128,60,17,29,39,91,91,160.

246 в DEC это и есть 0x0F6



Если в DEC считать, то 91/2-39.5 то почти всё правильно.
Если 91 перевести в HEX то получается билиберда.
Так что может нужно не 39,5 вычитать, а 39? Откуда вообще взято было 39,5?
Это взято из дальнейшего замера где на дисплее было 4, а по расчётам получалось 3,5.

Не понимаю связи между "перевести в HEX то получается билиберда" и "Так что может нужно не 39,5 вычитать, а 39".

На сколько я помню, 39.5, а не 39, как раз для того, чтобы после округления получалось точно как на дисплее.
На шине температура дается на 1 бит более точно, чем на экране. Дисплей или округляет, или отбрасывает (floor) младший бит, доподлинно установить не представляется возможным.
Я решил, что он округляет, поэтому такая формула.

T_r_D
08.10.2015, 13:26
Итак, разобрались чутка.
В скетч ща внесу то что заработало.

Кто с одометром поможет и с радио?

Вот такие числа и реальный пробег
Последнее меняется раз в 100 метров
17 36 62 | 112339
17 36 63 | 112339
17 36 64 | 112339
17 36 65 | 112339
17 36 66 | 112339
17 36 67 | 112339
17 36 68 | 112339
17 36 69 | 112339
17 36 70 | 112339
17 36 71 | 112339
17 36 72 | 112340
17 36 73 | 112340
17 36 74 | 112340

Для магнитолы
данные частота
32 0 16 2 238 | 87.5
32 0 16 2 240 | 87.6
32 0 16 2 242 | 87.7
32 0 16 2 244 | 87.8
32 0 16 2 246 | 87.9
32 0 16 2 248 | 88.0
32 0 16 2 250 | 88.1
32 0 16 2 252 | 88.2
32 0 16 2 254 | 88.3
32 0 16 3 0 | 88.4
32 0 16 3 2 | 88.5
32 0 16 3 4 | 88.6
32 0 16 3 6 | 88.7
32 0 16 3 8 | 88.8
32 0 16 4 136 | 108.0
|||||16 FM1
|||||32 FM2
|||||64 FM AST
|||||80 AM


32 0 80 2 19 | 531KHZ
32 0 80 2 20 | 532KHZ
32 0 80 2 21 | 533KHZ
32 0 80 2 255 | 767KHZ

xmetal
10.10.2015, 15:49
Прикинул, по радио получилось так:
Для АМ два байта 2 19 это и есть 531, то есть считать ничего не нужно.
Для FM получилась такая формула X/20+50, например два байта 2 244, это будет 756/20+50=87.8, 4 и 136 - 1160/20+50=108

T_r_D
10.10.2015, 15:59
Прикинул, по радио получилось так:
Для АМ два байта 2 19 это и есть 531, то есть считать ничего не нужно.
Для FM получилась такая формула X/20+50, например два байта 2 244, это будет 756/20+50=87.8, 4 и 136 - 1160/20+50=108

Для FM таже формула вышла только вот так :)
((byte3 * 256) + byte4) / 2 + 500

А для одометра есть идеи?

xmetal
10.10.2015, 16:09
я бы так записал ((bite3<<8) + byte4) / 20 + 50. По одометру идей пока нет.

T_r_D
10.10.2015, 16:52
По одометру скатаюсь на работу сегодня и обратно и посмотрим что покажет.

Там впереди самое сложное останется.
Найти расход на 100км (моментальный уже есть), передачу RDS сообщений от магнитолы и второй трип счётчик который на бортовике отображается.
В принципе мне больше ни чего и не надо.

Это позволит перенести все показания которые отображаются ща на бортовике в планшет не прибегая к загрузке основной шины ELM327.

xmetal
10.10.2015, 17:27
Появились мысли по одометру. Это 3 байтное число. Показания округляются отбрасывая последнюю цифру, на самом деле там:
17 36 70 - 1123398
17 36 71 - 1123399
17 36 72 - 1123400
17 36 73 - 1123401
17 36 74 - 1123402
и тд

T_r_D
11.10.2015, 12:38
Прокатился.
Вот что стало
17 38 174 112401

xmetal
так я изначально 3 байта давал имея в виду что это только одометр

Как это преобразование написать в коде-то?

lti1
11.10.2015, 13:57
Прокатился.
Вот что стало
17 38 174 112401

xmetal
так я изначально 3 байта давал имея в виду что это только одометр

Как это преобразование написать в коде-то?
17 38 174 в Bin это 00010001 00100110 10101110
000100010010011010101110 в Dec 1124014
То есть, что бы получить фактический пробег нужно считать так:
((bite2<<16) + (bite1<<8) + byte0) / 10

xmetal
11.10.2015, 14:20
Не забываем про приведение типов
unsigned long result = (((unsigned long)data[0] << 16) + ((unsigned int)data[1] << 8) + data[2])/10;

byte data[3] = {17,38,174};

void setup() {
Serial.begin(115200);
}

void loop() {
unsigned long result = (((unsigned long)data[0] << 16) + ((unsigned int)data[1] << 8) + data[2])/10;
Serial.println(result);
delay(1000);
}

T_r_D
11.10.2015, 14:48
(unsigned long)data[0] << 16)
Вот оно что!
я писал
(int)buf[2] << 16 | (int)buf[3] << 8| buf[4]
и у меня выходила охинея
Просто данные не входили!
Во блин!

Зато пока искал причину- нашёл где расход на 100км не моментальный.
2A1 байты 3 и 4

Почти всё отискал :)
Осталось найти где данные от кнопок стрелочек магнитолы в режиме отличного от меню
и данные которые передаются текстом о названии радиостанции и данные которые она передаёт

lti1
11.10.2015, 14:52
xmetal, собственно так и есть, как Вы выше писали.
T_r_D, int (http://www.arduino.ru/Reference/Int) занимает 2 байта, а unsigned long (http://www.arduino.ru/Reference/UnsignedLong) 4 байта. У Вас получается 3, по этому и получалась охинея.

T_r_D
11.10.2015, 15:16
Я уже осознал свою ошибку.

Народ- сильно не бейте! Я программированием занимался последний раз лет так 15 назад.

А по существу.
Я уже имею почти все данные кроме трипа который отображается на бортовике (не знаю нафига он мне) и нету текстовой инфы с магнитолы.
На остальное описание вроде есть, добавлю в скетч и посмотрю что получается (читать данные о CD и CD Changer), а так же вывод данных настроек (Menu).
Ещё там всякие Loud, TA, RDS и прочая шняга буковками выводится, но на это тоже вроде есть описание.
Ну и надо найти где прячут нажатие на стрелочки не в режиме Menu, а так же кнопки с 1 по 6.

Тоесть по сути я чисто для себя уже заменил TORQE. Нужно ещё сделать вольтметр или поискать передаётся ли эта инфа по шине.
Пока сидел в машине, то пришла в голову идея выкинуть нафиг блок климата, а кондеем управлять с планшета.

И тут кстати я подхожу к моменту когда нужно будет писать оболочку под это всё под андройд, а в этом я уж точно чайник!

весь список того что ща уже можно читать
Speed
RPM
Instant fuel consumption /100Km
Fuel consumption /100Km
Run on current fuel level
Odometr
Themperature (not water temp)
Steering while Scroll value
Steering while key
Radio key (частично)
Radio ON/OFF
Radio source
Radio band and frequency
Volume (выводится на секунду, нужно найти где всегда инфа есть)

Нашёл где трип прячется
2A1 байты 1 и 2

Пытался там же найти среднею скорость, но толи она не так же как всё выглядит, толи она просто не там.

T_r_D
13.10.2015, 22:37
Народ, помогите с выдёргиванием инфы из
1E5 байта 5.
первые два
бита это показывает меню или нет и значение этого меню.
3 бит второе меню, 4 не используется, 5,6,7 значение второго меню.
Как в коде это воплотить?
Не могу не фига сообразить!
хотелось бы в виде
if (buf[5] >> 7 == 1)
без дополнительных переменных.
Как избавится от лишних данных в байте?

lti1
13.10.2015, 23:00
Народ, помогите с выдёргиванием инфы из
1E5 байта 5.
первые два
бита это показывает меню или нет и значение этого меню.
3 бит второе меню, 4 не используется, 5,6,7 значение второго меню.
Как в коде это воплотить?
Не могу не фига сообразить!
хотелось бы в виде
if (buf[5] >> 7 == 1)
без дополнительных переменных.
Как избавится от лишних данных в байте?
Не совсем понятно, что Вы имеете ввиду, может это:
if (bitRead(buf[5], 6) == 1)

T_r_D
15.10.2015, 00:46
Не совсем понятно, что Вы имеете ввиду, может это:
if (bitRead(buf[5], 6) == 1)

ВО СПАСИБО!
Именно это и имел в виду!

и тогда вопрос в догонку.
Это один бит считать, а считать скажем два или три и получить число?
Ну тоесть в моём случае вытащить значение меню.
Есть такой же простой способ?

lti1
15.10.2015, 10:14
ВО СПАСИБО!
Именно это и имел в виду!

и тогда вопрос в догонку.
Это один бит считать, а считать скажем два или три и получить число?
Ну тоесть в моём случае вытащить значение меню.
Есть такой же простой способ?
Один из вариантов так:
int per;

bitWrite(per, 0, bitRead(buf[5], 5));
bitWrite(per, 1, bitRead(buf[5], 6));
bitWrite(per, 2, bitRead(buf[5], 7));

xmetal
15.10.2015, 12:12
Есть способ проще. Любые биты или группу бит можно проверить битовой маской: if ((buf[5] & 0x70) >> 4 == 7) - проверяем 5,6,7 биты, если они все в 1, то условие срабатывает.

Для наглядности маску можно написать в битовом виде: if ((buf[5] & B01110000) >> 4 == 7)

T_r_D
16.10.2015, 01:28
Вот так
if (bitRead(buf[5], 6) == 1)
и так
if (buf[5], 6 == 1)
Hе работает!

Хорошая была попытка.
Ещё есть идеи?

А, стоп! Заработало. Я не учёл что оно с право налево идёт.

За одно походу нашлась средняя скорость.

И в догонку.
Ардуина с шилдом тормозят.
Похоже что надо поставить апаратный фильтр в шилде, а то очень много сообщений сыпется.
Как это реализовать?

T_r_D
17.10.2015, 01:25
Всё, с показаниями бортового компа полностью закончено.
Читаю все параметры что есть на экране!
Speed
RPM
Instant fuel consumption /100Km
Fuel consumption /100Km
Trip
Average Speed
Themperature
Odometr
Run on current fuel level

Средняя скорость была в 0B6 байт 0.
Целиком байт это скорость без каких либо конвертаций.

Что осталось:
ну раз уж сдублировали с основного дисплея одометр и скорость, то надо и всё сдублировать :)
А осталось там
1 Уровень топлива
2 Температура охлаждайки
3 Остаток пробега до ТО
4 Уровень масла
5 Ограничитель и круиз
6 Трип

Ну и доделать сообщения в меню настройки, докопать кнопки на магнитоле.
Время к сожалению очень мало на это всё.
И нужно какую нить программу анализа данных.
Я вижу это так:

в первом столбце все ID найденных сообщение
во втором сами посылки
если было какое изменение, то перенос старой посылки в третий столбец

Может кто знает такую готовую прогу или готов написать?
А то в ручную отлавливать каждое сообщение очень геморно.

Ну и желательно чтоб прога могла с логом работать.
Тоесть данные устаканились- снял лог экрана проги, потом его загрузил и сравнил с новыми данными.
Это актуально для таких затяжных параметров как прогрев двигателя и топливо.

lti1
17.10.2015, 07:41
И нужно какую нить программу анализа данных.
Я вижу это так:

в первом столбце все ID найденных сообщение
во втором сами посылки
если было какое изменение, то перенос старой посылки в третий столбец

Может кто знает такую готовую прогу или готов написать?
А то в ручную отлавливать каждое сообщение очень геморно.

Ну и желательно чтоб прога могла с логом работать.
Тоесть данные устаканились- снял лог экрана проги, потом его загрузил и сравнил с новыми данными.
Это актуально для таких затяжных параметров как прогрев двигателя и топливо.http://techtinker.co.za/index.php/11-sniffing-the-can-bus-with-the-supersniffer-software-free

T_r_D
17.10.2015, 12:05
http://techtinker.co.za/index.php/11-sniffing-the-can-bus-with-the-supersniffer-software-free

Вот спасибо! А то уже заручился руками файлы логов перекапывать.
Так веселее пойдёт.

lti1
17.10.2015, 14:17
Вот спасибо! А то уже заручился руками файлы логов перекапывать.
Так веселее пойдёт.Не за что!
Только мне родной скетч не понравился, я пользовался во этим:#include <mcp_can.h>
#include <SPI.h>

long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];

MCP_CAN CAN0(10);

void setup()
{
Serial.begin(38400);
CAN0.begin(CAN_125KBPS); // скорость CAN шины
pinMode(2, INPUT);
}

void loop()
{
if(!digitalRead(2))
{
CAN0.readMsgBuf(&len, rxBuf);
rxId = CAN0.getCanId();

{
Serial.print("<");
Serial.print(rxId);
for(int i = 0; i<len; i++)
{
Serial.print(", ");
if(rxBuf[i] < 0x10) Serial.print("0");
Serial.print(rxBuf[i], HEX);
}
Serial.print(">");
Serial.println();
}
}
}

T_r_D
18.10.2015, 01:53
Не за что!
Только мне родной скетч не понравился, я пользовался во этим:

Да это не особо важно как писать скетч, главное чтоб прога обрабатывала.

Ну и сообщений там не очень много идёт, так что вид не важен- чисто эстетика.

T_r_D
20.10.2015, 23:34
Помогите ещё чутка.
есть бит в котором
01022222
0 - не используются
1 - активно меню или нет
2 - данные меню.
Пишу вот так (переменная равна int)
AM = buf[6] << 3;
Serial.println(AM);
По моему мнению это должно заставить сообщение принять вид
22222000
но в реале почему-то получаю число типо 696.
Этого числа вообще тут быть не может!
При этом видно что значения меняются и данные ячеек меню тоже.

Что я не так делаю?

Вот кусок кода
if(canId == 485) //1E5
{
if (bitRead(buf[0],7) == 1){AP = 1; APV = (buf[0] << 1 / 2) - 191; AM = 0;}
if (bitRead(buf[1],7) == 1){AP = 2; APV = (buf[1] << 1 / 2) - 191; AM = 0;}
if (bitRead(buf[2],7) == 1){AP = 3; APV = (buf[2] << 1 / 2) - 191; AM = 0;}
if (bitRead(buf[4],7) == 1){AP = 4; APV = (buf[4] << 1 / 2) - 191; AM = 0;}
if (bitRead(buf[5],7) == 1){AP = 5; APV = bitRead(buf[5],6); AM = 0;}
if (bitRead(buf[5],4) == 1){AP = 6; APV = bitRead(buf[5],2); AM = 0;}
if (bitRead(buf[6],6) == 1){AP = 7; APV = 0; AM = buf[6] << 3;}
}
Serial.println(AM);

значение в этом байте такие.
00011 None
00111 Classical
01011 Jazz-Blues
01111 Pop-Rock
10011 Vocal
10111 Techno
полностью сообщение с активным меню и предустановкой Classic выглядит как
01000111

autowp
20.10.2015, 23:53
Ты путаешь биты и байты.
Бит может быть 0 или 1. 2 быть не может.

Сдвиг осуществляется побитно, а не побайтно.

Хотя код выглядит логично, о каких 22222 речь совершенно не понятно

lti1
21.10.2015, 01:36
T_r_D, попробуйте так:

if (bitRead(buf[6],6) == 1){AP = 7; APV = 0; AM = buf[6]^=1<<6;}

В итоге в переменной AM получите:

3 или 00000011 None
7 или 00000111 Classical
11 или 00001011 Jazz-Blues
15 или 00001111 Pop-Rock
19 или 00010011 Vocal
23 или 00010111 Techno

GASCHE
21.10.2015, 09:59
Помогите ещё чутка... 01000111
Я бы побитно сложил ваш байт и маску 00111111
Res := 01000111 AND 00111111, а результат Res = 00000111 проверял на нужные вам цифры 3, 7... И учитывая что последние два бита не несут нужной вам информации или вы не знаете что они означают, я бы их убрал сложением с маской 00111100 с соответствующим перерасчетом цифр 3, 7...

T_r_D
21.10.2015, 12:12
Ты путаешь биты и байты.
Бит может быть 0 или 1. 2 быть не может.

Сдвиг осуществляется побитно, а не побайтно.

Хотя код выглядит логично, о каких 22222 речь совершенно не понятно

А запись вида xyxzzzzz тебя больше устраивает?
Где x не используемые биты
y бит состояния меню
И z содержание меню.

T_r_D
21.10.2015, 12:27
T_r_D, попробуйте так:

if (bitRead(buf[6],6) == 1){AP = 7; APV = 0; AM = buf[6]^=1<<6;}

В итоге в переменной AM получите:

3 или 00000011 None
7 или 00000111 Classical
11 или 00001011 Jazz-Blues
15 или 00001111 Pop-Rock
19 или 00010011 Vocal
23 или 00010111 Techno
А что означает buf[6]^=1<<6 ?

И почему моё смещение не приводит к такому результату?
По сути я хочу первые 5 бит переместить в начало обнулив последним 3
Мне кажется что при смещении какой-то мусор прилетает.
Может сначала спаять с байтом забитым нулями, а потом сместить?
Только хочется это по компактнее расписать, а не с кучей строк и условий.

xmetal
21.10.2015, 13:15
И почему моё смещение не приводит к такому результату?
По сути я хочу первые 5 бит переместить в начало обнулив последним 3
.Похоже, что при вычислениях все типы по умолчанию приводятся к результирующему типу, а он у тебя int. Поправьте меня, если я не прав. Тогда нужно делать так, если AM нужен int:
if (bitRead(buf[6],6) == 1){AP = 7; APV = 0; AM = (unsigned char)(buf[6] << 3);}

А что означает buf[6]^=1<<6 ?1 смещается на 6 бит влево и логически (XOR) побитово складывается с buf[6]. То есть, если биты одинаковые, то результирующий бит будет 0, если разные то 1. Но похоже это не то, что нужно, так как, если в 7 бите buf[6] будет 0, то после этой операции там станет 1 и результат будет опять не тот.

xmetal
21.10.2015, 14:38
Извиняюсь, ввел в заблуждение.:huh2: В данном случае buf[6]^=1<<6 будет отрабатывать как надо, так как стоит проверка if (bitRead(buf[6],6) == 1).

T_r_D
21.10.2015, 16:26
Извиняюсь, ввел в заблуждение.:huh2: В данном случае buf[6]^=1<<6 будет отрабатывать как надо, так как стоит проверка if (bitRead(buf[6],6) == 1).

В данном случае да, но нужен универсальный способ.

Вечером попробую сделать вот так
AX = buf[6],0 | buf[6],1 | buf[6],2 | buf[6],3 | buf[6],4;

Ну и способ со смещением
if (bitRead(buf[6],6) == 1){AP = 7; APV = 0; AM = (unsigned char)(buf[6] << 3);}

xmetal
21.10.2015, 16:59
Вечером попробую сделать вот так
AX = buf[6],0 | buf[6],1 | buf[6],2 | buf[6],3 | buf[6],4;
Что это дает?

T_r_D
21.10.2015, 17:29
Что это дает?

Склейку битов по идеи должно дать.
Только надо было не 0-4, а 4-0

xmetal
21.10.2015, 17:51
Так они и так склеены. Тебе надо только отбросить не нужное. Чтобы взять первые 5 бит нужно просто сделать следующее: AX = buf[6] & 0x1F;

T_r_D
21.10.2015, 19:07
НТак они и так склеены. Тебе надо только отбросить не нужное. Чтобы взять первые 5 бит нужно просто сделать следующее: AX = buf[6] & 0x1F;

Вот! Это то, что нужно!
Спасибо

T_r_D
22.10.2015, 01:27
Оттестировал.
Всё заработало нормально.
Всем спасибо!
Заработало вот так
AX = buf[6] & 0x1F;



Теперь можно дальше копать что есть к чему.
Дальше продолжу с поисков всех опций меню.

GASCHE
22.10.2015, 08:41
Заработало вот так
AX = buf[6] & 0x1F;
Удивительно!

T_r_D
22.10.2015, 16:47
Удивительно!

Давайте без флейма

T_r_D
26.10.2015, 13:12
Ещё требуется хелп, а то не соображу.
Получаю по ID 2A5 RDS:

45,69,78,69,82,71,89,45
соответствует -ENERGY- и это ASCII.

Как записать это в переменную в виде символов?
И какого она должна быть типа? String?

lti1
26.10.2015, 16:23
Ещё требуется хелп, а то не соображу.
Получаю по ID 2A5 RDS:

45,69,78,69,82,71,89,45
соответствует -ENERGY- и это ASCII.

Как записать это в переменную в виде символов?
И какого она должна быть типа? String?
Если потом планируете передавать эти данные в винду, можно писать как число, потом отправлять с помощью Serial.write (http://www.arduino.ru/Reference/Serial/Write) for (int i=0; i <= 7; i++) Serial.write(buf[i]); Если в андройд, то так не подойдет.

T_r_D
26.10.2015, 17:16
Если потом планируете передавать эти данные в винду, можно писать как число, потом отправлять с помощью Serial.write (http://www.arduino.ru/Reference/Serial/Write) for (int i=0; i <= 7; i++) Serial.write(buf[i]); Если в андройд, то так не подойдет.

Именно в дройд.

Да и вообще хочу в итоге все получаемые параметры записывать в строку и отправлять целой строкой.
Не одной конечно, разбить на группы.
Ну например если активно радио, то отправлять что-то типо
<RADIO 1|1|100.0|1|RDS>
что будет значить что радио включено (RADIO 1), что выбрано как источник радио (1), на частоте 100.0, банд FM1, ну и сообщение от рдс.

Таких сообщений будет несколько по типу данных.
Пока вижу так:
1 Все данные что отображались на экране трипа (пробег, средняя скорость и т.д.)
2 Данные которые отображаются на верхнем дисплее (скорость одометр и т.д)
3 Включено ли радио и если да, то его источник и в зависимости от источника данные (номер трека, время трека или РДС)
4 Если активно какое либо из меню, то данные этого меню (выбранный элемент и значение элемента)
5 Значки дисплея (LOUD, Play,Pause и т.д)
6 Нажатые кнопки. Как показала практика кнопки нажимаемые на магнитоле нужны только частично.

Собственно это позволит полностью заменить дисплей.

Вот только блин не могу ни как найти сообщения о состояние меню.
Те меню что по кнопкам отдельным открываются- понятно, они есть, а вот те меню что при нажатии на кнопку MENU не могу найти!
Да и то, то меню что по кнопке LIST открывается, открывается жутко криво.
Такое впечатление что данные выдаются только во время нажатия кнопки и естественно ардуина их поймать не всегда успевает.
Так что в последствие очень нужно будет аппаратно шилдом убрать не нужные сообщения и может быть это поможет.

Если уж совсем туго с этим всем будет, то собственно данные трипа я достал из шины, а на радио можно и забить.
Тем более что RD4 это полный шлак по приёму даже в городе. Слушать радио не возможно.
Оставлю на крайняк балалайку эту в виде усилителя и всё.
Тем более я заказал уже модуль радио. Хочу его опробовать.
Есть очень большие опасения что ардуины на всё к тому же не хватит.

lti1
26.10.2015, 19:55
T_r_D, для андойда у меня пока реализовано так:
unsigned code_en[137]={0x20, 0x28, 0x29, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A,
0x0401, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, 0x0451, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F};
char* en[137]={" ", "(", ")", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
"\u0401", "\u0410", "\u0411", "\u0412", "\u0413", "\u0414", "\u0415", "\u0416", "\u0417", "\u0418", "\u0419", "\u041A", "\u041B", "\u041C", "\u041D", "\u041E", "\u041F", "\u0420", "\u0421", "\u0422", "\u0423", "\u0424", "\u0425", "\u0426", "\u0427", "\u0428", "\u0429", "\u042A", "\u042B", "\u042C", "\u042D", "\u042E", "\u042F", "\u0451", "\u0430", "\u0431", "\u0432", "\u0433", "\u0434", "\u0435", "\u0436", "\u0437", "\u0438", "\u0439", "\u043A", "\u043B", "\u043C", "\u043D", "\u043E", "\u043F", "\u0440", "\u0441", "\u0442", "\u0443", "\u0444", "\u0445", "\u0446", "\u0447", "\u0448", "\u0449", "\u044A", "\u044B", "\u044C", "\u044D", "\u044E", "\u044F"};


for(byte j=0; j<137; j++)
{
if(Buf[i]==code_en[j]) Serial.print(en[j]);
}
\u0*** - это русские буквы в юникоде (http://foxtools.ru/Unicode#).
Вот только блин не могу ни как найти сообщения о состояние меню.
Те меню что по кнопкам отдельным открываются- понятно, они есть, а вот те меню что при нажатии на кнопку MENU не могу найти!
У меня похожая ситуация, только с дисплеем FF3.
Есть очень большие опасения что ардуины на всё к тому же не хватит.
Arduino Mega 2560 (http://arduino.ru/Hardware/ArduinoBoardMega2560)
Краткие характеристики

Микроконтроллер ATmega2560
Рабочее напряжение 5В
Входное напряжение (рекомендуемое) 7-12В
Входное напряжение (предельное) 6-20В
Цифровые Входы/Выходы 54 (14 из которых могут работат также как выходы ШИМ)
Аналоговые входы 16
Постоянный ток через вход/выход 40 mA
Постоянный ток для вывода 3.3 В 50 mA
Флеш-память 256 KB (из которых 8 КB используются для загрузчика)
ОЗУ 8 KB
Энергонезависимая память 4 KB
Тактовая частота 16 MHz

T_r_D
27.10.2015, 09:03
T_r_D, для андойда у меня пока реализовано так:
unsigned code_en[137]={0x20, 0x28, 0x29, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A,
0x0401, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, 0x0451, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F};
char* en[137]={" ", "(", ")", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ".", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
"\u0401", "\u0410", "\u0411", "\u0412", "\u0413", "\u0414", "\u0415", "\u0416", "\u0417", "\u0418", "\u0419", "\u041A", "\u041B", "\u041C", "\u041D", "\u041E", "\u041F", "\u0420", "\u0421", "\u0422", "\u0423", "\u0424", "\u0425", "\u0426", "\u0427", "\u0428", "\u0429", "\u042A", "\u042B", "\u042C", "\u042D", "\u042E", "\u042F", "\u0451", "\u0430", "\u0431", "\u0432", "\u0433", "\u0434", "\u0435", "\u0436", "\u0437", "\u0438", "\u0439", "\u043A", "\u043B", "\u043C", "\u043D", "\u043E", "\u043F", "\u0440", "\u0441", "\u0442", "\u0443", "\u0444", "\u0445", "\u0446", "\u0447", "\u0448", "\u0449", "\u044A", "\u044B", "\u044C", "\u044D", "\u044E", "\u044F"};


for(byte j=0; j<137; j++)
{
if(Buf[i]==code_en[j]) Serial.print(en[j]);
}
\u0*** - это русские буквы в юникоде (http://foxtools.ru/Unicode#).

У меня похожая ситуация, только с дисплеем FF3.

Arduino Mega 2560 (http://arduino.ru/Hardware/ArduinoBoardMega2560)
Проще уж цифрами тогда передавать, а на стороне устройства декодировать.

Про мегу всё круто, но что-то я не вижу чтоб она могла клавиатурой прикидываться.

Про меню. Я ща проверю и посмотрю. Возможно сделано так:
В каком-то сообщение содержится состояние меню (активно или нет), а потом уже в нескольких сообщениях его статус.
Или после активации меню дальше просто считаются нажатия вправо или лево и выводятся данные так как если меню исчезнет, то оно открывается всегда на одной и той же вкладке.

Вчера я просто нажимал циклически одну кнопку и искал сообщение которое это отражало бы, но искал я тоже сообщение которое менялось бы количество раз нажатия кнопки.

Поискал. В сообщение с адресом DF пишется активно меню или нет в 0 бит.
Но он обозначает ещё что-то. 132 активно, а есть ещё значения 133 и 134 которые пролетают кратковременно при выборе параметров.
далее там же первый бит выдаёт какую-то инфу при нажатии кнопок вверх и вниз, но кратковременно.
При нажатии влево или вправо выдаёт 1.

lti1
27.10.2015, 10:55
Проще уж цифрами тогда передавать, а на стороне устройства декодировать.

Про мегу всё круто, но что-то я не вижу чтоб она могла клавиатурой прикидываться.В таком случае лучше переправлять в планшет "сырые" данные с CAN шины и писать приложение которое будет эти данные обрабатывать и выводить, при этом Arduino Micro хватит за глаза.
Mega и не умеет.

T_r_D
27.10.2015, 11:01
В таком случае лучше переправлять в планшет "сырые" данные с CAN шины и писать приложение которое будет эти данные обрабатывать и выводить, при этом Arduino Micro хватит за глаза.
Mega и не умеет.

А вот и не фига её не хватает.
Если брать полностью поток с CAN и делать простейший скетч на выдачу всех сообщений в COM, то задержки начинаются по 2 секунды и некоторые сообщения вообще не видно.
Поэтому и хочу аппаратный фильтр.
Но он будет актуален только после того, как найду последние две искомые величины: управление меню и вывод значков.
Количество "нужных" сообщений в таком случае не должно превысить 30 что, я думаю, будет вполне перевариваемо ардуиной.

T_r_D
27.10.2015, 11:37
И кстати вопрошаю- как написать вот это в рамках ардуиносреды
Прямо сообщение возьму у autowp чтоб было понятно что передаётся в ID 125.
http://www.pccar.ru/showpost.php?p=279220&postcount=44

xmetal
27.10.2015, 18:16
А вот и не фига её не хватает.
Если брать полностью поток с CAN и делать простейший скетч на выдачу всех сообщений в COM, то задержки начинаются по 2 секунды и некоторые сообщения вообще не видно. А если увеличить скорость COM до 250kBaud?

T_r_D
27.10.2015, 19:00
А если увеличить скорость COM до 250kBaud?

А скорость шины всё равно 125 какой смысл?
Тем более это происходит даже при записи данных в переменные внутри микроконтроллера.
Так что только фильтровать сам поток по CAN.
Там идёт очень много не нужного для CarPC.
Не вижу смысла ловить все сообщения.

autowp
27.10.2015, 19:17
125 на бинарном CAN - это совсем не 125 на текстовом UART.
Как минимум потому, что на uart вы передаете в ASCII. И в случае HEX кодирования это в 2 раза больше данных, а в случае DEC и того больше

awtoap
27.10.2015, 19:28
125 на бинарном CAN - это совсем не 125 на текстовом UART.
Как минимум потому, что на uart вы передаете в ASCII. И в случае HEX кодирования это в 2 раза больше данных, а в случае DEC и того больше

Чуш! Скорость будет таже самая.

Можно и МК фильтровать интересующие пиды, а потом передавать на комп, правда нужно прикинуть на сколько будет загружен МК, чтобы можно было дополнительной работай заниматься. Можно еще сильнее разгрузить МК, если подсунуть маску нужных пидов в сам CAN контроллер.

xmetal
27.10.2015, 21:14
А скорость шины всё равно 125 какой смысл?
Смысл в том, что тебе на скорости 125к прилетает из КАН быстрее, чем ты забираешь на 115,2к, тем более в ascii, от сюда и задержки. Это если ловить все сообщения подряд. В принципе ардуино должна справляться с фильтрацией программно. Сколько отлавливаешь "полезных" ID?

T_r_D
27.10.2015, 23:27
Смысл в том, что тебе на скорости 125к прилетает из КАН быстрее, чем ты забираешь на 115,2к, тем более в ascii, от сюда и задержки. Это если ловить все сообщения подряд. В принципе ардуино должна справляться с фильтрацией программно. Сколько отлавливаешь "полезных" ID?

Будет в итоге штук 30 если см менню разбирусь, а если нет, то штук 15.

И настиг чисто технический вопрос использования arduino pro micro.
Значит так, кан шилд использует пин 2 (видимо как int 0).
А модулю радио нужен это пин как SDA.
Как это подружить или переназначить пин SDA или INT0?
Или может это будет работать и так?

xmetal
28.10.2015, 13:23
Будет в итоге штук 30 если см менню разбирусь, а если нет, то штук 15.Вообще странно, что при перехвате сообщений подряд, как ты говоришь, есть пропуски...
И настиг чисто технический вопрос использования arduino pro micro.
Значит так, кан шилд использует пин 2 (видимо как int 0).
А модулю радио нужен это пин как SDA.
Как это подружить или переназначить пин SDA или INT0?
Или может это будет работать и так?Судя по скетчу из 4 страницы пин 2 не используется вообще. Так что можно его не соединять с кан шилдом.

T_r_D
28.10.2015, 13:25
Вообще странно, что при перехвате сообщений подряд, как ты говоришь, есть пропуски...
Судя по скетчу из 4 страницы пин 2 не используется вообще. Так что можно его не соединять с кан шилдом.
Он внутри библиотеки скорее всего используется.
Но я попробую его отпаять :)

Пин 2 законнекчен с выводом 12 (INT) MCP2515

И повторюсь- как вот это повторить на ардуино

125 6 01110000 TTTTTTTT AAAAAAAA 0SXEBBBB MMMMMMMM 00000000 [[JJJJJJJJ x20] [HHHHHHHH x20] x0-4]
6 Показать меню списка треков.
TTTTTTTT - количество треков,
AAAAAAAA - offset экрана списка треков,
S - флаг "покажи список треков"
E - флаг "список треков сдвинулся" на 1 позицию выше или ниже за пределы 4х видимых в данный момент. Направление сдвига определяется по BBBB
BBBB - offset выбранного трека внутри экрана списка треков
MMMMMMMM - дескриптор текстовых данных, идущих далее.
каждая пара бит соответствует наличию исполнителя и названия трека, идущих далее пакетами по 20 байт в соответствующем порядке.
Позиции соответствуют позициям на экране, кроме ситуации наличия флага E
[JJJJJJJJ x20] - 20 байт имени исполнителя
[HHHHHHHH x20] - 20 байт названия трека

125 1 00000000 Спрятать меню списка треков. (Нажатие на OK после выбора трека в LIST, нажатие на ESC, по таймаут)

lti1
28.10.2015, 13:51
А может быть пропуски потому, что не используется пин 2?
Попробуйте этот скетч:
#include <mcp_can.h>
#include <SPI.h>

long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];

MCP_CAN CAN0(10);

void setup()
{
Serial.begin (115200);
CAN0.begin(CAN_500KBPS); // скорость CAN
pinMode(2, INPUT); // пин 2 можно переназначить
}

void loop()
{
if(!digitalRead(2)) // пин 2 можно переназначить
{
CAN0.readMsgBuf(&len, rxBuf);
rxId = CAN0.getCanId();

if (rxId == 0x306) // фильтр по ID, в данном случае по ID 0x306
{

}
}
}

T_r_D
28.10.2015, 14:07
А может быть пропуски потому, что не используется пин 2?
Попробуйте этот скетч:
#include <mcp_can.h>
#include <SPI.h>

long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];

MCP_CAN CAN0(10);

void setup()
{
Serial.begin (115200);
CAN0.begin(CAN_500KBPS); // скорость CAN
pinMode(2, INPUT); // пин 2 можно переназначить
}

void loop()
{
if(!digitalRead(2)) // пин 2 можно переназначить
{
CAN0.readMsgBuf(&len, rxBuf);
rxId = CAN0.getCanId();

if (rxId == 0x306) // фильтр по ID, в данном случае по ID 0x306
{

}
}
}

if(!digitalRead(2)) что тут означает восклицательный знак?

Если я правильно понимаю, то проверяется возникновение чего-то на пине 2, и если оно появилось, то читаем данные из буфера.
У меня написано тоже самое, только проверка делается
if(CAN_MSGAVAIL == CAN.checkReceive())

в библиотеке
INT8U MCP_CAN::checkReceive(void)
{
INT8U res;
res = mcp2515_readStatus(); /* RXnIF in Bit 1 and 0 */
if (res & MCP_STAT_RXIF_MASK)
{
return CAN_MSGAVAIL;
}
else
{
return CAN_NOMSG;
}
}

.....................................
INT8U MCP_CAN::mcp2515_readStatus(void)
{
INT8U i;
MCP2515_SELECT();
spi_readwrite(MCP_READ_STATUS);
i = spi_read();
MCP2515_UNSELECT();

return i;
}

Тоесть я проверяю и так наличие единицы.

xmetal
28.10.2015, 14:12
lti1, вот только подумал тоже самое :smile2:

lti1
28.10.2015, 14:15
if(!digitalRead(2)) что тут означает восклицательный знак?

Если я правильно понимаю, то проверяется возникновение чего-то на пине 2, и если оно появилось, то читаем данные из буфера.
У меня написано тоже самое, только проверка делается
if(CAN_MSGAVAIL == CAN.checkReceive())

в библиотеке
INT8U MCP_CAN::checkReceive(void)
{
INT8U res;
res = mcp2515_readStatus(); /* RXnIF in Bit 1 and 0 */
if (res & MCP_STAT_RXIF_MASK)
{
return CAN_MSGAVAIL;
}
else
{
return CAN_NOMSG;
}
}

.....................................
INT8U MCP_CAN::mcp2515_readStatus(void)
{
INT8U i;
MCP2515_SELECT();
spi_readwrite(MCP_READ_STATUS);
i = spi_read();
MCP2515_UNSELECT();

return i;
}

Тоесть я проверяю и так наличие единицы.
Что тут рассуждать, попробуйте и будет понятно. У меня пропусков нет, скорость CAN 500 kbps.

T_r_D
28.10.2015, 14:22
Что тут рассуждать, попробуйте и будет понятно. У меня пропусков нет, скорость CAN 500 kbps.

А строка-то что означает?
if(!digitalRead(2))
Я блин не как не въеду в синтаксис!
Что делает "!"

xmetal
28.10.2015, 15:05
! - логический оператор. Пример !1=0 (false), !0=1 (true). Если на ножке 0 то условие выполняется

Можно немного ускорить работу, чтобы было поменьше лишних проверок: if(!digitalRead(2)) // check if data coming
{
CAN.readMsgBuf(&len, buf);
canId = CAN.getCanId();

if(canId == 246) //0F6
{
...
goto output; // пропускаем остальные ID
}

if(canId == 182) //0B6
{
...
goto output; // пропускаем остальные ID
}

if(canId == 545) //221
{
...
goto output; // пропускаем остальные ID
}

if(canId == 543) //21F
{
...
goto output; // пропускаем остальные ID
}

if(canId == 997) //3E5
{
...
goto output; // пропускаем остальные ID
}

if(canId == 357) //165
{
...
goto output; // пропускаем остальные ID
}

if(canId == 549) //225
{
...
goto output; // пропускаем остальные ID
}

if(canId == 421) //1A5
{
VOL = buf[0];
}

output: //прыгаем сразу сюда
//Выводим данные.
if (incomingByte == 98){;Serial.print("Speed: "); Serial.println(Speed);}
if (incomingByte == 99){Serial.print("RPM: "); Serial.println(RPM);}
if (incomingByte == 100){Serial.print("Instant fuel consumption /100Km: "); Serial.println(ILPK);}
if (incomingByte == 101){Serial.print("Run on current fuel level: "); Serial.println(ARCFL);}
if (incomingByte == 102){Serial.print("Themperature: "); Serial.println(Themperature);}
...
}

T_r_D
28.10.2015, 18:55
! - логический оператор. Пример !1=0 (false), !0=1 (true). Если на ножке 0 то условие выполняется
[/CODE]

Спасибо.
А про 125 сообщение ни кто не знает как его отобразить?

И всётаки как загнать все данные в одну строку?
Хочу вообще уменьшить скорость выдачи данных в порт.
Если ни чего не поменялось в группе данных, то их и не выводить в порт.
Тогда скорость порта станет вообще не особо критичной.

xmetal
28.10.2015, 22:36
И всётаки как загнать все данные в одну строку?
Может так?
void setup() {
Serial.begin(115200);
}

void loop() {
String str= "string ";
byte data1[8] = {1,2,3,4,5,6,7,8};
byte data2[8] = {8,7,6,5,4,3,2,1};

for(byte i=0; i<8; i++){
str += data1[i];
str += " ";
}

for(byte i=0; i<8; i++){
str += data2[i];
str += " ";
}

Serial.println(str);
delay(5000);
}

T_r_D
29.10.2015, 16:01
Короче получил в лоб от Pro Micro!
подключаю плату кан
10 вывод CS, 16 MOSI, 14 MISO, 15 SCK. (эти выводы идут подряд на самом деле на плате дуины взято отсюда распиновка https://learn.sparkfun.com/tutorials/pro-micro--fio-v3-hookup-guide)
И нефига не работает!
Такое впечатление что контроллер подвисает!
Отcоединяем SCK и естественно эрор инита.

Даже попробовал именно под эту плату бутлоадер
https://github.com/sparkfun/Arduino_Boards

и ни чего!

Перепаял назад на Nano- всё работает снова!
Это так, ради страховки, ну типо не попалил ли я платку кана пока паял.

У кого какие соображения?
Хочется на pro-micro всё собрать.

T_r_D
30.10.2015, 14:27
Сам себе отвечаю.
Всё и так работало, просто то что в void setup() было в порт не попадало.
Другие ардуины проходили инит при подключении программы к COM порту (или сбрасывались), а эта нет. Так что если нужно увидеть эти сообщения, то нужна задержка в 10 секунд. Там лоадер инится 8 секунд.
А по подключению то что выше написал.
И ещё на ардуине перемычку запаял чтоб плата CAN питалась напрямую от порта, а не через резистор на плате.
Как только всё заработает окончательно питание с USB разъёма вообще уберу.

Ща время нету, но попозде попробую с Interupt сделать и скажу пропали задержки или нет.

По поводу меню. Само меню реально прошито в дисплее.
Дисплей ловит нажатия на кнопки после получение сообщения от магнитолы что мы нажали кнопку меню.
Далее обрабатывает нажатия кнопок и в обратку выдаёт в 125 сообщение активна настройка или нет.
Скорее всего при изменении значения меню посылается или модифицируется сообщение. И скорее всего это сообщение 1E0.
Так что данные об том что в данный момент на дисплее отображает меню в CAN не идёт.
Посему это можно реализовать только ловя нажатие кнопок без пропусков и задержек.

Если модуль радио покажет себя лутчше чем штатная магнитола, то париться с этим я больше не буду.

lti1
30.10.2015, 19:14
Если потом планируете передавать эти данные в винду, можно писать как число, потом отправлять с помощью Serial.write (http://www.arduino.ru/Reference/Serial/Write) for (int i=0; i <= 7; i++) Serial.write(buf[i]); Если в андройд, то так не подойдет.Я немного обманул, Serial.write (http://www.arduino.ru/Reference/Serial/Write) на андройде то же нормально работает. Убрал у себя английские буквы и символы, оставил только русские.unsigned code_ru[66]={0x0401, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, 0x0451, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F};
char* ru[66]={ "\u0401", "\u0410", "\u0411", "\u0412", "\u0413", "\u0414", "\u0415", "\u0416", "\u0417", "\u0418", "\u0419", "\u041A", "\u041B", "\u041C", "\u041D", "\u041E", "\u041F", "\u0420", "\u0421", "\u0422", "\u0423", "\u0424", "\u0425", "\u0426", "\u0427", "\u0428", "\u0429", "\u042A", "\u042B", "\u042C", "\u042D", "\u042E", "\u042F", "\u0451", "\u0430", "\u0431", "\u0432", "\u0433", "\u0434", "\u0435", "\u0436", "\u0437", "\u0438", "\u0439", "\u043A", "\u043B", "\u043C", "\u043D", "\u043E", "\u043F", "\u0440", "\u0441", "\u0442", "\u0443", "\u0444", "\u0445", "\u0446", "\u0447", "\u0448", "\u0449", "\u044A", "\u044B", "\u044C", "\u044D", "\u044E", "\u044F"};


for(byte j=0; j<66; j++)
{
if(Buf[i]==code_ru[j]) Serial.print(ru[j]);
}

T_r_D
31.10.2015, 15:10
Может так?
void setup() {
Serial.begin(115200);
}

void loop() {
String str= "string ";
byte data1[8] = {1,2,3,4,5,6,7,8};
byte data2[8] = {8,7,6,5,4,3,2,1};

for(byte i=0; i<8; i++){
str += data1[i];
str += " ";
}

for(byte i=0; i<8; i++){
str += data2[i];
str += " ";
}

Serial.println(str);
delay(5000);
}

А можно это сделать массивом, а не пересобирать целиком строчку каждый раз?
Я наступаю на грабли
char* OUTLINE[] = {"RPM","|","SPD","|","ILPK","|","LPK","|","Trip","|","AVG SPD","|","Themp"};
задали массив и так его можно выводить спокойно, но он требует char.
модифицируем строку которая в int
RPM = (int)buf[0] << 5 | buf[1] >> 3;
в
str = String((int)buf[0] << 5 | buf[1] >> 3);
загоняем в массив
OUTLINE[0] = str;
Получаем несоответствие типов данных.
Как это побороть?
мне просто нужно чтоб был какой нить разделитель в строке между числами.

xmetal
31.10.2015, 19:48
Наверное так, если я правильно понял задачу:
void setup() {
Serial.begin(115200);
}

void loop() {
char *OUTLINE[] = {"RPM","|","SPD","|","ILPK","|","LPK","|","Trip","|","AVG SPD","|","Themp"};

for(byte i=0; i<13; i++){
Serial.print(OUTLINE[i]); //вывод: RPM|SPD|ILPK|LPK|Trip|AVG SPD|Themp
}
Serial.println();

String str;
str = String(123.456,3);
OUTLINE[8]="";
str.toCharArray(OUTLINE[8],str.length()+1); //копируем новые данные в OUTLINE[8]

for(byte i=0; i<13; i++){
Serial.print(OUTLINE[i]); //вывод: RPM|SPD|ILPK|LPK|123.456|AVG SPD|Themp
}

a:
goto a;
}

T_r_D
01.11.2015, 10:09
Наверное так, если я правильно понял задачу:
void setup() {
Serial.begin(115200);
}

void loop() {
char *OUTLINE[] = {"RPM","|","SPD","|","ILPK","|","LPK","|","Trip","|","AVG SPD","|","Themp"};

for(byte i=0; i<13; i++){
Serial.print(OUTLINE[i]); //вывод: RPM|SPD|ILPK|LPK|Trip|AVG SPD|Themp
}
Serial.println();

String str;
str = String(123.456,3);
OUTLINE[8]="";
str.toCharArray(OUTLINE[8],str.length()+1); //копируем новые данные в OUTLINE[8]

for(byte i=0; i<13; i++){
Serial.print(OUTLINE[i]); //вывод: RPM|SPD|ILPK|LPK|123.456|AVG SPD|Themp
}

a:
goto a;
}

Ты просто мой спаситель!
Именно это и нужно.
Блин, какой С оказывается не простой язык. Паскаль проще.

T_r_D
01.11.2015, 14:03
но поторопился!
char *OUTLINE[] = {"RPM","|","SPD","|","ILPK","|","LPK","|","Trip","|","AVG SPD","|","Themp"};

for(int i=0; i<13; i++){
Serial.print(OUTLINE[i]);
}
Так будет всё правильно, но стоит между этим вставить
OUTLINES[0] = "";
str = String(123);
str.toCharArray(OUTLINES[0],str.length()+1);
OUTLINES[1] = "bbb";
как вместо того что нужно получим
123123|bbb|SPD|||

А если сделаем вот так, то получим ещё круче!
OUTLINES[0] = "";
str = String(123);
str.toCharArray(OUTLINES[0],str.length()+1);

OUTLINES[1] = "";
str = String(278);
str.toCharArray(OUTLINES[1],str.length()+1);

OUTLINES[2] = "str";

выведет
278278|278|str|||

T_r_D
02.11.2015, 15:17
Короче сделал вот так:
#include <SPI.h>
#include "mcp_can.h"
MCP_CAN CAN(10);
unsigned char len = 0;
unsigned char buf[8];
INT32U canId = 0x000; // идентификаторы могут быть 11-ти или 29-битные

//RPM SPD ILPK LPK AVG_SPD Trp Tmp
// /100 /10 /10 делить на
int OUTLINES[] = {0,0,0,0,0,0,0};

void setup()
{
Serial.begin(115200);
pinMode(9, INPUT);
delay(10000);

START_INIT:
if(CAN_OK == CAN.begin(CAN_125KBPS,MCP_8MHz))
{Serial.println("Init OK!");}
else
{Serial.println("Init fail");delay(100);goto START_INIT;}
}


void loop()
{

if(CAN_MSGAVAIL == CAN.checkReceive())
{
CAN.readMsgBuf(&len, buf);
canId = CAN.getCanId();

//_________________________________TRIP_____________ ______________________
if(canId == 182) //0B6
{
OUTLINES[0] = (int)buf[0] << 5 | buf[1] >> 3; //Обороты
OUTLINES[1] = ((int)buf[2] << 8 | buf[3]); //скорость / 100
}

if(canId == 545) //221
{
OUTLINES[2] = (int)buf[1] << 8 | buf[2]; //моментальный расход / 10, если -1 то показаний нет
//ARCFL = (int)buf[3] << 8 | buf[4]; //Километры на остатке топлива
}

if(canId == 673) //0B6
{
OUTLINES[3] = (int)buf[3] << 8 | buf [4]; //Расход на 100км /10
OUTLINES[4] = buf[0]; //Средняя скорость
OUTLINES[5] = ((int)buf[1] << 8 | buf [2]); //Трип
}

if(canId == 246) //0F6
{
OUTLINES[6] = (buf[6] / 2) - 39; //Температура
//Odometr = ((unsigned long)buf[2] << 16 | (unsigned int)buf[3] << 8 | buf[4])/10; //Там есть десятые километра
}
}

__________________________________Выводим данные__________________________________
Serial.print("<TRIP|");
for(int i = 0; i < 7; i++)
{
Serial.print(OUTLINES[i]);
if (i != 6){Serial.print("|");}
}
Serial.println(">");
}

Это собственно всё что показывает борт комп не считая сообщений информационных.
Ну и то что закоменчено, то на верхнем дисплее и скорость с оборотами тоже.

Надо ещё поколдовать и сделать что если массив не менялся, то и данные выводить не надо.

lti1
02.11.2015, 21:58
но поторопился!
char *OUTLINE[] = {"RPM","|","SPD","|","ILPK","|","LPK","|","Trip","|","AVG SPD","|","Themp"};

for(int i=0; i<13; i++){
Serial.print(OUTLINE[i]);
}
Так будет всё правильно, но стоит между этим вставить
OUTLINES[0] = "";
str = String(123);
str.toCharArray(OUTLINES[0],str.length()+1);
OUTLINES[1] = "bbb";
как вместо того что нужно получим
123123|bbb|SPD|||

А если сделаем вот так, то получим ещё круче!
OUTLINES[0] = "";
str = String(123);
str.toCharArray(OUTLINES[0],str.length()+1);

OUTLINES[1] = "";
str = String(278);
str.toCharArray(OUTLINES[1],str.length()+1);

OUTLINES[2] = "str";

выведет
278278|278|str|||
В OUTLINE[0] = " "; вставьте пробелы, в количестве равном количеству символов в str = String(123);
void setup() {
Serial.begin(115200);
}
void loop() {
char *OUTLINE[] = {"RPM","|","SPD","|","ILPK","|","LPK","|","Trip"," |","AVG SPD","|","Themp"};
String str;
OUTLINE[0] = " ";
str = String(123);
str.toCharArray(OUTLINE[0],str.length()+1);
OUTLINE[2] = "bbb";
for(int i=0; i<13; i++){
Serial.print(OUTLINE[i]);
}
Serial.println("");
delay(5000);
} Результат: 123|bbb|ILPK|LPK|Trip |AVG SPD|Themp
Какой-то костыль получается, но работает. Ссылка (http://arduino.ru/forum/programmirovanie/problema-s-funktsiei-tochararray).

T_r_D
02.11.2015, 23:24
В OUTLINE[0] = " "; вставьте пробелы, в количестве равном количеству символов в str = String(123);
void setup() {
Serial.begin(115200);
}
void loop() {
char *OUTLINE[] = {"RPM","|","SPD","|","ILPK","|","LPK","|","Trip"," |","AVG SPD","|","Themp"};
String str;
OUTLINE[0] = " ";
str = String(123);
str.toCharArray(OUTLINE[0],str.length()+1);
OUTLINE[2] = "bbb";
for(int i=0; i<13; i++){
Serial.print(OUTLINE[i]);
}
Serial.println("");
delay(5000);
} Результат: 123|bbb|ILPK|LPK|Trip |AVG SPD|Themp
Какой-то костыль получается, но работает. Ссылка (http://arduino.ru/forum/programmirovanie/problema-s-funktsiei-tochararray).

А если этот самый str каждый раз разной длины? :smile2:
Я уже int массив сделал, в принципе и так пойдёт.

xmetal
04.11.2015, 05:13
но поторопился!Согласен, фигня получается.

T_r_D
12.11.2015, 22:29
Короче, я в стопоре.
С программированием под андроид чо-то как-то совсем уныло. Ни фига понять не могу, да и время нету почти.
Заказал модуль приёмника Fm. Догружу своё устройство им до полного счастья.

Raikkonen
15.11.2015, 12:01
терпение и труд!

T_r_D
06.12.2015, 16:34
Вот тут я описал написание программы под Android.
Почти месяц мучений.
http://www.pccar.ru/showthread.php?t=23635
Она пока пустая, просто принимает данные и выводит их, но это не надолго :)

T_r_D
23.12.2015, 02:59
Итак, с USB коннектом и pro micro не сложилось.
Был докуплен модуль HC 05 bluetooth
И при помощи него реализован коннект.
Всё работает хорошо, но есть проблема в обнаружение подключения.

Ни чего путного в инете не нашёл, а пробовать каждый раз коннектится к устройству очень долго.

Тоесть получается:
Зажигание выключилось и переферия отключилась.
Планшет ушёл спать.
Зажигание включилось, переферия включилась, планшет проснулся, но поскольку программа не выключалась, то коннекта нет.
Нужно или как-то научить программу видеть уход в сон и возвращение из него или при помощи кондёров делать задержку отключения переферии чтоб она могла на последнем издыхании гавкнуть что питания нет и тем самым прогу вообще завершить.
Тогда вопрос как при выходе из сна её запустить?

Не знаю куда код программы для андройда выкидывать. Сюда или в программы.

T_r_D
23.12.2015, 21:30
Итак, допилил прогу под ВТ для андройда.
манифест

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.oho.bt" >

<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH" />

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/AppTheme.NoActionBar" >

<receiver android:name=".MyReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.SCREEN_ON"/>
<action android:name="android.intent.action.SCREEN_OFF"/>
</intent-filter>
</receiver>

<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>


Ява

package com.example.oho.bt;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IntentFilter;
import android.os.Handler;

import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

Button btnOn, btnOff;
TextView txtArduino;

Handler h;
private static final int REQUEST_ENABLE_BT = 1;
private BluetoothAdapter btAdapter = null;
private ConnectedThread mConnectedThread;
private StringBuilder sb = new StringBuilder();
final int RECIEVE_MESSAGE = 1; // Статус для Handler
Integer btconnectingst = 0; //Проверяем активно ли соединение

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnOn = (Button) findViewById(R.id.btnOn);
btnOff = (Button) findViewById(R.id.btnOff);

txtArduino = (TextView) findViewById(R.id.txtArduino);
btAdapter = BluetoothAdapter.getDefaultAdapter();
registerReceiver(mybroadcast, new IntentFilter(Intent.ACTION_SCREEN_ON));
registerReceiver(mybroadcast, new IntentFilter(Intent.ACTION_SCREEN_OFF));

btnOn.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (btconnectingst.equals(1)) {
mConnectedThread.write("1"); // Отправляем через Bluetooth цифру 1
}
}
});

btnOff.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
if (btconnectingst.equals(1)) {
mConnectedThread.write("0"); // Отправляем через Bluetooth цифру 0
}
}
});

h = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case RECIEVE_MESSAGE: // если приняли сообщение в Handler
byte[] readBuf = (byte[]) msg.obj;
String strIncom = new String(readBuf, 0, msg.arg1);
sb.append(strIncom); // формируем строку
int endOfLineIndex = sb.indexOf("\r\n"); // определяем символы конца строки
if (endOfLineIndex > 0) { // если встречаем конец строки,
String sbprint = sb.substring(0, endOfLineIndex); // то извлекаем строку
sb.delete(0, sb.length()); // и очищаем sb
txtArduino.setText(sbprint); // обновляем TextView
btnOff.setEnabled(true);
btnOn.setEnabled(true);
}
break;
}
}
};
}

BroadcastReceiver mybroadcast = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals(Intent.ACTION_SCREEN_ ON)){
checkBTState();
}
else if(intent.getAction().equals(Intent.ACTION_SCREEN_ OFF)){
if (btconnectingst.equals(1)){
btconnectingst = 0;
mConnectedThread.cancel();
}
}

}
};


private void errorExit(String title, String message){
Toast.makeText(getBaseContext(), title + " - " + message, Toast.LENGTH_LONG).show();
}



private void checkBTState() {
if(btAdapter==null) {
} else {
if (btAdapter.isEnabled()) {
ConnectBT();
btconnectingst = 1;
} else {
Intent enableBtIntent = new Intent(btAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
}
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == REQUEST_ENABLE_BT){
if (resultCode == RESULT_OK){
ConnectBT();
btconnectingst = 1;
}
if(resultCode == RESULT_CANCELED){
finish();
}
}
}

@Override
public void onResume() {
super.onResume();
checkBTState();
}

@Override
public void onPause() {
//тут возникает проблема если ВТ выключен!
//Видимо из за того, что пытамся закрыть несуществующий сокет.
//Нужно записывать в переменную статус адаптера!
super.onPause();
if (btconnectingst.equals(1)) {
btconnectingst = 0;
mConnectedThread.cancel();
}
}

public void ConnectBT() {
btAdapter.cancelDiscovery();
for (BluetoothDevice device : btAdapter.getBondedDevices()) {
try {
try {
Method m = device.getClass().getMethod("createRfcommSocket",new Class[] { int.class });
try {
BluetoothSocket btSocket = (BluetoothSocket) m.invoke(device,Integer.valueOf(1));
btSocket.connect();
mConnectedThread = new ConnectedThread(btSocket);
mConnectedThread.start();
break;
} catch (IOException e) {}
}
catch (IllegalArgumentException e) {}
catch (IllegalAccessException e) {}
catch (InvocationTargetException e) {}
} catch (SecurityException e) {}
catch (NoSuchMethodException e) {}
}
}

private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;

public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;

// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }

mmInStream = tmpIn;
mmOutStream = tmpOut;
}

public void run() {
byte[] buffer = new byte[256]; // buffer store for the stream
int bytes; // bytes returned from read()

// Keep listening to the InputStream until an exception occurs
while (true) {
try {
// Read from the InputStream
bytes = mmInStream.read(buffer); // Получаем кол-во байт и само собщение в байтовый массив "buffer"
h.obtainMessage(RECIEVE_MESSAGE, bytes, -1, buffer).sendToTarget(); // Отправляем в очередь сообщений Handler
} catch (IOException e) {
break;
}
}
}

/* Call this from the main activity to send data to the remote device */
public void write(String message) {
byte[] msgBuffer = message.getBytes();
try {
mmOutStream.write(msgBuffer);
} catch (IOException e) {
}
}

/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
}

xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:showIn="@layout/activity_main" tools:context=".MainActivity">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Text From Arduino"
android:id="@+id/txtArduino"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_above="@+id/btnOn"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="1"
android:id="@+id/btnOn"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_marginBottom="37dp" />

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
android:id="@+id/btnOff"
android:layout_alignBottom="@+id/btnOn"
android:layout_toRightOf="@+id/btnOn"
android:layout_toEndOf="@+id/btnOn" />
</RelativeLayout>

T_r_D
23.12.2015, 21:37
Условия для работы.
bluetooth устройства должны быть сопряжены.
В списке сопряжонных устройств должно быть только то, которое является модулем hc-05.
Ардуина и модуль должны включаться ДО выхода планшета из слипа или ДО его загрузки в случае автоматического запуска программы при старте.

Концом стороки является \r\n при посылках из ардуины.

События которые происходят в программе.
Запуск
Если БТ включён, то коннектимся.
Если выключен, то просим пользователя включить.
Если включил- коннектимся, если нет- выходим из программы.
Свёртывание программы- дисконнект ВТ.
Развёртывание- коннект.
Уход в слип (потухание экрана)- дисконнект
Возвращение из слипа (включение экрана)- коннект.

Во вложении АПК.

autowp
06.01.2016, 21:04
Я тут переписал старую как мир библиотеку под MCP2515 от SeedStudio
https://github.com/Seeed-Studio/CAN_BUS_Shield

Вот что вышло
https://github.com/autowp/CAN_BUS_Shield

А вот пример приложения на базе этой библиотеки:
https://github.com/autowp/can-usb - эмулятор CanHacker'а (lawicel).

Пока не работают только фильтры/маски.

Цель переписывания была в том, чтобы обеспечить безошибочную работу на высоких скоростях. С оригинальной библиотекой очень много потерь было. Переписанная тянет полный загруз UART на 115200 (эффективная скорость данных 87Кбит). Дальше не мерял, потому как это предел для программы, под которую делалось (CanHacker http://www.mictronics.de/projects/usb-can-bus/ )

P.S.
Ах, да, забыл упомянуть, что я всё делаю на Arduino Nano.
На Arduino Uno у меня не заработало, потому что она слишком долго загружается и не успевает принять от CanHacker'а команду на подключение. Возможно с иным бутлоадером и заработает, но мне не очень хочется разбираться

T_r_D
07.01.2016, 15:17
А я тут опять в стопоре!
Запутался в трёх соснах.
В скетче указывают delay(100) и всё работает, делаю задержку через millis и не фига не работает!
Тоесть сообщения-то идут, но похоже быстрее чем с делеем и поэтому для андройде это уже каша, а не то что должно быть.
Сколько не смотрел в инете и всё говорят про то, что внутренний таймер считает по микросекундам и соответственно 100 millis должно быть эквивалентом delay(100).
Может это только с промикро такие глюки?

autowp
07.01.2016, 19:02
А я тут опять в стопоре!
Запутался в трёх соснах.
В скетче указывают delay(100) и всё работает, делаю задержку через millis и не фига не работает!
Тоесть сообщения-то идут, но похоже быстрее чем с делеем и поэтому для андройде это уже каша, а не то что должно быть.
Сколько не смотрел в инете и всё говорят про то, что внутренний таймер считает по микросекундам и соответственно 100 millis должно быть эквивалентом delay(100).
Может это только с промикро такие глюки?

millis - это не задержка, а текущее время.
В нормальной программе delay быть не должно.

T_r_D
08.01.2016, 01:38
millis - это не задержка, а текущее время.
В нормальной программе delay быть не должно.

Я и написал что через.
Уже разобрался. Глюк компилятора однако.
Если нет пробела между переменными и знаком "-" почему-то бред был.

За библиотеку спасибо.


PS Я уже двигаюсь к завершению первоочередной задачи.
У меня остались только непонятные глюки при коннекте планшета к модулю. По неизвестным причинам и без всякой логики иногда при коннекте приложение вылетает с ошибкой.

Ну и не пойму ни как как сделать чтоб работало всё в фоне.
Поток создан, а всёравно при свёртывании приложения если не терминировать коннект сокета, то вываливается с ошибкой.
Надо тоже разобраться.

T_r_D
26.01.2016, 11:27
В связи с выходом новой версии драйвера у Фелча, вернулся на провод.
К проге прикрутил работу сервиса в фоне, окна сообщений поверх всего.

Купил планшет новый Lenovo tab 2. Вот его и буду использовать.
Скоро установка в машину будет.

Dmitry8
01.02.2016, 00:46
В связи с выходом новой версии драйвера у Фелча, вернулся на провод.


Что за драйвера? И кто такой Фелч?

T_r_D
02.02.2016, 14:35
Это вот этот человек.
Где-то на форуме его так называли. Как его зовут на самом деле понятия не имею.
https://github.com/felHR85/UsbSerial

На самом деле дело было не в дровах, а в посылках. Если передавать с промикры в виде чисел, то не фига не работает. Нужно жёстко указать что передаём стринг.

Короче вот так надо передавать

#include <SPI.h>
#include "mcp_can.h"
MCP_CAN CAN(10);
unsigned char len = 0;
unsigned char buf[8];
INT32U canId = 0x000; // идентификаторы могут быть 11-ти или 29-битные

unsigned long time0 = -120;

//TRIP
//RPM|SPD|LPK|AVG.LPK|AVG_SPD|Trp|Tmp
// /100 /10 /10 делить на
int OUTLINES[] = {0,0,0,-1,-1,0,0,-1,-1,-1};
int OUTLINES2[] = {0,0,0,-1,-1,0,0,-1,-1,-1};

//Кнопки на руле
int SWSV = 0;

//Меню аудио настроек
int AP = 0;
int APV = 0;
String AUDIO, AUDIO2 ="0:0";

//Банды, частота
int RB = 0;
float RFR = 0;
String BANDFREQ, BANDFREQ2 = "0:0";

//RDS
String RDS ="NO RDS";

void setup()
{
Serial1.begin(38400);
pinMode(9, INPUT);
delay(10000);

START_INIT:
if(CAN_OK == CAN.begin(CAN_125KBPS,MCP_8MHz))
{Serial1.println("Init OK!");}
else
{Serial1.println("Init fail");delay(100);goto START_INIT;}
}


void loop()
{

// if(CAN_MSGAVAIL == CAN.checkReceive())
if(!digitalRead(9)) // пин 9 можно переназначить
{
CAN.readMsgBuf(&len, buf);
canId = CAN.getCanId();

//_________________________________TRIP_____________ ______________________
if(canId == 182) //0B6
{
OUTLINES[0] = (int)buf[0] << 5 | buf[1] >> 3; //Обороты
OUTLINES[1] = ((int)buf[2] << 8 | buf[3]); //скорость / 100
}

if(canId == 545) //221
{
OUTLINES[2] = (int)buf[1] << 8 | buf[2]; //моментальный расход / 10, если -1 то показаний нет
//ARCFL = (int)buf[3] << 8 | buf[4]; //Километры на остатке топлива
}

if(canId == 673) //0B6
{
OUTLINES[3] = (int)buf[3] << 8 | buf [4]; //Расход на 100км /10
OUTLINES[4] = buf[0]; //Средняя скорость
OUTLINES[5] = ((int)buf[1] << 8 | buf [2]); //Трип
}

if(canId == 246) //0F6
{
OUTLINES[6] = (buf[6] / 2) - 39; //Температура
//Odometr = ((unsigned long)buf[2] << 16 | (unsigned int)buf[3] << 8 | buf[4])/10; //Там есть десятые километра
}
//______________________________ERROR MSG_________________________________
if(canId == 417) //1A1
{
if(buf[0] == 128) //buf[2]bit[1] X00000000 X=1 when SHOW 0R buf[0] 0x80(128) show, 0x7F(127) hide, 0xff(255) clear (default)
{
OUTLINES[7] = buf[1];
} else {OUTLINES[7] = -1;}
}
//_________________________________VOLUME___________ ______________________
if(canId == 421) //1A5
{
OUTLINES[8] = buf[0];
}
//_________________________Кнопки на руле справа__________________________
if(canId == 543) //21F
{
/* SWSV = buf[1];
if(bitRead(buf[0],7) == 0 && bitRead(buf[0],6) == 0 && bitRead(buf[0],3) == 0 && bitRead(buf[0],2) == 0 && bitRead(buf[0],1) == 0){OUTLINES[8] = -1;} //Release
if(bitRead(buf[0],7) == 1){OUTLINES[8] = 1;} //Forward
if(bitRead(buf[0],6) == 1){OUTLINES[8] = 2;} //Backward
if(bitRead(buf[0],3) == 1 && bitRead(buf[0],2) == 1){OUTLINES[8] = 3;} //Mute
if(bitRead(buf[0],3) == 1 && bitRead(buf[0],2) == 0){OUTLINES[8] = 4;} //Vol Up
if(bitRead(buf[0],2) == 1 && bitRead(buf[0],3) == 0){OUTLINES[8] = 5;} //Vol Down
if(bitRead(buf[0],1) == 1){OUTLINES[8] = 6;} //Source */
}
//__________________________Меню настройки аудио__________________________
if(canId == 485) //1E5
{
AP = 0;
APV = 0;
if (bitRead(buf[0],7) == 1){AP = 1; APV = (buf[0] & 0x7F) - 63;} //BALANCE L/R ||логическое И с 01111111. Где 0 там всегда 0
if (bitRead(buf[1],7) == 1){AP = 2; APV = (buf[1] & 0x7F) - 63;} //BALANCE RR/FF
if (bitRead(buf[2],7) == 1){AP = 3; APV = (buf[2] & 0x7F) - 63;} //BASS
if (bitRead(buf[4],7) == 1){AP = 4; APV = (buf[4] & 0x7F) - 63;} //TREBLE
if (bitRead(buf[5],7) == 1){AP = 5; APV = bitRead(buf[5],6);} //LOUD
if (bitRead(buf[5],4) == 1){AP = 6; APV = bitRead(buf[5],2);} //AUTO VOLUME
if (bitRead(buf[6],6) == 1){AP = 7;
if ((buf[6] & 0x1F) == 3){APV = 1;} //NONE ||//Логическое И c 00011111
if ((buf[6] & 0x1F) == 7){APV = 2;} //CLASSIC
if ((buf[6] & 0x1F) == 11){APV = 3;} //JAZZ-BLUES
if ((buf[6] & 0x1F) == 15){APV = 4;} //POP-ROCK
if ((buf[6] & 0x1F) == 19){APV = 5;} //VOCAL
if ((buf[6] & 0x1F) == 23){APV = 6;} //TECHNO
}
AUDIO = String(AP) + ":" + String(APV);
}
//_______________Включено или нет радио, источник на радио________________
if(canId == 357) //165
{
if (buf[0] == 192){OUTLINES[9] = 1;} else {OUTLINES[9] = 0;} //ON/OFF
if (buf[2] == 16){OUTLINES[9] = 2;} //Radio
if (buf[2] == 32){OUTLINES[9] = 3;} //CD
if (buf[2] == 48){OUTLINES[9] = 4;} //CD-Changer
if (buf[2] == 64){OUTLINES[9] = 5;} //AUX 1
if (buf[2] == 80){OUTLINES[9] = 6;} //AUX 2
}
//_________________________Банды и частота радио__________________________
//первые 2 меняются иногда, последнии 3 незнамо что (мусор или уровень сигнала),
//частота и мусор не пропадают при отключении магнитолы
if(canId == 549) //225
{
if (bitRead(buf[2],4) == 1){RB = 0; RFR = (int)buf[3] << 8 | buf[4];RFR = RFR / 20 + 50;}//FM1
if (bitRead(buf[2],5) == 1){RB = 1; RFR = (int)buf[3] << 8 | buf[4];RFR = RFR / 20 + 50;}//FM2
if (bitRead(buf[2],6) == 1){RB = 2; RFR = (int)buf[3] << 8 | buf[4];RFR = RFR / 20 + 50;}//FM AST
if (bitRead(buf[2],4) == 1 && bitRead(buf[2],6) == 1){RB = 3; RFR = (int)buf[3] << 8 | buf[4];}//AM
BANDFREQ = String(RB) + ":" + String(RFR);
}
//________________________________RDS_______________ ______________________
if(canId == 677) //2A5
{
for(int i = 0; i<len; i++)
{
RDS = RDS + buf[i];
}
}

//Выводим данные.
/*
Serial.print("Steering while valcoder value:"); Serial.print(SWSV); Serial.print(" | ");
*/
if ((OUTLINES[0] != OUTLINES2[0] ||
OUTLINES[1] != OUTLINES2[1] ||
OUTLINES[2] != OUTLINES2[2] ||
OUTLINES[3] != OUTLINES2[3] ||
OUTLINES[4] != OUTLINES2[4] ||
OUTLINES[5] != OUTLINES2[5] ||
OUTLINES[6] != OUTLINES2[6] ||
OUTLINES[7] != OUTLINES2[7] ||
OUTLINES[8] != OUTLINES2[8] ||
AUDIO != AUDIO2 ||
OUTLINES[9] != OUTLINES2[9] ||
BANDFREQ != BANDFREQ2) &&
(millis() - time0) > 100)
{String s = String(OUTLINES[0]) + "|" +
String(OUTLINES[1]) + "|" +
String(OUTLINES[2]) + "|" +
String(OUTLINES[3]) + "|" +
String(OUTLINES[4]) + "|" +
String(OUTLINES[5]) + "|" +
String(OUTLINES[6]) + "|" +
String(OUTLINES[7]) + "|" +
String(OUTLINES[8]) + "|" +
AUDIO + "|" +
String(OUTLINES[9]) + "|" +
BANDFREQ;
Serial.print(s);
OUTLINES2[0] = OUTLINES[0];
OUTLINES2[1] = OUTLINES[1];
OUTLINES2[2] = OUTLINES[2];
OUTLINES2[3] = OUTLINES[3];
OUTLINES2[4] = OUTLINES[4];
OUTLINES2[5] = OUTLINES[5];
OUTLINES2[6] = OUTLINES[6];
OUTLINES2[7] = OUTLINES[7];
OUTLINES2[8] = OUTLINES[8];
AUDIO2 = AUDIO;
OUTLINES2[9] = OUTLINES[9];
BANDFREQ2 = BANDFREQ;
time0 = millis();
}
}
}

T_r_D
02.02.2016, 14:38
Ребят, а к вам вопрос!
Не могу разобраться в посылке листа списки станций!
У autowp написано следующее:

T_r_D
02.02.2016, 14:40
Пакеты которые приходят вот:
Как это собрать просто в строки на стороне ардуины с пометкой строки которая в данный момент выделена?

autowp
02.02.2016, 14:46
Смотрите в сторону ISO 15765-2 (мультифреймовые посылки)
https://en.wikipedia.org/wiki/ISO_15765-2
http://www.canbushack.com/blog/index.php?title=iso-15765-2-can-transport-layer-yes-it-can-be-fun&more=1&c=1&tb=1&pb=1

T_r_D
02.02.2016, 14:54
Да я понимаю как они идут.
Идёт пакет в котором сначала инфа техническая (показывает меню или нет и так далее), а последние два байта это начало строки данных.
Потом в какой- то посылке дальше идёт сообщение начинающиеся с символа "!" и после него 6 байт продолжение строки. Что значит 8 байт я не понимаю.

Как всю эту кашу собрать воедино-то. Я этого сообразить не могу.

autowp
02.02.2016, 15:05
Да я понимаю как они идут.
Идёт пакет в котором сначала инфа техническая (показывает меню или нет и так далее), а последние два байта это начало строки данных.
Потом в какой- то посылке дальше идёт сообщение начинающиеся с символа "!" и после него 6 байт продолжение строки. Что значит 8 байт я не понимаю.

Как всю эту кашу собрать воедино-то. Я этого сообразить не могу.

Не, не надо так подходить к вопросу. Надо сначала собрать всю посылку в цельное сообщение, а уже потом анализировать её содержимое. Она переменной длины. Названий может не быть вообще или быть только частично.

Поэтому изучите организацию таких посылок и напишите код, который соберёт её, согласно протоколу. Готовый код на Си показать не могу, не писал, но вот на java, если чем-то поможет (ищите по слову isMultiFrame )
https://github.com/autowp/CAN/blob/master/src/com/autowp/can/CanClient.java

T_r_D
02.02.2016, 16:16
Чо-то я не понимаю тогда!
Как организован пакет?
Идёт первая посылка, потом он ждёт ответа от принимающий стороны?
Потом кидает пакеты с данными длинна которых описана в первом пакете и опять ждёт подтверждения?
Или как?

autowp
02.02.2016, 16:23
Примерно так, но в вашем случае, принимающая сторона уже есть и вам об этом (подтверждении) не придется беспокоиться. Вы "подслушиваете" обмен между другими устройствами.

T_r_D
02.02.2016, 17:15
Ну тогда вопрос как отмечается конец посылки?
Как посылается длинна следующего пакета? Ну или если хотите, то данные о следующем пакете.

Можно описать человеческим языком как происходит обмен?

Да и кстати дисплея у меня потом не будет. Так что на мою железку и это ляжет.

autowp
02.02.2016, 17:25
> как отмечается конец посылки?
зачем его как-то отмечать? Получили задекларированный объем данных - передача закончена

> Как посылается длинна следующего пакета?
Как и любого другого - в его DLC

> Можно описать человеческим языком как происходит обмен?
Я ж дал вам 2 ссылки с детальнейшим описанием всего процесса.

Dmitry8
02.02.2016, 21:46
T_r_D, спасибо, нашёл уже. Я так понял, что вся логика работы вашего девайса организована на ардуине. С чем связано такое решение? Почему бы всю логику не реализовать на андройде?

T_r_D
03.02.2016, 10:39
T_r_D, спасибо, нашёл уже. Я так понял, что вся логика работы вашего девайса организована на ардуине. С чем связано такое решение? Почему бы всю логику не реализовать на андройде?

Потому что логики тут мало :)
Получили пакет, переделали в стринг и отправили его.
В некоторых случаях проанализировали данные в пакете и отправили результат.

Так гораздо проще посылать пакеты и длина их получается приемлемой.
И на стороне андройда не надо следить за целостностью пакета, а проверять целостность можно по его длине.

T_r_D
03.02.2016, 10:44
autowp
> как отмечается конец посылки?
зачем его как-то отмечать? Получили задекларированный объем данных - передача закончена

Где этот объём смотреть?
И вопрос второй был в том- посылается в первом пакете полный размер сообщения текста или только первого фрейма? Если всего, то не понятно зачем после каждого фрейма ждать подтверждения от дисплея, если только первого, то какой пакет посылает магнитола потом для описания следующего пакета с текстом и как узнать сколько всего пакетов в таком случае.

Я всё прочитал, но ни чего особо не понял к сожалению.
Мне бы на примере моих пакетов ткнули бы носом где какая посылка и что она значит был бы очень благодарен!

autowp
03.02.2016, 11:47
>Где этот объём смотреть?

Вы точно смотрели то, что по ссылкам? В первом фрейме.

>И вопрос второй был в том- посылается в первом пакете полный размер сообщения текста или только первого фрейма?

Странный вопрос. Зачем в первом фрейме посылать размер первого фрейма? Он и так в DLC есть

> зачем после каждого фрейма ждать подтверждения от дисплея

Это мера, направленная на исключение перегрузки входного буфера принимающей стороны.

T_r_D
04.02.2016, 00:45
>И вопрос второй был в том- посылается в первом пакете полный размер сообщения текста или только первого фрейма?

Странный вопрос. Зачем в первом фрейме посылать размер первого фрейма? Он и так в DLC есть


Я не так выразился просто. Имел в виду в первом фрейме указан размер данных всех последующих фреймов или только идущего за ним?

Как я понял в 4 байте первого фрейма указаны размеры 4 фреймов с данными далее?
Или всётаки 8?
Если 4, то первая пара бит указывает первым битом на количество данных о исполнители в пакете, а вторым на количество данных названия трека?

И почему в конце первого пакета 2 бита данных текстовых? Это биты относятся к исполнителю или треку?

autowp
04.02.2016, 01:07
Я не так выразился просто. Имел в виду в первом фрейме указан размер данных всех последующих фреймов или только идущего за ним?
The first frame contains the length of the full packet, along with the initial data.
т.е. всего

Как я понял в 4 байте первого фрейма указаны размеры 4 фреймов с данными далее?
Или всётаки 8?
Если 4, то первая пара бит указывает первым битом на количество данных о исполнители в пакете, а вторым на количество данных названия трека?

И почему в конце первого пакета 2 бита данных текстовых? Это биты относятся к исполнителю или треку?
Еще раз: сначала соберите сообщение целиком, потом беритесь за его анализ. Иначе каша.

Когда соберете готовое сообщение, в 4ом (с нуля) байте получившегося блока данных (6ом с нуля байте первого фрейма) будут флажки, сигнализирующие о том, что следует искать в последующей части сообщение: названия исполнителей и треков (1100000 будет означать, что дальше будет 40 байт с исполнителем и названием первого трека, а остальные 3 трека не имеют названия и исполнителя)

T_r_D
04.02.2016, 01:25
Вот кусок лога:
16 13 16 29 25 16 86 69
4 0 96
48 0 10
16 0
33 83 84 73 32 70 77 144
0 0 0 0 0 0 0 208
0 255 255 0 85 0 0
1 3 146 64 0 208 0 16
0 0 2 111 0 89 0 0
255 255 0 80 0
1 0 0 0 0 0 0 0
0 255 255 0 0 7 56 9
2 63 255 255 255 0 255 255

В первом сообщении в двух битах с конца буквы VE
В пятом ! S T I F M 

Можно ли считать первое сообщение заглавным мультифрейма?

По каким признакам вообще определить первое сообщение?
Как его найти в потоке данных?

В 4 байте первого сообщение DEC 25 что в бинарном виде 00011001
это означает что 20 байт следующие за этим сообщением названия артиста первого, потом 20 байт названия второго трека, потом 20 байт артиста 3 трека?
или я не с той стороны считаю биты?
или то что обозначено "0", то тоже занимает 20 байт?

autowp
04.02.2016, 01:31
Лог должен быть в hex и выровненным, если вы хотите, чтобы в нем кто-то разбирался

https://en.wikipedia.org/wiki/ISO_15765-2
Написано, что первым является то сообщение, у которого в старших четырех битах единица (0001).
Так же сообщение может быть первым и единственным, если в вся посылка уместилась в 1 фрейм. Тогда в старших битах 0 (0000)

T_r_D
04.02.2016, 02:04
Лог должен быть в hex и выровненным, если вы хотите, чтобы в нем кто-то разбирался

https://en.wikipedia.org/wiki/ISO_15765-2
Написано, что первым является то сообщение, у которого в старших четырех битах единица (0001).
Так же сообщение может быть первым и единственным, если в вся посылка уместилась в 1 фрейм. Тогда в старших битах 0 (0000)

тоесть моё сообщение является стартовым поскольку 16 в хексе это 0x10, что есть 00010000.
И если бы оно начиналось на 0x0, то это тоже то, что мне надо.

С этим разобрались.

T_r_D
04.02.2016, 02:56
Так я правильно понял что информация о фреймах находиться в 4 байте который 25 в DEC или 0x19 в HEX?
Мне же эти данные и нужны для сборки пакета целиком. Как я без них его соберу-то?

мой лог в HEX
10 0D 10 1D 19 10 56 45
04 00 60
30 00 0A
10 00
21 53 54 49 20 46 4D 90
00 00 00 00 00 00 00 D0
00 FF FF 00 55 00 00 00
01 03 92 40 00 D0 00 10
00 00 02 6F 00 59 00 00
FF FF 00 50 00 00 00 00
01 00 00 00 00
00 FF FF 00 00 07 38 09
02 3F FF FF FF 00 FF FF

autowp
04.02.2016, 03:04
Так я правильно понял что информация о фреймах находиться в 4 байте который 25 в DEC или 0x19 в HEX?
Мне же эти данные и нужны для сборки пакета целиком. Как я без них его соберу-то?

Абсолютно нет.

Забудьте на время про радиостанции, названия и прочее.
Перед вами CAN TP сообщение, передаваемое по кускам (CAN-фреймам).

Вся информация, необходимая для того, чтобы собрать сообщение в целую посылку, согласно таблице https://en.wikipedia.org/wiki/ISO_15765-2 , находится в 7 .. 4 (byte 0), 3 .. 0 (byte 0), 15 .. 8 (byte 1)

Вот когда соберете, тогда и будете думать про 4ый байт, названия станций и прочую полезную нагрузку посылки

T_r_D
04.02.2016, 04:26
Абсолютно нет.

Забудьте на время про радиостанции, названия и прочее.
Перед вами CAN TP сообщение, передаваемое по кускам (CAN-фреймам).

Вся информация, необходимая для того, чтобы собрать сообщение в целую посылку, согласно таблице https://en.wikipedia.org/wiki/ISO_15765-2 , находится в 7 .. 4 (byte 0), 3 .. 0 (byte 0), 15 .. 8 (byte 1)

Вот когда соберете, тогда и будете думать про 4ый байт, названия станций и прочую полезную нагрузку посылки

Так, тоесть
7-4 бит байта 0 говорит нам о длине пакета. В данном случае он равен 1, тоесть 8..4095.

3-0 бит байта 0 это длина сообщения которую надо сложить с чем?
Что такое 15 .. 8 (byte 1)? это полностью первый байт или что?
Судя по всему пол байта 0 нужно сложить с байтом 1. Так?

Тогда получается что нам нужны 6 байт в этом пакете, а остальные 7 нужно добирать из сообщения которое начинается с 2, тоесть в бинаре старшие биты 7-4 0010, начиная со следующего байта или с байта идентификатора?
Так?
10 0D 10 1D 19 10 56 45 21 53 54 49 20 46 4D
или так?
10 0D 10 1D 19 10 56 45 53 54 49 20 46 4D 90

А биты 3-0 в байте 0 указывают на количество пакетов или на количество оставшихся или просто на номер этого пакета?

autowp
04.02.2016, 10:44
Так, тоесть
7-4 бит байта 0 говорит нам о длине пакета. В данном случае он равен 1, тоесть 8..4095.

3-0 бит байта 0 это длина сообщения которую надо сложить с чем?
Что такое 15 .. 8 (byte 1)? это полностью первый байт или что?
Судя по всему пол байта 0 нужно сложить с байтом 1. Так?

Тогда получается что нам нужны 6 байт в этом пакете, а остальные 7 нужно добирать из сообщения которое начинается с 2, тоесть в бинаре старшие биты 7-4 0010, начиная со следующего байта или с байта идентификатора?
Так?
10 0D 10 1D 19 10 56 45 21 53 54 49 20 46 4D
или так?
10 0D 10 1D 19 10 56 45 53 54 49 20 46 4D 90

А биты 3-0 в байте 0 указывают на количество пакетов или на количество оставшихся или просто на номер этого пакета?

Ни так, ни так.
Зачем вы тащите сюда 10 0D?

Сходите по ссылке на wiki. Все, что обозначенно "data" - это данные. Их и надо собирать, чтобы получить содержимое сообщения.

Сами же вот правильно рассуждает, а делаете по-другому.

> Тогда получается что нам нужны 6 байт в этом пакете, а остальные 7 нужно добирать из сообщения которое начинается с 2

Т.е. от первых двух сообщений надо 6+7=13 байт.

Ваш "Так?" мне не понятен.по какой причине вы выкинули последний байт фрейма?

GASCHE
04.02.2016, 12:10
Это посылка
10 0D 10 1D 19 10 56 45 First frame
30 00 0A 10 00 00 00 00 Flow control frame
21 53 54 49 20 46 4D 90 Consecutive frame
это данные в этой посылке
10 1D 19 10 56 45 53 54 49 20 46 4D 90
Не знаю как у вас но если стандартно то
10 - SID
1D - PID
19 10 56 45 53 54 49 20 46 4D 90 Какие то данные
Cудя по SID это запрос каких-то данных

Dmitry8
04.02.2016, 13:26
10 0D 10 1D 19 10 56 45 - First Frame , данные 13 байт
30 00 0A - Flow Control
21 53 54 49 20 46 4D 90 - Consecutive Frame
Данные тут: 10 1D 19 10 56 45 53 54 49 20 46 4D 90
... VESTI FM

lti1
04.02.2016, 13:41
Господа, а что означают выделенные данные в таком пакете? Машина другая, FF3, но раз пошла такая пляска...

10 90 A3 0 0 5 0 5
21 0 0D 10 10 10 0 0A
22 0 55 0 53 0 42 0
23 0 0 4C 0 69 0 6B
24 0 65 0 20 0 4E 0
25 6F 0 62 0 6F 0 64
26 0 79 0 20 0 45 0
27 6C 0 73 0 65 0 0
28 0 4D 0 79 0 20 0
29 44 0 61 0 72 0 6B
2A 0 65 0 73 0 74 0
2B 20 0 44 0 61 0 79
2C 0 73 0 0 4 1F 0
2D 2E 0 20 0 35 0 2F
2E 0 31 0 33 0 0 0A
2F 0A 0A 2 4 1E 4 3F
20 4 46 0 2E 0 0 4
21 1F 4 40 4 3E 4 41
22 4 3C 0 2E 0 0 4
23 18 4 3D 4 44 4 3E
24 0 0 CF 0 0 0 0

Вот, что на дисплее отображается в данный момент.

Dmitry8
04.02.2016, 13:49
10 90 A3 0 0 5 0 5 - First frame
всё что дальше: 144 байта - Consecutive frame

autowp
04.02.2016, 13:53
Не знаю как у вас но если стандартно то
10 - SID
1D - PID
19 10 56 45 53 54 49 20 46 4D 90 Какие то данные
Cудя по SID это запрос каких-то данных

Зацепило слово "стандартно". Есть какой-то стандарт?

Для меня открытыми и интересующими по TP являются вопросы:
- как выбирается ID traffic control frame'ов
- как определяется, какие ID являются multiframe

Пока мой ответ на это: стандарта нет, по согласованию разработчиков. Но мне не нравится такой ответ.

lti1
04.02.2016, 14:06
10 90 A3 0 0 5 0 5 - First frame
всё что дальше: 144 байта - Consecutive frame
Мне не понятно то, что выделено жирным, то что там 144 байта я и так понял, калькулятором умею пользоваться. То есть начиная с A3 начинаются данные и их нужно как то разбирать?

T_r_D
04.02.2016, 14:07
Так народ, не путайте меня.
Моё рассуждение правильно?
Что если пакет начинается с 0001 или 0000 это или первый пакет или единственный.
Младшая часть нулевого байта и весь первый байт это размер дальнейшего пакета(ов) с данными.
Пакеты с данными начинаются всегда 0010
кусок из вики: Consecutive 7 .. 4 (byte 0) 2.

GASCHE
04.02.2016, 14:08
Есть какой-то стандарт?.Под стандартом следует читать ISO 15765-2, ссылку на который приводили выше.

Dmitry8
04.02.2016, 14:13
10 - SID
1D - PID

Про это ничего нет в ISO 15765-2

GASCHE
04.02.2016, 14:28
Что если пакет начинается с 0001 или 0000 это или первый пакет или единственныйНе понял?
Single frame
01 3E FF FF FF FF FF FF
02 10 81 FF FF FF FF FF

Про это ничего нет в ISO 15765-2Согласен!

Dmitry8
04.02.2016, 14:31
GASCHE,
тогда поясните откуда вы взяли SID и PID?

T_r_D
04.02.2016, 14:51
GASCHE в вики написано что 4 старших бита нулевого байта если 0000, то это одиночный пакет, а если 0001, то длинный, тоесть с мультифреймом.

так, скажите мне по коду- я правильно смещаю?


int Length;
if(!digitalRead(9)) // пин 9 можно переназначить
{
CAN.readMsgBuf(&len, buf);
canId = CAN.getCanId();

if(canId == 293) // 125HEX
{
if ((buf[0] >> 4) == 16){
Length = ((buf[0] << 4) | buf[1]) - (len - 2);
}
}

}

autowp
04.02.2016, 14:57
GASCHE в вики написано что 4 старших бита нулевого байта если 0000, то это одиночный пакет, а если 0001, то длинный, тоесть с мультифреймом.

так, скажите мне по коду- я правильно смещаю?


int Length;
if(!digitalRead(9)) // пин 9 можно переназначить
{
CAN.readMsgBuf(&len, buf);
canId = CAN.getCanId();

if(canId == 293) // 125HEX
{
if ((buf[0] >> 4) == 16){
Length = ((buf[0] << 4) | buf[1]) - (len - 2);
}
}

}


Чтобы не писать "if(canId == 293) // 125HEX" и не забивать себе голову никому не нужными DEC'ами, рекомендую "if(canId == 0x125)"

(buf[0] >> 4) == 16

Это всегда false, не может быть равен 16и байт, 4 раза поделенный на 2

- (len - 2)

Вот это не понятно. Length - это что? (понятно, что длина, но длина чего?)

Dmitry8
04.02.2016, 14:59
if ((buf[0] >> 4) == 0 // Single frame
...
if ((buf[0] >> 4) == 0x01 // First Frame
...
if ((buf[0] >> 4) == 0x02 // Consecutive Frame

T_r_D
04.02.2016, 15:00
Чтобы не писать "if(canId == 293) // 125HEX" и не забивать себе голову никому не нужными DEC'ами, рекомендую "if(canId == 0x125)"

(buf[0] >> 4) == 16

Это всегда false, не может быть равен 16 байт, 4 раза поделенный на 2

- (len - 2)

Вот это не понятно. Length - это что? (понятно, что длина, но длина чего?)

Это я хочу туда запихать длину пакета. А это - (len - 2) вычитание длины первого пакета и двух первых байт. В первом же пакете оставшиеся байты кроме первых двух входят в общею длину.

А если не смещать на 4, то нужно битовую маску?
buf[0] & 0xF0 ?

GASCHE
04.02.2016, 15:03
GASCHE в вики написано что 4 старших бита нулевого байта если 0000, то это одиночный пакет, а если 0001, то длинный, тоесть с мультифреймом.Да, я этого и не отрицаю.

T_r_D
04.02.2016, 15:06
Короче я со смещениями опять всё перепутал...

Куда чего надо смещать или с какой маской плюсовать чтоб узнать длину пакета?
Помогите плиз- чайник я в этом.

GASCHE
04.02.2016, 15:26
Короче я со смещениями опять всё перепутал...Так Dmitry8 вам правильно показал.
Куда чего надо смещать или с какой маской плюсовать чтоб узнать длину пакета?Как-то так
buf[0] & 0x0F * 256 + buf[1]

T_r_D
04.02.2016, 16:08
Вот что получилось.
Кстати почему не работает вот такой способ узнать длину массива
int i = DataBuf.length?


if(canId == 293) // 125HEX
{
if ((buf[0] >> 4) == 0x01){
Length = (buf[0] & 0x0F * 256 + buf[1]) - (len -2);
for (int i=0; i<len;i++){
DataBuf[i] = buf[i];
}
}

if(((buf[0] >> 4) == 0x02) && Length > 0){
int sz = sizeof(DataBuf);
Length = Length - len;

if (Length > len){
for (int i = sz; i < (len + sz);i++){
DataBuf[i] = buf[i-sz];
}
}
else{
for (int i =sz; i < (Length +sz);i++){
DataBuf[i] = buf[i-sz];
}
//тут надо обрабатывать полученный пакет
}
}

}


Работоспособно?

GASCHE
04.02.2016, 16:37
Работоспособно?Не знаю, len - это что?

T_r_D
04.02.2016, 18:47
Не знаю, len - это что?

Это длина буфера с пришедшим сообщением

Вот только не пойму
Length = (buf[0] & 0x0F * 256 + buf[1]) - (len -2);
постоянно возвращает -6.
тоесть (buf[0] & 0x0F * 256 + buf[1]) равно нулю!

Length это int

T_r_D
04.02.2016, 18:49
вот полный код

#include <SPI.h>
#include "mcp_can.h"
MCP_CAN CAN(10);
unsigned char len = 0;
unsigned char buf[8];
INT32U canId = 0x000; // идентификаторы могут быть 11-ти или 29-битные

int LengthP;
int DataBuf[100];
int DataBufSize;

void setup()
{
Serial.begin(38400);
pinMode(9, INPUT);

START_INIT:
if(CAN_OK == CAN.begin(CAN_125KBPS,MCP_8MHz))
{Serial1.println("Init OK!");}
else
{Serial1.println("Init fail");delay(100);goto START_INIT;}
}


void loop()
{
// if(CAN_MSGAVAIL == CAN.checkReceive()) // check if data coming
if(!digitalRead(9))
{
CAN.readMsgBuf(&len, buf);
canId = CAN.getCanId();

if(canId == 293) // 125HEX
{
Serial.println("PKG");
if ((buf[0] >> 4) == 0x01)
{
LengthP = (buf[0] & 0x0F * 256 + buf[1]) - (len - 2);
for (int i=0; i<len;i++){
DataBuf[i] = buf[i];
DataBufSize = i;
}
Serial.print("FIRST Length=");
Serial.println(LengthP);
}

if(((buf[0] >> 4) == 0x02) && LengthP > 0){
int Length2 = LengthP - len;
Serial.print("SECOND Length=");
Serial.print(LengthP);
Serial.print(" len=");
Serial.println(len);

if (Length2 > len){
Serial.println("SECOND>>> Length=");
Serial.print(LengthP);
Serial.print(" len=");
Serial.println(len);

for (int i = 0; i < len;i++){
DataBuf[i+DataBufSize] = buf[i];
}
DataBufSize = DataBufSize + len;
}
else{
Serial.println("SECOND2>>> Length=");
Serial.print(LengthP);
Serial.print(" len=");
Serial.println(len);

for (int i=0; i < LengthP;i++){
DataBuf[i + DataBufSize] = buf[i];
}
DataBufSize = DataBufSize + LengthP;

for (int i; i < DataBufSize;i++){
Serial.print(DataBuf[i], HEX);
}
Serial.println(" ");
}
}

}
}
}

GASCHE
04.02.2016, 19:13
Это длина буфера с пришедшим сообщением

мой лог в HEX
10 0D 10 1D 19 10 56 45
04 00 60
30 00 0A
10 00
21 53 54 49 20 46 4D 90
00 00 00 00 00 00 00 D0
00 FF FF 00 55 00 00 00
01 03 92 40 00 D0 00 10
00 00 02 6F 00 59 00 00
FF FF 00 50 00 00 00 00
01 00 00 00 00
00 FF FF 00 00 07 38 09
02 3F FF FF FF 00 FF FF

Если сообщение 10 0D 10 1D 19 10 56 45 то
buf[0] & 0x0F * 256 = 0
buf[1] = 0D
Length = (buf[0] & 0x0F * 256 + buf[1]) = 0D общая длина сообщения.
Теперь
First frame количество значащих байт 6
j = 0;
for (int i=2; 6;i++){
DataBuf[j] = buf[i];
j++;
}
Теперь судя по логу надо искать 21 и со следующего байта копировать 7 или (Length - 6) байт если (Length - 6) < 7 потом искать 22 если надо и так далее пока не скопируете Length байт.
В этом случае в DataBuf будет посылка без обрамления и DataBufSize = Length.
К сожалению я не знаю язык на котором вы пишите.

T_r_D
04.02.2016, 19:15
модифицировал чтоб видить пакеты

{
CAN.readMsgBuf(&len, buf);
canId = CAN.getCanId();

if(canId == 293) // 125HEX
{
Serial.print("PKG: ");
for (int i=0;i<len;i++){
Serial.print(buf[i], HEX);
Serial.print(" ");
}
Serial.println("");

if ((buf[0] >> 4) == 0x01)


В лог пришло следующее:
PKG: 10 D 10 1D 13 10 4E 52
FIRST Length=-6
PKG: 21 4A 31 30 34 2E 32 B0
PKG: 10 D 10 1D 12 10 4D 41
FIRST Length=-6
PKG: 21 58 49 4D 55 4D 20 80
PKG: 10 D 10 1D 11 10 20 4D
FIRST Length=-6
PKG: 21 2D 43 41 52 4C 4F 90
PKG: 10 D 10 1D 10 10 20 20
FIRST Length=-6
PKG: 21 4A 61 7A 7A 20 20 90
PKG: 10 D 10 1D F 10 46 4D
FIRST Length=-6
PKG: 21 20 38 39 2E 39 20 90
PKG: 10 D 10 1D E 10 45 75
FIRST Length=-6
PKG: 21 72 6F 70 61 20 20 90
PKG: 10 D 10 1D D 10 44 4F
FIRST Length=-6
PKG: 21 50 4F 2A 48 4F 45 80
PKG: 10 D 10 1D C 10 44 46
FIRST Length=-6
PKG: 21 4D 44 41 4E 43 45 90
PKG: 10 D 10 1D B 10 20 44
FIRST Length=-6
PKG: 21 41 43 48 41 20 20 90
PKG: 10 D 10 1D A 10 20 43
FIRST Length=-6
PKG: 21 4F 4D 45 44 59 20 90
PKG: 10 D 10 1D 9 10 42 45
FIRST Length=-6
PKG: 21 53 54 20 46 4D 20 90
PKG: 10 D 10 1D 8 10 42 45
FIRST Length=-6
PKG: 21 43 48 41 20 46 4D 90
PKG: 10 D 10 1D 7 10 61 6E
FIRST Length=-6
PKG: 21 73 6F 6E 2E 66 6D 80
PKG: 10 D 10 1D 6 10 39 38
FIRST Length=-6
PKG: 21 2E 38 20 46 4D 20 90
PKG: 10 D 10 1D 5 10 20 39
FIRST Length=-6
PKG: 21 38 2E 34 20 46 4D 90
PKG: 10 D 10 1D 4 10 20 39
FIRST Length=-6
PKG: 21 36 2C 38 20 46 4D 90
PKG: 10 D 10 1D 3 10 39 30
FIRST Length=-6
PKG: 21 2E 33 20 46 4D 20 B0
PKG: 10 D 10 1D 2 10 38 38
FIRST Length=-6
PKG: 21 2E 37 20 46 4D 20 B0
PKG: 10 D 10 1D 1 10 20 20
FIRST Length=-6
PKG: 21 38 38 2E 33 20 20 90
PKG: 10 D 10 1D 0 10 31 30
FIRST Length=-6
PKG: 21 37 2E 38 20 46 4D 80

Грабли точно в строке
LengthP = (buf[0] & 0x0F * 256 + buf[1]) - (len - 2);
Может её нужно как-то по другому записать или скобок где наставить?

Короче сам разобрался
скобок не хватало
LengthP = ((buf[0] & 0x0F) * 256 + buf[1]) - (len - 2);
вот так всё красиво!

От тестировал - пакет собирается. Но у меня почему-то по одному пакету данных всегда...
Возможно из за дисплея.
И по сути в этом пакете ни чего важного больше и нет.
Можно просто строку эту вытащить и всё.

T_r_D
05.02.2016, 14:46
Вот окончательный скетч который точно работает с одной строчкой, тоесть First Frame + Consecutive Frame. У меня больше 1 Consecutive Frame не идёт с моим дисплеем.

#include <SPI.h>
#include "mcp_can.h"
MCP_CAN CAN(10);
unsigned char len = 0;
unsigned char buf[8];
INT32U canId = 0x000; // идентификаторы могут быть 11-ти или 29-битные

int LengthP;
int DataBuf[100];
int DataBufSize;

void setup()
{
Serial.begin(38400);
pinMode(9, INPUT);
delay (7000);
START_INIT:
if(CAN_OK == CAN.begin(CAN_125KBPS,MCP_8MHz))
{Serial1.println("Init OK!");}
else
{Serial1.println("Init fail");delay(100);goto START_INIT;}
}


void loop()
{
// if(CAN_MSGAVAIL == CAN.checkReceive()) // check if data coming
if(!digitalRead(9))
{
CAN.readMsgBuf(&len, buf);
canId = CAN.getCanId();

if(canId == 293) // 125HEX
{
if ((buf[0] >> 4) == 0x01)
{
LengthP = ((buf[0] & 0x0F) * 256 + buf[1]) - (len - 2);
DataBufSize = len;
for (int i=0; i<len;i++){
DataBuf[i] = buf[i];
}
}

if(((buf[0] >> 4) == 0x02) && LengthP > 0){
int Length2 = LengthP - len;
if (Length2 > len){
for (int i = 0; i < len;i++){
DataBuf[i + DataBufSize] = buf[i];
}
DataBufSize = DataBufSize + len;
}
else{
for (int i=0; i < LengthP;i++){
DataBuf[i + DataBufSize] = buf[i];
}
DataBufSize = DataBufSize + LengthP;

for (int i=0; i < DataBufSize;i++){
Serial.print(DataBuf[i], HEX);
Serial.print(" ");
}
for (int i=0; i < DataBufSize;i++){
Serial.print(char(DataBuf[i]));
}
Serial.println(" ");
}
}

}
}
}


Выдаёт он вот такое:
10 D 10 1D 12 10 4D 41 21 58 49 4D 55 4D 20 MA!XIMUM
10 D 10 1D 11 10 20 48 21 49 54 20 46 4D 20 H!IT FM
10 D 10 1D 10 10 46 4D 21 20 38 39 2E 39 20 FM! 89.9
10 D 10 1D F 10 45 75 21 72 6F 70 61 20 20 Eu!ropa
10 D 10 1D E 10 44 4F 21 50 4F 2A 48 4F 45 DO!PO*HOE
10 D 10 1D D 10 20 44 21 41 43 48 41 20 20 D!ACHA
10 D 10 1D C 10 20 43 21 4F 4D 45 44 59 20 C!OMEDY
10 D 10 1D B 10 20 42 21 4F 43 54 4F 4B 20 B!OCTOK
10 D 10 1D A 10 42 45 21 53 54 20 46 4D 20 BE!ST FM
10 D 10 1D 9 10 42 45 21 43 48 41 20 46 4D BE!CHA FM
10 D 10 1D 8 10 61 6E 21 73 6F 6E 2E 66 6D an!son.fm
10 D 10 1D 7 10 20 39 21 38 2E 34 20 46 4D 9!8.4 FM
10 D 10 1D 6 10 39 36 21 2C 34 20 46 4D 20 96!,4 FM
10 D 10 1D 5 10 20 39 21 35 2E 36 20 46 4D 9!5.6 FM
10 D 10 1D 4 10 39 30 21 2E 33 20 46 4D 20 90!.3 FM
10 D 10 1D 3 10 38 38 21 2E 37 20 46 4D 20 88!.7 FM
10 D 10 1D 2 10 20 20 21 38 38 2E 33 20 20 !88.3
10 D 10 1D 1 10 31 30 21 37 2E 38 20 46 4D 10!7.8 FM
10 D 10 1D 0 10 31 30 21 36 2C 36 20 46 4D
То что нечитабельными символами в ascii сюда не копируется, но между хексом и нормальным текстом то, что не перевелось в ascii.
Восклицательный знак это 0 байт Consecutive Frame.

При нажатии кнопки LIST при проигрование диска на дисплее отображаются номер трека и звёздочки за место текста (ну его и нет), но в этот ID это почему-то не попадает....

T_r_D
06.02.2016, 18:48
Итак, у меня классные новости!
Я купил магнитолу и дисплей, кинул их на стол, отсканировал и нашёл то, что мне не хватало.
Нашёл где прячится иконка LOUD, а так же подошёл к событию которое позволит выкинуть дисплей штатный нафиг.
Вот что я накопал:
ID от дисплея
0 <0,0,80,1> через секунд 30 после включения
4 <0,F,F0,0,0,80,1> через секунд 30 после включения
6 <FF,FF,7F,FF,0,0> через секунд 30 после включения
5E0 Один раз при подключении питания магнитолы.
1ED неизменен
167 неизменен
15B неизменен
525 неизменен
5E5 неизменен
DF Отвечае открыто меню или нет: 10,0,50 открыто, 90,0,70 не открыто.
Если не отреагировать на нажатие кнопки MENU изменением битов,
то магнитола не отреагирует и будет кнопками также переключать станции или треки.

Всего 10 ID. Скорее всего какие-то отвечают за набор функций в дисплее.
Это будет просто проверить отсканировав мой строчный дисплей (этот графический).

T_r_D
07.02.2016, 12:43
Так ребят, извиняюсь.
Вчера не было времени на детальный анализ ID.
Исправляюсь

0xDF Отвечае открыто меню или нет и состояние его элементов.
За открытие меню отвечает второй байт.
50HEX 0101 0000 закрыто
70HEX 0111 0000 открыто

Первый байт отвечает за выбор элемента.
Отображает выбраный элемент в реальном времени если меню вызвано через OK
или последний элемент с которым производились действия если меню вызвано через MENU.
При повторном входе в меню любой кнопкой сбрасывается на первый элемент.
1HEX 00000001 Alternative frequencies
3HEX 00000011 Regional mode (00000010, но не включается без RDS)
24HEX 00100100 Radio-text information
42HEX 01000010 Track random play

Нулевой байт отвечает сразу за 2 функции.
при неактивном меню
10HEX 00010000 Выход из меню по таймауту или ESC
11HEX 00010001 элемен был деактивирован
12HEX 00010010 элемент был активирован
при активном
90HEX 10010000 нахождение в меню в предидущий вход действий с элементами не выполнялось
91HEX 10010001 элемент был активирован - передаётся во время нажатия OK
92HEX 10010010 элемент был деактивирован - передаётся во время нажатия OK

Тоесть если вы попали в меню через OK, то положение в нём можно отследить, если через кнопку MENU, то нет.

T_r_D
08.02.2016, 13:19
И ещё раз прошу помощи с мультифреймом.
Собрал пакет и не пойму как теперь его разбить на части.
Вот пример:

10 28 10 1E 0 41 2D 45 >>> -E
21 4E 45 52 47 59 2D B0 >>> N E R G Y - °
22 31 30 33 2E 30 20 46 >>> 1 0 3 . 0 F
23 4D 80 20 20 38 38 2E >>> M Ђ 8 8 .
24 33 20 20 80 39 30 2E >>> 3 Ђ 9 0 .
25 33 20 46 4D 20 B0 2E >>> 3 F M ° .
10 28 10 1E 0 41 2D 45 4E 45 52 47 59 2D B0 31 30 33 2E 30 20 46 4D 80 20 20 38 38 2E 33 20 20 80 39 30 2E 33 20 46 4D 20 B0 0 ( A-ENERGY-°103.0 FMЂ 88.3 Ђ90.3 FM °

Присутствует паразитный(а может и нет, а информационный) символ 80(Ђ).
На экране БК выглядит так:
-ENERGY- PTY TA
103.0 FM
88.3
90.3 FM PTY TA

И не понятно ещё где хранятся данные о PTY, но оно отображается.

B0 ° это признак TA на станции с РДС, а вот пакет для станций без РДС, но с ТА. там 0. И как его выуживать тоже не понятно. Единственное он всегда в плотную к следующей надписи идёт

10 28 10 1E C 41 39 33 >>> 9 3
21 2E 36 30 0 0 0 10 >>> . 6 0
22 39 34 2E 38 30 0 0 >>> 9 4 . 8 0
3 0 30 39 35 2E 32 30 >>> 0 9 5 . 2 0
24 0 0 0 10 39 35 2E >>> 9 5 .
25 36 30 0 0 0 10 2E >>> 6 0 .
10 28 10 1E C 41 39 33 2E 36 30 0 0 0 10 39 34 2E 38 30 0 0 0 30 39 35 2E 32 30 0 0 0 10 39 35 2E 36 30 0 0 0 10 0 (A93.60 94.80 095.20 95.60

autowp
08.02.2016, 13:56
10 28 в собранном сообщение быть не должно.

>> Присутствует паразитный(а может и нет, а информационный) символ 80(Ђ).

Конечно он не паразитный. Что-то он в себе несёт, но покуда вам нет в нем нужды, игнорируйте этот байт.

Вторая посылка на первый взгляд выглядит так же, как первая. не понятен вопрос.

У всех данных фиксированные позиции в посылках. Иначе и быть не может. Если в одно сообщение информация идет 5ым байтом, то и в другом она будет 5ым байтом

T_r_D
08.02.2016, 14:29
10 28 в собранном сообщение быть не должно.

>> Присутствует паразитный(а может и нет, а информационный) символ 80(Ђ).

Конечно он не паразитный. Что-то он в себе несёт, но покуда вам нет в нем нужды, игнорируйте этот байт.

Вторая посылка на первый взгляд выглядит так же, как первая. не понятен вопрос.

У всех данных фиксированные позиции в посылках. Иначе и быть не может. Если в одно сообщение информация идет 5ым байтом, то и в другом она будет 5ым байтом

Я не понял.
Выглядят-то они идентично. Вопрос как разбить на строки?
Специально дал то, что отражается на дисплее. Ведь сообщения которые в разных посылках в одной строчке на дисплеее.
Как искать разделение?

А, всё! ДОГНАЛ!
Получается что мои сообщения всегда занимают 9 байт! Счёт идёт с 6 байта первого пакета!

Это утверждение не верно!
У всех данных фиксированные позиции в посылках. Иначе и быть не может. Если в одно сообщение информация идет 5ым байтом, то и в другом она будет 5ым байтом

T_r_D
08.02.2016, 17:49
так ребят, не наступите на грабли! Я час потратил чтоб разобраться! Символы переведённые способом char(), переводятся все и получается что даже не видимые символы могут потом складываться с видимыми давая чудесные результаты!
вот окончательный код сборки строки.
через | выводится что поддерживает данная станция.

if(canId == 293) // 125HEX
{
if ((buf[0] >> 4) == 0x01)
{
LengthP = ((buf[0] & 0x0F) * 256 + buf[1]) - 6;
DataBufSize = 2;
DataBuf[0]=buf[6];
DataBuf[1]=buf[7];
}

if(((buf[0] >> 4) == 0x02) && LengthP > 0){
if (LengthP > 8)
{
for (int i=1; i < 8;i++) DataBuf[i + DataBufSize - 1] = buf[i];
DataBufSize = DataBufSize + 7;
LengthP = LengthP - 7;
}
else{
for (int i=1; i < LengthP+1;i++) DataBuf[i + DataBufSize - 1] = buf[i];
DataBufSize = DataBufSize + LengthP;

//OUT OF MESSAGE
for (int c=0; c < DataBufSize/9;c++){
String strmsg;
for (int i= 9*c; i < (9*c)+8;i++){
if (DataBuf[i] > 31) strmsg = strmsg + char(DataBuf[i]);
else strmsg = strmsg + " ";
}
strmsg = strmsg + "|" + String(DataBuf[(9*c)+8]);
Message[c] = strmsg;
}
for (int i=0; i < DataBufSize/9;i++) Serial.println(Message[i]);
}
}

}

Dmitry8
09.02.2016, 13:51
T_r_D, а как вы собираетесь инсталлировать планшет в машину? Есть уже какой-то план? Пилить пластик будете? Заглушки штатные будут?

T_r_D
09.02.2016, 14:30
T_r_D, а как вы собираетесь инсталлировать планшет в машину? Есть уже какой-то план? Пилить пластик будете? Заглушки штатные будут?

Ни чего видимого пилить не буду. Из невидимого рамку изнутри изрядно вырезать надо будет и 4 отверстия для крепления прижимной "пластины" планшета к рамке.

А пластина в кавычках потому что это площадка из оргстекла которая одновременно будет и прижимать планшет к рамке и на неё же крепиться моя плата.

А сама рамка вот
http://www.ebay.com/itm/Car-Radio-Frame-Dashboard-Fascia-Panel-Trim-for-Citroen-C4-C-Quatre-C-Triumph-/281108464553?hash=item41735ec3a9:g:rpwAAOSwRLZUAE-B&vxp=mtr

Только отверстие под SD уберу и затяну в плёнку под карбон.

Dmitry8
09.02.2016, 14:36
Я думал у вас Ситроен С4 b7, как у меня. Ищу решение чтобы ничего не пилить, планшет под нужный размер пока найти не удалось.

T_r_D
10.02.2016, 11:40
Кстати в мультифрейме идёт ещё и выбор запрограммированных станций. При нажатии кнопок 1-6 тоже отображается мультифрейм и при нажатии кнопки BAND.

Надо записать диск с CD-Text и посмотреть как там организован мультифрейм.

Для этих случаев он организован одинакого- пакет состоит из 8 байт текстовой информации + 1 байт служебной. Для листа станций радио этот девятый байт это PTY, TA, RDS.

Скоро совмещу мультифрейм скетч и основной и покажу что получилось.

По идеи остаётся два меню- одно для кнопки OK на радио, второе на ЦД.
Это собственные меню магнитолы. Они идут с выбором позиции. В них те же пункты что и по кнопке MENU, но отрабатываемые магнитолой, а не дисплеем.
Тоесть там включение RDS, REG, RDTXT, Intro mode, Random play.

А и ещё меню с выбором трека если нет CD-Text. Оно выдаётся по кнопке LIST

PS.
Пытался записать болванку с ЦД-текстом разными программами и ни одной не получилось!
Есть у кого такой компакт? Снимите образ с него, а то проверить не могу.

T_r_D
18.02.2016, 09:33
Короче забил я на CD-Text. Как не старался его записать на болванку ни чего не вышло. Если попадётся, то допишу потом его расшифровку...

Для полного завершения не хватает отработки трёх меню.
Первое при нажатии кнопки OK в режиме радио
Второе при нажитии кнопки OK в режиме CD
Третье при нажатии собственно кнопки MENU.

Если дисплей подключен, то по ID DF он передаёт в магнитолу выбраный элемент меню, но вопрос откуда он берёт эти меню.
Оказалось что при загрузке у него для радио 3 стандартных пункта меню, а для CD один. Я так понимаю что это минимальный набор и он присутствует всегда.
Далее похоже на то, что дисплею посылается установка, но какая-то она маленькая...
ID 365
при запуске FF,FF,FF,0,0
при работе 45,31,1B,0,0
В процессе работы меняется иногда на пустое, но на долю секунды
Возможно что такой пакет это и есть опции меню?
Просто больше других не вижу.

Итак- раскопал я этот ID. Отношение к меню он имеет только тем, что если вставлен диск, то появляется дополнительный элемент меню.

при запуске и если нет диска FF,FF,FF,0,0
при работе:
Нулевой байт это количество треков на диске.
Первый байт общее время на диске минуты
Второй байт общее время на диске секунды
Третий и четвёртый ноли всегда.

В процессе работы меняется иногда на пустое, но на долю секунды

Если диск вставлен, то в меню появляется пункт Activate Track Intro

Тоесть меня это не особо приблизило к цели, но из задачь убралось первые два пункта.

Кстати в 1E0 ещё и источник передаётся!
нулевой байт это источник!
0101 0000
^^
||радио
|CD
Дальше надо в машине смотреть, на столе нету ни аукса ни ченджера.

T_r_D
20.02.2016, 14:16
Найден ещё один ID с мультифреймом!

Radio Text 0xA4

5 10 0 0 0 0
10 44 10 0 0 0 20 20
21 20 20 20 20 20 20 20
22 20 20 20 2E 63 6F 6D
23 2F 72 61 64 20 20 20
24 20 20 20 20 20 72 75
25 20 20 20 20 20 20 20
26 20 20 20 20 20 20 20
27 20 20 20 20 20 20 20
28 20 20 20 20 20 20 20
29 20 20 20 20 20 20
23 2F 72 61 64 69 6F 73
24 70 20 20 20 20 72 75
10 44 10 0 0 0 49 4E
21 20 40 20 77 77 77 2E
22 69 6E 73 20 20 20 20
23 20 20 20 20 20 20 20
24 20 20 20 20 20 5F 66
25 6D 20 20 20 20 20 20
22 69 6E 73 74 61 67 72
23 61 6D 2E 63 6F 6D 2F
24 73 70 6F 72 74 5F 66
22 20 20 20 20 20 20 20
24 20 20 20 20 20 20 20
23 52 53 54 20 20 20 20
21 20 20 20 77 77 77 20
10 44 10 0 0 0 46 42
22 66 61 63 20 20 20 20
23 20 20 20 20 6D 2F 73
24 70 6F 72 74 66 6D 2E
25 72 75 20 20 20 20 20
21 20 20 20 74 77 69 20
23 61 6D 2E 63 20 20 20
24 20 70 6F 72 74 20 20
24 73 70 6F 72 74 20 20
21 20 40 20 77 77 77 20
10 44 10 0 0 0 40 20

autowp
20.02.2016, 14:30
Найден ещё один ID с мультифреймом!

Radio Text 0xA4


Прям "breaking news" =)
http://autowp.github.io/#0A4

T_r_D
21.02.2016, 03:57
autowp

Source: Radio
Dest: Display

Current track name

ISO 15765-2
0A4
00100000 00000000 010
A
1 - message contains track author data
1000
NNNNNNNN
track nubmer
[
TEXT_DATA
author & track name
]

И?
Тут понятно что это? Что у тебя написано?
Какой блин автор и трек нейм?
Это Радиотекст!

Я тебя просил поправить свои таблицы с моими дополнениями- ты сказал чтоб я сам их правил.
Так что буду тут разъяснять что нахожу.

autowp
21.02.2016, 12:38
Я и не говорю, что там все понятно. Я просто заметил, что "найден!" звучит странно.

>Какой блин автор и трек нейм?
>Это Радиотекст!

Логично предположить, что это и то, и другое : текущий трек/станция

T_r_D
23.02.2016, 19:45
Так. Потестил всё и пошёл в машину.
Оказалось что в машине List of station который передаётся мультифреймом не такой как дома. Он всегда состоит из одной строки отображающийся на дисплее.
Короче стало очевидно что магнитола определяет тип дисплея который подключён или может он прописывается диагностической программой при установке?
Есть у кого какие мысли?
На всякий приложу картинку с ID которые у меня есть на столе в связке магнитола и нормальный дисплей. Там нескольких нет, но они возникают после некоторого время работы, так что не относятся точно к иниту дисплея если он есть.

T_r_D
24.02.2016, 08:55
Народ, а кто нить делал что нить на исходниках для дройда которые я использую? Всплыла плохая бяка. С увеличением длины строки некоторые цифры начинают переводится в ASCII как я подозреваю. Тоесть при каком-то наборе символов в передаваемой строке всё замирает, а дальнейшие пакеты валятся в буфер. Какое-то время это продолжается, а потом вываливается всё что накопилось. Ща не дома, но если интересно, то могу дать строку которая при передачи с ардуины в дройд не будет отображаться совсем, но как только в ней поменяется первое число, то выпадет на экран всё что напередавалось

xmetal
24.02.2016, 12:22
Короче стало очевидно что магнитола определяет тип дисплея который подключён или может он прописывается диагностической программой при установке?
Есть у кого какие мысли?Мое предположение такое, в момент подключения магнитолы происходит обмен информацией с авто, считывание пин - кода как минимум, возможно инфа о конфигурации дисплея тоже проскакивает. Нужно начинать сниферить кан шину до подключения разъема магнитолы, чтобы поймать этот самый момент подключения.

Dmitry8
24.02.2016, 18:59
Мой дисплей после включения постоянно отправляет какие-то данные. Вполне вероятно что в них указан тип дисплея.

T_r_D
24.02.2016, 23:36
У меня на столе собрана магнитола и дисплей. При включении они выплёвывают по одному Id. На картинке такой id для дисплея указан. При этом есть циклический id который очень похож на тот который единожды проходит.

Короче я понял- Ща с глюком перекодировки разбирусь, доделаю менюшки не требующие эмуляции дисплея и с машины сниму свой строчечный дисплей чтоб на столе запустить и посмотреть отличия.

Dmitry8
25.02.2016, 10:25
Так у вас в машине другой тип дисплея?
Скорее всего при телекодировании в магнитоле прописывается тип дисплея и от этого зависит как она передаёт данные на дисплей.

T_r_D
25.02.2016, 15:56
Народ- дурацкий вопрос. Передаю из ардуины дройду два байта
DATA[9] = 0x09;
DATA[10] = 0xA0;
принимаю на стороне дройда нормально, а теперь пытаюсь их склеить и получаю чушь!
(Arbyte[9] << 8) + Arbyte[10])

Arbyte[9] равно -91 и поэтому заполняется еденицами, а нужно чтоб нолями.
Как это сделать?

GASCHE
25.02.2016, 22:41
А так (Arbyte[9] * 256 ) + Arbyte[10] не пробовали?

T_r_D
25.02.2016, 23:42
Пробовал- тоже самое.
Помогла маска 0хff.
Там дело в том, что он про арбайт 10 думает что оно-90, а оно на самом деле 160.
Тоесть 160 это 16 бит и старшим забиты нулями. Если обрезать до 8 бит, то получится как раз -90

GASCHE
26.02.2016, 10:43
Тоесть 160 это 16 бит и старшим забиты нулями. Если обрезать до 8 бит, то получится как раз -90Вы бы вначале сами разобрались. Как это Байт стал 16 бит и при этом еще умудрился сдвинуться на 4 бита?

lti1
26.02.2016, 11:43
Вы бы вначале сами разобрались. Как это Байт стал 16 бит и при этом еще умудрился сдвинуться на 4 бита?
Ни какого сдвига на 4 бита нет. А вот каким чудесным образом в андройд меняется тип значения на 16 битный, не понятно.
T_r_D описался, не -90, а -96.

GASCHE
26.02.2016, 13:17
T_r_D описался, не -90, а -96.Даже не знаю что сказать
00001001(09)*00000001 00000000(256)=00001001 00000000(09 00)
00001001 00000000(09 00) + 10100000(А0) = 00001001 10100000(09 A0)

01011010(90) это еще можно объяснить, но это 01100000(96) откуда вы взяли, даже понять не могу.

lti1
26.02.2016, 13:30
Даже не знаю что сказать
00001001(09)*00000001 00000000(256)=00001001 00000000(09 00)
00001001 00000000(09 00) + 10100000(А0) = 00001001 10100000(09 A0)

01011010(90) это еще можно объяснить, но это 01100000(96) откуда вы взяли, даже понять не могу.
Не 01100000(96), а 10100000(-96).
8 бит и 16 бит дают разный результат.

xmetal
26.02.2016, 15:43
Я так понимаю вся беда в том, что ява не поддерживает беззнаковый тип данных, отсюда и косяки. Либо надо работать с более вместительными типами, либо как сделал T_r_D, обрезать маской.

lti1
26.02.2016, 15:57
Беззнаковая арифметика в Java (https://habrahabr.ru/post/225901/)

GASCHE
26.02.2016, 16:57
Уж не знаю что у него , но вот он писал
int LengthP;
LengthP = (buf[0] & 0x0F * 256 + buf[1]) - (len - 2);
и говорит что работает.

lti1
26.02.2016, 17:06
Уж не знаю что у него , но вот он писал

и говорит что работает.
Внимательнее прочитайте.
Народ- дурацкий вопрос. Передаю из ардуины дройду два байта
DATA[9] = 0x09;
DATA[10] = 0xA0;
принимаю на стороне дройда нормально, а теперь пытаюсь их склеить и получаю чушь!
(Arbyte[9] << 8) + Arbyte[10])

Arbyte[9] равно -91 и поэтому заполняется еденицами, а нужно чтоб нолями.
Как это сделать?

T_r_D
01.03.2016, 13:28
Найдена очередная неточность в описании от autowp.
ID 265
байт 2 это не текущий элемент меню, а вообще выбранный элемент! Тоесть скажем Sport и он будет выбран даже после выхода из меню.

байт 3 это текущяя PTY станции. Если она не совпадает с выбранной в меню, то значёк PTY перечёркнут, а если совпадает, то нормальный.

T_r_D
02.03.2016, 18:02
В том же 265 ID
Байт 0 бит 5 это сообщение Please Wait когда идёт поиск PTY станций.
Причём 1 когда надписи нету, тоесть рабочий режим.

ошибся!
Всё ещё проще
байт 0
бит 7 надпись RDS
бит 5 надпись перечёркнутая RDS и REG
бит 4 TA
бит 2 перечёркнутое TA

байт 1
бит7 PTY
бит6 PTY menu show
бит4 надпись перечёркнутая PTY

T_r_D
03.03.2016, 14:56
ещё покопал.
Сообщение Please Wait обозначается почему-то в двух ID сразу!

1E0 второй байт в режиме радио и если идёт поиск PTY с надписью на экране
Please Wait, то 61 если надпись пропала, то A2.
Скорее всего там только какой-то бит отвечает за это, а что остальное- хз.

А второе место из раскопаного ID 225
Byte 0
0- В процессе поиска PTY (бит 2 показывает тоже самое?).
1- 1 когда идёт поиск частоты радио
2- см выше
3- не опознан
4- не опознан
5- в какую сторону шло сканирование. Если в + частоты, то 1 если в - то 0
6- не опознан
7- после поиска PTY 1- нашли, 0- нет. Если 1, то мультифреймом выводится список, если 0, то надпись что не нашли с выбранной опцией PTY.

Byte 1
Если текущая частота в памяти то 10,20,30,40,50,60 в DEC или если не в памяти, то 0

Byte 2
10dec- fm1
20dec- fm2
40dec- fm ast
50dec- MW

Byte 3,4 частота радио для FM формула (byte3|byte4)/20+50, для MW byte3|byte4

T_r_D
07.03.2016, 16:33
Спасибо lti1. Научил меня делать скриншоты с планшета :)

Ловите!

T_r_D
07.03.2016, 16:44
Ну и фотки того что творю не в виртуальном мире, а в материальном.
Обтянуто плёнкой, оргстекло как основа для крепления платы и держалка планшета в рамке.

T_r_D
08.03.2016, 17:15
Все окна что выводят инфу они поверх всего и вылезают даже когда приложение скрыто.

Дописал PTY лист и сообщение когда идёт поиск PTY

Рамки этим сообщениям сделать надо, но ща тестирование и попытка дружить железки вместе.

T_r_D
09.03.2016, 14:24
И ещё одна менюшка готова.

Dmitry8
09.03.2016, 19:01
Все окна что выводят инфу они поверх всего и вылезают даже когда приложение скрыто.
Интересно, можно узнать подробности? Я так понимаю, Приложение состоит из фоновой службы и активностей вызываемых по определенным событиям? Какие свойства должны быть у активностей для описываемого здесь поведения?

T_r_D
09.03.2016, 20:30
приложение состоит из трёх частей.

Первая часть это главное активити которое стартует сервис.
Сервис принимает сообщения из порта и делит в две стороны- в главную активити и на всплывающие окно. Это часть два.
И часть три это всплывающее окно. Оно реализовано тоже сервисом.

Ну и да- в фоне всегда служба приёма пакетов :)

T_r_D
09.03.2016, 21:45
В основе лежит всё равно проект автора дров.
https://github.com/felHR85/UsbSerial
Я не претендую на первенство- я просто модифицировал его библиотеку под себя.

Dmitry8
09.03.2016, 21:50
Я немного о другом спрашивал. Что вы подразумеваете под:
всплывающие окно.

T_r_D
09.03.2016, 21:53
Dmitry8
Про свойства активности я не понял, но окно создаётся динамически.
Сначала создаётся сервис, а потом создаётся лейаут и компоненты на нём формируя конечное "окно".

Dmitry8
09.03.2016, 21:58
Dmitry8
Про свойства активности я не понял, но окно создаётся динамически.
Сначала создаётся сервис, а потом создаётся лейаут и компоненты на нём формируя конечное "окно".

Чтобы было понятнее, выложите сюда код xml-файла, описывающего свойства активити, которое на последнем скриншоте.

T_r_D
09.03.2016, 22:00
нету его. XML в смысле
И активити там нет.
Динамически из явы создаётся

Код создания окна если поможет
public void Window_style_rec (){
Typeface face = Typeface.createFromAsset(getAssets(), "lcd.ttf");
wm = (WindowManager) getSystemService(WINDOW_SERVICE);
ll = new LinearLayout(this);
msgstr = new TextView(this);
img = new ImageView(this);
LinearLayout.LayoutParams llParameters = new LinearLayout.LayoutParams(LinearLayout.LayoutParam s.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT );
ll.setBackgroundColor(Color.argb(180, 0, 0, 0)); //255,0,0
ll.setOrientation(LinearLayout.HORIZONTAL);


ViewGroup.LayoutParams groupParameters = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP _CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT);
img.setLayoutParams(groupParameters);
msgstr.setTypeface(face);
msgstr.setTextSize(80);
msgstr.setTextColor(0xFFE6E9FD);
msgstr.setLayoutParams(groupParameters);


ll.setLayoutParams(llParameters);
ll.addView(img);
ll.addView(msgstr);

WindowManager.LayoutParams parameters = new WindowManager.LayoutParams(WindowManager.LayoutPar ams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTE NT,WindowManager.LayoutParams.TYPE_PHONE,WindowMan ager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT);
parameters.x = 0;
parameters.y = 0;
parameters.gravity = Gravity.CENTER | Gravity.CENTER;
wm.addView(ll, parameters);
}

T_r_D
10.03.2016, 10:28
Народ- вопрос.
Кто что знает про радиотекст?
Интересует есть ли у него ограничение по длине текста или нет?

xmetal
10.03.2016, 11:53
Народ- вопрос.
Кто что знает про радиотекст?
Интересует есть ли у него ограничение по длине текста или нет?
До 64 знаков. Страница 25. ftp://ftp.rds.org.uk/pub/acrobat/rbds1998.pdf

T_r_D
10.03.2016, 18:51
xmetal Вот спасибо!

Так, теперь в ход пошла тяжёлая артиллерия.
Мультифрейм стало быть.

T_r_D
11.03.2016, 11:05
Может кто знает.
Есть XML
В нём рамка.

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">

<solid android:color="#DC000000" />
<stroke
android:width="3dip"
android:color="#FFFFFF" />

<corners android:bottomRightRadius="10dip"
android:bottomLeftRadius="10dip"
android:topLeftRadius="10dip"
android:topRightRadius="10dip"/>

</shape>


Она соответственно на лейаут применяется.
Получается как на первой картинке, а надо как на второй.
Что куда вписать?

T_r_D
11.03.2016, 12:39
Вопрос с LayoutInflater снят.

Результат:

T_r_D
11.03.2016, 18:06
Ну и пошёл процесс окультуривания

T_r_D
12.03.2016, 12:27
Всё, сегодня я закончил со всеми меню которые можно повторить без эмуляции дисплея. Мне осталось сделать
1 отображение если станция в памяти (Mem1 -6)
2 Радиотекст
3 Отловить поиск станций РДС. Надпись появляется RDS Search и всё замолкает.

T_r_D
12.03.2016, 17:50
Вот окончательный вид интерфейса. Не реальный только радиотекст, всё остальное снимается с магнитолы которая лежит на столе.

T_r_D
13.03.2016, 20:03
Вопрос с радиотекстом решён. Кстати он почему-то всегда одного размера в кане передаётся. Максимального :)
Вот код

//____________________________MULTIFRAME____________ ______________________
if(canId == 164) // 125HEX
{
if ((buf[0] >> 4) == 0x01){
LengthR = ((buf[0] & 0x0F) * 256 + buf[1]) - 6;
DataBufSizeR = 2;
MULTIFRAMER[0] = buf[6];
MULTIFRAMER[1] = buf[7];
}

if(((buf[0] >> 4) == 0x02) && LengthR > 0) multiframef();
if(((buf[0] >> 4) == 0x02) && LengthR == 0)
{
for(int i=0;i<=53;i++) Serial.print(char(MULTIFRAMER[i]));
Serial.println();
}
}

}
}

void multiframef(){
if (LengthR > 8)
{
for (int i=0; i < 7;i++) MULTIFRAMER[i + DataBufSizeR] = buf[i+1];
DataBufSizeR = DataBufSizeR + 7;
LengthR = LengthR - 7;
}
else{
for (int i=0; i < LengthR;i++) MULTIFRAMER[i + DataBufSizeR] = buf[i+1];
DataBufSizeR = DataBufSizeR + LengthR;
LengthR = 0;
}
}

Как бы всё отображается.

T_r_D
16.03.2016, 12:13
Всё народ. С первой частью задачи я справился благодаря всем вам. За что вам огромное спасибо.

На данный момент полностью повторён дисплей. Тоесть отображаем на планшете всё что на дисплее. Бортовик, всё что отображает магнитола в режиме радио\ЦД\Ченджера, настройки аудио и громкость.

Во второй части будем пытаться эмулировать дисплей. Без этого невозможно отобразить меню(3 разных для каждого режима работы) по кнопке ОК и меню по кнопке MENU.
Делать меню по кнопке ОК я не буду так как не удобно, а вот по кнопке MENU сделать нужно.

Но для начала надо понять главное- не в дисплее ли случаем считается бортовик?
Если нет, то перед тем как разбираться с меню надо разобраться с загвоздкой со сбросом трипа. Он сбрасывается только тогда, когда находится в отображении трипа. Надо понять кто в этом замешен и если кто идентифицирует в каком мы сейчас режиме отображения.

dmit
17.03.2016, 17:52
Заказал Ардуино и Шилд . Тоже хочу помучаться в этом плане. Идея такая на первых порах ловить сообщения, которые рисуют надписи на штатном мониторе. И посылать сообщения для того, чтобы написать свои сообщения на штатном мониторе ! Конкретно для чего пока не знаю, но мысли есть ! Возможно ли такая процедура на Ардуино ? Авто Ниссан Теана2 . Направьте в нужное русло с чего начинать ? Может ЕЛМ327 пока протокол пощупать ? Какой принцип прорисовки экрана в протоколе, текст допустим ascii сообщениями (если я не ошибаюсь), а прорисовка других элементов ?

T_r_D
18.03.2016, 03:39
Для начала нужно узнать какая шина в тиане на которой висит дисплей.
Потом уже разбираться с протоколом.

Ардуине с CAN платой вполне справляется с задачами обработки, приёма и передачи данных из шины.

Возможно или нет на дисплее что-то писать своё станет понятно после разбора протокола.
И сообщения в CAN ходят не обязательно в ASCII, тем более что в нём нет русских буковок, а в тиане они скорее всего есть.

Ловить сообщения можно, но они для дисплея идут явно не символами. Скорее стандартные меню дисплея прошиты в нём, а идут только указатели на то, что надо отображать.

dmit
18.03.2016, 12:25
Для начала нужно узнать какая шина в тиане на которой висит дисплей.
Потом уже разбираться с протоколом.

Если к монитору подключиться по CAN сможет Ардуино распознать протокол и скорость ? или эти данные явно нужно знать, чтобы снюхать Ардуино с шиной на дисплее ?

Ардуине с CAN платой вполне справляется с задачами обработки, приёма и передачи данных из шины.

Возможно или нет на дисплее что-то писать своё станет понятно после разбора протокола.
И сообщения в CAN ходят не обязательно в ASCII, тем более что в нём нет русских буковок, а в тиане они скорее всего есть. В Теане 2 в моей по крайней мере нет русских букв !

Ловить сообщения можно, но они для дисплея идут явно не символами. Скорее стандартные меню дисплея прошиты в нём, а идут только указатели на то, что надо отображать.
т.е если выловить данные управляющие стандартными меню дисплея в шине, то этими меню можно управлять для своих сообщений !

dmit
18.03.2016, 12:36
Если к монитору подключиться по CAN сможет Ардуино распознать протокол и скорость ? или эти данные явно нужно знать, чтобы снюхать Ардуино с шиной на дисплее ?

т.е если выловить данные управляющие стандартными меню дисплея в шине, то этими меню можно управлять для своих сообщений !

T_r_D
18.03.2016, 14:28
dmit
Нету понятия монитор, дисплей, магнитола и так далее. Есть понятие "шина данных".
Она бывает по крайней мере двух типов- стандартная высокоскоростная и FT-CAN.
Для стандартной на плате распаяна микруха TJA1050, для FT потребуется перепайка на TJA1054 или 1055.
Эти данные можно узнать перебором. Перебирая для каждой из категорий скорость.
Но лутчше найти данные сразу.

Там не так всё просто.
Более или менее просто "читать" данные из шины и выводить их на своё устройство.

Нельзя просто взять и вмешаться своими сообщениями в шину. Точнее в некоторых случаях можно, но в 90% сообщения цикличны. Тоесть каждые, скажем 500мс, идёт передача данных о, ну допустим, нажатой или нет кнопке.
И этот статус будет в битовом виде допустим 0, а ты будешь пихать ему 1. С кнопкой это может и прокатит, а вот с сообщениями, кроме как мерцания ни чего не выйдет.

Короче. При удачном подключении к шине нужно будет заниматься анализом пакетов. Тупо тыкать кнопки, крутить ручки и смотреть что происходит.
Это долго и уныло. Да ещё можно и чего-то не заметить.
С наскока не выйдет короче.

Посмотри дату начала этой темы и пойми сколько нужно время для раскопки примерно 50% информации в шине FT(кан комфорт).

dmit
19.03.2016, 19:25
dmit
Нету понятия монитор, дисплей, магнитола и так далее. Есть понятие "шина данных".
Она бывает по крайней мере двух типов- стандартная высокоскоростная и FT-CAN.
Для стандартной на плате распаяна микруха TJA1050, для FT потребуется перепайка на TJA1054 или 1055.
Эти данные можно узнать перебором. Перебирая для каждой из категорий скорость.
Но лутчше найти данные сразу.

Там не так всё просто.
Более или менее просто "читать" данные из шины и выводить их на своё устройство.

Нельзя просто взять и вмешаться своими сообщениями в шину. Точнее в некоторых случаях можно, но в 90% сообщения цикличны. Тоесть каждые, скажем 500мс, идёт передача данных о, ну допустим, нажатой или нет кнопке.
И этот статус будет в битовом виде допустим 0, а ты будешь пихать ему 1. С кнопкой это может и прокатит, а вот с сообщениями, кроме как мерцания ни чего не выйдет.

Короче. При удачном подключении к шине нужно будет заниматься анализом пакетов. Тупо тыкать кнопки, крутить ручки и смотреть что происходит.
Это долго и уныло. Да ещё можно и чего-то не заметить.
С наскока не выйдет короче.

Посмотри дату начала этой темы и пойми сколько нужно время для раскопки примерно 50% информации в шине FT(кан комфорт).

1.Т.е. получается сразу ориентироваться на перепайку микрухи ? скорее всего в Теане тоже FT(кан комфорт)
2. Получается кроме анализа никакой радости не принес попытка разбираться с сообщениями. Если я допустим вычислю как опустить стеклоподъемник , то послав свое сообщение , а не нажимая кнопки стекло не опуститься ? Или монитор не напишет слово и не прорисует стандартное меню ?
3. Хотел бы уточнить по Вашему проекту . Как я понял Вы просто перевели содержимое штатного монитора на свой ! Т.е. вы выловили сообщения , расшифровали их и средсвами Андроид нарисовали на экране андроида в своей современной интерпритации ! Ардуин у вас вылавливает сообщения , а далее что , кто занимается формирование новой информации на основе выловленых данных, тоже Ардуин ? Как соединен АРдуин с Андроид ? Вот здесь можно подробнее ?

T_r_D
20.03.2016, 14:11
1 Сначала пробовать.
2 Пока не увидишь что происходит и не попробуешь послать пакет ни чего не узнаешь. Протокол у всех разный.
2. У меня всё идёт при помощи разных ID и байт/бит в них, сама визуализация в дисплее вшита. Отдельно только идёт мультифрейм для вывода сообщений и RDS.
Они идут фактически в ASCII.
Ардуина ловит с платы кан сообщения и передаёт их на сериал порт, а к тому уже подключена микруха которая выдаёт это на ЮСБ(стандартный разъём на плате ардуины). Далее по юсб это подключено к планшету.
На планшете при помощи изисканий вот этого дяди написан софт
https://github.com/felHR85/UsbSerial/releases/

T_r_D
20.03.2016, 14:14
Народ, а теперь вопрос на засыпку!
Походу я загрузил дуину настолько, что она стала тупо не успевать за пакетами.

Как отфильтровать аппаратно при помощи mcp пакеты?
нашёл только это
INT8U init_Mask(const INT8U num,const INT32U ulData); /* init Masks */
INT8U init_Filt(const INT8U num,const INT8U ext,const INT32U ulData);
Что с этим делать не понятно.
Какой фильтр подсовывать и маску чего?
Мне надо пропускать около 30 ID, а всё остальное игнорировать.

Сегодня выяснилось что очень большие грабли с приёмом одиночных сообщений.
Коими является мультифрейм.
Дома всё ок, всё принимается нормально, менюшки выскакивают, очень редко бывают пустыми, но это фигня.
В машине меню показывает с 10 нажатия, часто не закрывает.
Единственное логическое объяснение такому поведению это то, что ардуина сравнивает все пакеты которые приходят немаленьким кодом и просто захлёбывается данными.

xmetal
20.03.2016, 19:05
Там по-моему можно только 6 аппаратных фильтров настроить. Нужно либо оптимизировать проверки, либо переносить всю логику в андроид. Ардуине оставить фильтр и передачу сырых данных в компорт.

T_r_D
21.03.2016, 05:56
Я как понял там две маски на Разрешить и Запретить и 6 фильтров.
Мало.
Нужно проверять 21 ID.

По пробую заменить if на switch.
Должно быть быстрее.

Ps.
Попробовал подключить к своей шине стандартный контроллер can с tja1050 и увидил странную штуку- половину id он видит, но только половину ))

xmetal
21.03.2016, 12:19
Я больше думаю на то, что где-то слишком долго идет обработка самих данных. На ардуиновский код можно посмотреть?

T_r_D
24.03.2016, 19:30
Я больше думаю на то, что где-то слишком долго идет обработка самих данных. На ардуиновский код можно посмотреть?

Дома буду- скину.
Там вообще странная штука получилась.
Походу глюк компилятора при работе с памятью.
Короче, если код мультифрейма вконце, то нужно перед сравнением массивов ставит delay(2). Имено 2- меньше не работает. Если его нет, то вывод оконечного массива в порт получается с ошибками.тоесть каша тупо пишется.
Такое происходит похоже только при интенсивной работе с массивами в памяти.
Если код мультифреймом вначале, то работает без делея.
Вообще понять не могу в чём дело.

Если заменить if на switch, то задержки даже в 20 мало- каша пишется.
Может совместно разобраться выйдет...

T_r_D
24.03.2016, 23:18
вот код- сильно не пинать, потом окультурю

#include <SPI.h>
#include "mcp_can.h"
MCP_CAN CAN(10);
unsigned char len = 0;
unsigned char buf[8];
INT32U canId = 0x000;
unsigned long time0 = -120;

//RDS
int digit1, digit2;

uint8_t DATA[162] = {};
uint8_t DATA2[162] = {};
boolean Flag = false;
boolean Flag2 = false;
int Count = 0;
int Count2 = 0;
int FMS = 0;
int VolCount = 5;
int arrcmp;

//Multiframe
int LengthP;
int DataBufSize;
int Scroll = 0;
uint8_t MULTIFRAMEFTMP[3] = {};
uint8_t MULTIFRAMETMP[54] = {};
uint8_t MULTIFRAME[55] = {};
//Multiframe RDTxT
//Package length: 64
int LengthR;
int DataBufSizeR;

void setup()
{
DATA[14] = 0x20;
Serial.begin(115200);
pinMode(9, INPUT);
CAN.begin(CAN_125KBPS,MCP_8MHz);
}

unsigned long time2 = 0;
unsigned char stmp[8] = {14, 0, 0, 15, 1, 0, 0, 160};

void loop()
{
// if ((millis() - time2) > 100){
// CAN.sendMsgBuf(0x036, 0, 8, stmp); //Это пакет зажигания.
// time2 = millis();}

if(!digitalRead(9))
{
CAN.readMsgBuf(&len, buf);
canId = CAN.getCanId();

if(canId == 0x125) {
if (buf[0] == 1) {
bitWrite(DATA[30],5,0);bitWrite(DATA[30],6,0);bitWrite(DATA[30],7,0);
memset(MULTIFRAMEFTMP, 0, sizeof(MULTIFRAMEFTMP));
memset(MULTIFRAMETMP, 0, sizeof(MULTIFRAMETMP));
memset(MULTIFRAME, 0, sizeof(MULTIFRAME));
for (int i=0; i<55; i++) DATA[i+41] = 0x00;
}
else {
if (buf[0] == 4) DATA[39] = buf[4];
if (buf[1] == 112 && buf[0] == 6){
bitWrite(DATA[30],7,1);
bitWrite(DATA[30],5,0);
bitWrite(DATA[30],6,0);
if (buf[4]!=16 && buf[4]!=19 &&
buf[4]!=64 && buf[4]!=65 &&
buf[4]!=66 && buf[4]!=67) DATA[39] = buf[4];
else {
if (buf[4] == 16 || buf[4] == 64) DATA[39] = 0x00;
if (buf[4] == 65) DATA[39] = 0x01;
if (buf[4] == 66) DATA[39] = 0x02;
if (buf[4] == 19 || buf[4] == 67) DATA[39] = 0x03;
}
if (buf[4] == 16) Scroll = 1;
if (buf[4] == 19) Scroll = 2;
if (buf[4] != 16 && buf[5] != 19) Scroll = 0;
DATA[40] = buf[3] + 0x01;
}

if ((buf[0] >> 4) == 0x01){
LengthP = ((buf[0] & 0x0F) * 256 + buf[1]) - 6;
DataBufSize = 0;
MULTIFRAMEFTMP[0] = buf[6];
MULTIFRAMEFTMP[1] = buf[7];
if (buf[1] == 13 || buf[1] == 22 || buf[1] == 31 || buf[1] == 40){
FMS = 1;
if (buf[5] == 64 || buf[5] == 16) DATA[39] = 0x00;
if (buf[5] == 65 || buf[5] == 33) DATA[39] = 0x01;
if (buf[5] == 66 || buf[5] == 50) DATA[39] = 0x02;
if (buf[5] == 67 || buf[5] == 19) DATA[39] = 0x03;
if (buf[5] == 16) Scroll = 1;
if (buf[5] == 19) Scroll = 2;
if (buf[5] != 16 && buf[5] != 19) Scroll = 0;
}
if (buf[1] == 58){
FMS = 2;
if (buf[3] == 16) DATA[39] = 0x00;
if (buf[3] == 32) DATA[39] = 0x01;
if (buf[3] == 48) DATA[39] = 0x02;
if (buf[3] == 64) DATA[39] = 0x03;
if (buf[3] == 80) DATA[39] = 0x04;
if (buf[3] == 96) DATA[39] = 0x05;
Scroll = 0;
}
}

if(((buf[0] >> 4) == 0x02) && LengthP != 0) multiframef();
if(((buf[0] >> 4) == 0x02) && LengthP == 0)
{
if (Scroll == 0){
MULTIFRAME[0] = MULTIFRAMEFTMP[0];
MULTIFRAME[1] = MULTIFRAMEFTMP[1];
for(int i=0;i<=51;i++) MULTIFRAME[i+2] = MULTIFRAMETMP[i];}

if (Scroll == 1){
for (int i = 26; i>=0; i--) MULTIFRAME[i+9] = MULTIFRAME[i];
MULTIFRAME[0] = MULTIFRAMEFTMP[0];
MULTIFRAME[1] = MULTIFRAMEFTMP[1];
for (int i = 0; i<7;i++) MULTIFRAME[i+2] = MULTIFRAMETMP[i];
}

if (Scroll == 2){
for (int i = 0; i<=26; i++) MULTIFRAME[i] = MULTIFRAME[i+9];
MULTIFRAME[27] = MULTIFRAMEFTMP[0];
MULTIFRAME[28] = MULTIFRAMEFTMP[1];
for (int i = 0; i<7;i++) MULTIFRAME[i+29] = MULTIFRAMETMP[i];
}
for (int i=0; i<54; i++) DATA[i+41] = MULTIFRAME[i];
if (FMS == 1) {bitWrite(DATA[30],5,1); bitWrite(DATA[30],6,0); bitWrite(DATA[30],7,0);}
if (FMS == 2) {bitWrite(DATA[30],6,1); bitWrite(DATA[30],5,0); bitWrite(DATA[30],7,0);}
}
}
}
if(canId == 0xA4 && bitRead(DATA[21],5) == 1)
{
if ((buf[0] >> 4) == 0x01){
LengthR = ((buf[0] & 0x0F) * 256 + buf[1]) - 6;
DataBufSizeR = 98;
DATA[96] = buf[6];
DATA[97] = buf[7];
}

if(((buf[0] >> 4) == 0x02) && LengthR > 0) multiframeRF();
if(((buf[0] >> 4) == 0x02) && LengthR == 0){
}
}
if(canId == 0xB6){
DATA[0] = buf[0];DATA[1] = buf[1];
DATA[2] = buf[2];DATA[3] = buf[3];}
if(canId == 0x221){DATA[4] = buf[1];DATA[5] = buf[2];
bitWrite(DATA[36],3,bitRead(buf[0],3));}
if(canId == 0x2A1){DATA[6] = buf[3];DATA[7] = buf[4];<< 8 | buf [4];
DATA[8] = buf[0];
DATA[9] = buf[1];DATA[10] = buf[2];}
if(canId == 0xF6) DATA[11] = buf[6];
if(canId == 0x1A1){if (bitRead(buf[2],7) == 1) DATA[12] = 0x01; else DATA[12] = 0x00;
DATA[13] = buf[1];}
if(canId == 0x1A5) //421 1A5
if (buf[0] <= 30){
DATA[14] = buf[0];
VolCount = 0;
}
else {
if (VolCount < 5) VolCount = VolCount +1;
else DATA[14] = 0x1F;
}
if(canId == 0x1E5){
if (bitRead(buf[0],7) == 1 || bitRead(buf[1],7) == 1 || bitRead(buf[2],7) == 1 || bitRead(buf[4],7) == 1 ||
bitRead(buf[5],7) == 1 || bitRead(buf[5],4) == 1 || bitRead(buf[6],6) == 1){
if (bitRead(buf[0],7) == 1){DATA[15] = 0x01; DATA[16] = (buf[0] & 0x7F);}
if (bitRead(buf[1],7) == 1){DATA[15] = 0x02; DATA[16] = (buf[1] & 0x7F);}
if (bitRead(buf[2],7) == 1){DATA[15] = 0x03; DATA[16] = (buf[2] & 0x7F);}
if (bitRead(buf[4],7) == 1){DATA[15] = 0x04; DATA[16] = (buf[4] & 0x7F);}
if (bitRead(buf[5],7) == 1){DATA[15] = 0x05; DATA[16] = bitRead(buf[5],6);}
if (bitRead(buf[5],4) == 1){DATA[15] = 0x06; DATA[16] = bitRead(buf[5],2);}
if (bitRead(buf[6],6) == 1){DATA[15] = 0x07;
if ((buf[6] & 0x1F) == 3)DATA[16] = 1;
if ((buf[6] & 0x1F) == 7)DATA[16] = 2;
if ((buf[6] & 0x1F) == 11)DATA[16] = 3;
if ((buf[6] & 0x1F) == 15)DATA[16] = 4;
if ((buf[6] & 0x1F) == 19)DATA[16] = 5;
if ((buf[6] & 0x1F) == 23)DATA[16] = 6;
}
}else DATA[15] = 0x00;
bitWrite(DATA[21],7,bitRead(buf[5],6));
}

if(canId == 0x165)
{
if (buf[0] == 192)DATA[17] = 0x01; else DATA[17] = 0x00;
if (buf[2] == 16){DATA[17] = 0x02;}
if (buf[2] == 32){DATA[17] = 0x03;}
if (buf[2] == 48){DATA[17] = 0x04;}
if (buf[2] == 64){DATA[17] = 0x05;}
if (buf[2] == 80){DATA[17] = 0x06;}
}
if(canId == 0x225 && DATA[17] == 0x02)
{
DATA[19] = buf[3];
DATA[20] = buf[4];
DATA[31] = buf[1];
bitWrite(DATA[18],0,bitRead(buf[2],4));
bitWrite(DATA[18],1,bitRead(buf[2],5));
bitWrite(DATA[18],2,bitRead(buf[2],6));
if (bitRead(buf[2],4) == 1 && bitRead(buf[2],6) == 1)bitWrite(DATA[18],3,1); else bitWrite(DATA[18],3,0);
bitWrite(DATA[18],4,bitRead(buf[0],2));
//bitWrite(DATA[18],5,bitRead(buf[0],7));

if (bitRead(buf[0],2) == 1) Flag = true;
if (bitRead(buf[0],2) == 0 && Flag == true){
Count = Count + 1;
if (Count > 2){
if (bitRead(buf[0],7) == 0) {bitWrite(DATA[18],5,1);bitWrite(DATA[18],6,0);}
if (bitRead(buf[0],7) == 1) {bitWrite(DATA[18],5,0);bitWrite(DATA[18],6,1);}
Flag = false;
Count = 0;
Flag2 = true;
Count2 = 0;
}
}
if (Flag2 == true){
Count2= Count2 + 1;
if (Count2 == 14){
bitWrite(DATA[18],5,0);
bitWrite(DATA[18],6,0);
Count2 = 0;
Flag2 = false;
}
}

}
if(canId == 0x1E0)
{
bitWrite(DATA[21],0,bitRead(buf[0],5));
bitWrite(DATA[21],1,bitRead(buf[0],2));
bitWrite(DATA[21],2,bitRead(buf[1],7));
bitWrite(DATA[21],3,bitRead(buf[2],5));
bitWrite(DATA[21],4,bitRead(buf[3],7));
bitWrite(DATA[21],5,bitRead(buf[4],5));
}
if(canId == 0x2A5 && DATA[17] == 0x02)
{
if (buf[0] != 0 && buf[1] != 0 && buf[2] != 0 && buf[3] != 0 && buf[4] != 0 && buf[5] != 0 && buf[6] != 0 && buf[7] != 0 && buf[8] != 0){
for(int i = 22; i<=29; i++) DATA[i] = buf[i-22];}
else
{DATA[22] = 0x20;DATA[23] = 0x4E;DATA[24] = 0x4F;DATA[25] = 0x20;
DATA[26] = 0x52;DATA[27] = 0x44;DATA[28] = 0x53;DATA[29] = 0x00;}
}
if(canId == 0x365 && DATA[17] == 0x03) DATA[20] = buf[0];
if(canId == 0x3A5 && DATA[17] == 0x03)
{
if (buf[3] == 255 && buf[4] == 127){
DATA[22] = 0x20;DATA[23] = 0x20;DATA[24] = 0x20;DATA[25] = 0x2D;DATA[26] = 0x2D;DATA[27] = 0x3A;DATA[28] = 0x2D;DATA[29] = 0x2D;}
else {
converter(buf[0]);
DATA[22] = digit1;
DATA[23] = digit2;
DATA[24] = 0x2D;
converter(buf[3]);
DATA[25] = digit1;
DATA[26] = digit2;
DATA[27] = 0x3A;
converter(buf[4]);
DATA[28] = digit1;
DATA[29] = digit2;
}
}
if (DATA[17] == 0x04) {
if(canId == 0x162) DATA[19] = buf[3];
if(canId == 0x1A2) DATA[20] = buf[0];
if(canId == 0x1E2)
{
if (buf[3] == 255 && buf[4] == 127){
DATA[22] = 0x20;DATA[23] = 0x20;DATA[24] = 0x20;DATA[25] = 0x2D;DATA[26] = 0x2D;DATA[27] = 0x3A;DATA[28] = 0x2D;DATA[29] = 0x2D;}
else {
converter(buf[0]);
DATA[22] = digit1;
DATA[23] = digit2;
DATA[24] = 0x2D;
converter(buf[3]);
DATA[25] = digit1;
DATA[26] = digit2;
DATA[27] = 0x3A;
converter(buf[4]);
DATA[28] = digit1;
DATA[29] = digit2;
}
}
}

if(canId == 0x265) {
bitWrite(DATA[21],6,bitRead(buf[0],4));
bitWrite(DATA[30],0,bitRead(buf[1],7));
bitWrite(DATA[30],1,bitRead(buf[1],6));
bitWrite(DATA[30],2,bitRead(buf[1],5));
bitWrite(DATA[30],3,bitRead(buf[0],5));
bitWrite(DATA[30],4,bitRead(buf[0],2));
DATA[32] = buf[2];
DATA[33] = buf[3];
}

if(canId == 0x21F)
{
bitWrite(DATA[34],0,bitRead(buf[0],7));
bitWrite(DATA[34],1,bitRead(buf[0],6));
if(bitRead(buf[0],3) == 1 && bitRead(buf[0],2) == 1) bitWrite(DATA[34],2,1); else bitWrite(DATA[34],2,0);
if(bitRead(buf[0],3) == 1 && bitRead(buf[0],2) == 0) bitWrite(DATA[34],3,1); else bitWrite(DATA[34],3,0);
if(bitRead(buf[0],2) == 1 && bitRead(buf[0],3) == 0) bitWrite(DATA[34],4,1); else bitWrite(DATA[34],4,0);
bitWrite(DATA[34],5,bitRead(buf[0],1));
DATA[37] = buf[1];
}

if(canId == 0x3E5)
{
bitWrite(DATA[34],6,(bitRead(buf[0],6)));
bitWrite(DATA[34],7,(bitRead(buf[0],4)));
bitWrite(DATA[35],0,(bitRead(buf[0],0)));
bitWrite(DATA[35],1,(bitRead(buf[1],6)));
bitWrite(DATA[35],2,(bitRead(buf[1],4)));
bitWrite(DATA[35],3,(bitRead(buf[1],0)));
bitWrite(DATA[35],4,(bitRead(buf[2],6)));
bitWrite(DATA[35],5,(bitRead(buf[2],4)));
bitWrite(DATA[35],6,(bitRead(buf[2],2)));
bitWrite(DATA[35],7,(bitRead(buf[5],6)));
bitWrite(DATA[36],0,(bitRead(buf[5],4)));
bitWrite(DATA[36],1,(bitRead(buf[5],2)));
bitWrite(DATA[36],2,(bitRead(buf[5],0)));
}
}


//delay(2); //Не знаю зачем, но без этого и со строкой выше высыпается каша!
arrcmp = memcmp(DATA,DATA2,161);
if ((millis() - time0) > 100 && arrcmp != 0){
Serial.write(DATA, 161);
memcpy(DATA2,DATA,161);
time0 = millis();}
}

void converter(int inpint){
if (inpint < 10){
digit1 = 48;
digit2 = inpint + 48;
}
else{
if (inpint > 89) {digit1 = 9 + 48; digit2 = inpint - 42;}
else if (inpint > 79) {digit1 = 8 + 48; digit2 = inpint - 32;}
else if (inpint > 69) {digit1 = 7 + 48; digit2 = inpint - 22;}
else if (inpint > 59) {digit1 = 6 + 48; digit2 = inpint - 12;}
else if (inpint > 49) {digit1 = 5 + 48; digit2 = inpint - 2;}
else if (inpint > 39) {digit1 = 4 + 48; digit2 = inpint + 8;}
else if (inpint > 29) {digit1 = 3 + 48; digit2 = inpint + 18;}
else if (inpint > 19) {digit1 = 2 + 48; digit2 = inpint + 28;}
else if (inpint > 9) {digit1 = 1 + 48; digit2 = inpint + 38;}
}
}

void multiframef(){
if (LengthP > 7)
{
for (int i=0; i < 7;i++) MULTIFRAMETMP[i + DataBufSize] = buf[i+1];
DataBufSize = DataBufSize + 7;
LengthP = LengthP - 7;
}
else{
for (int i=0; i < LengthP;i++) MULTIFRAMETMP[i + DataBufSize] = buf[i+1];
LengthP = 0;
}
}

void multiframeRF(){
if (LengthR > 7)
{
for (int i=0; i < 7;i++) DATA[i + DataBufSizeR] = buf[i+1];
DataBufSizeR = DataBufSizeR + 7;
LengthR = LengthR - 7;
}
else{
for (int i=0; i < LengthR;i++) DATA[i + DataBufSizeR] = buf[i+1];
LengthR = 0;
}
}

xmetal
25.03.2016, 15:54
Строка 134: for (int i = 0; i < 54; i++) DATA[i + 41] = MULTIFRAME[i]; правильно, что копирует 54 байта, а не 55?

Строка в конце Serial.write(DATA, 161); передает 161, а не 162 байта, правильно? Зачем объявляли 162 байта?

Проверку на изменения может сделать так?
if (!digitalRead(9))
{
CAN.readMsgBuf(&len, buf);
canId = CAN.getCanId();
.......................
.......................
arrcmp = memcmp(DATA, DATA2, 161); // перенести сюда
}

if ((millis() - time0) > 100 && arrcmp != 0){
Serial.write(DATA, 161);
memcpy(DATA2, DATA, 161);
time0 = millis();
}
Перенести memcmp выше, а то получается, что оно постоянно вызывается.
Вообще по логике получается, что данные в DATA еще полностью не заполнились, а уже идет сравнение с DATA2 и если оно несовпадает, то идет отправка на планшет.
Надо вводить флаг, который будет разрешать/запрещать сравнение DATA с DATA2.

(millis() - time0) > 100 - некая задержка чтобы DATA успел заполнится, не совсем понял?

T_r_D
25.03.2016, 19:37
По порядку.
Да- 54 байта это правильно. Максимальная длина этого мультифрейм 9*6=54

162 объявлено с запасом. Тут тоже всё корректно.

С сравнением массивов согласен. Нужно убрать в if который возникает при приходе пакета и желательно только мне нужного. Над этим подумаю- спасибо. Можно уменьшить количество проверяемый информации, но тогда увеличится код. В каждом if пришедшего пакета проверять изменения для конкретного id. Тоесть сравнивать только те байты, которые он может изменять.

Про флаг подробнее можно?

Про задержку в 100мс. Сделана чтоб не грузить особо COM и планшет. Быстрее чем 10 раз в секунду мне данные не нужны.

T_r_D
25.03.2016, 22:49
Вот что имел в виду:

void CompareOut(){
arrcmp = memcmp(DATA,DATA2,161);
}

И вызывать это если ID совпал. Тоесть например:

if(canId == 0x1E0)
{
bitWrite(DATA[21],0,bitRead(buf[0],5));
bitWrite(DATA[21],1,bitRead(buf[0],2));
bitWrite(DATA[21],2,bitRead(buf[1],7));
bitWrite(DATA[21],3,bitRead(buf[2],5));
bitWrite(DATA[21],4,bitRead(buf[3],7));
bitWrite(DATA[21],5,bitRead(buf[4],5));
CompareOut();
}


Так должна ещё скорость увеличится.

А если узнать как сравнивать кусок массива, а не весь, то будет ещё быстрее.
Ну скажем байты с 10 по 15. И передавать эти значения в функцию CompareOut(15,20);

xmetal
26.03.2016, 12:29
Данные которые складываются в массив DATA приходят же не за одно сообщение, так вот в момент когда приходит первое сообщение нужно запретить сравнение массивов. Когда приходит последнее сообщение и массив DATA завершает свое формирование, сравнение можно разрешить. Для этого нужен флаг запрет/разрешение.
А если узнать как сравнивать кусок массива, а не весь, то будет ещё быстрее.
Ну скажем байты с 10 по 15. И передавать эти значения в функцию CompareOut(15,20);Можно самому написать сравнение, тапример так:
byte compare(byte *data1, byte *data2, byte first, byte last) {
for (byte i = first; i < last+1; i++) {
if (data1[i] != data2[i]) {
return 1; // если не равны, возвращаем 1
}
}
return 0; // если равны, возвращаем 0
}

data1, data2 - массивы, first и last начальный и конечный индексы массивов для сравнения (начиная с 0).

T_r_D
26.03.2016, 14:20
Данные которые складываются в массив DATA приходят же не за одно сообщение, так вот в момент когда приходит первое сообщение нужно запретить сравнение массивов. Когда приходит последнее сообщение и массив DATA завершает свое формирование, сравнение можно разрешить. Для этого нужен флаг запрет/разрешение.


А вот нету конечного сообщения. Это всё в динамике отображается. Тоесть нужно отображать любое изменение массива за период 100мс


А самописное сравнение с for будет ли быстрее memcmp?

xmetal
26.03.2016, 14:43
А самописное сравнение с for будет ли быстрее memcmp? ХЗ, а почему бы ему тормозить? ))


А вот нету конечного сообщения. Это всё в динамике отображается. Тоесть нужно отображать любое изменение массива за период 100мс Экран же понимает, когда можно начинать выводить. Я не очень представляю как выглядят данные с которыми ты работаешь, поэтому мне сложно что-то конкретное советовать.

Подкорректировал тот пример, чтобы когда неравны возвращало 1. Возвращать индекс первого несовпадения в общем-то никчему, но непонятка могла возникнуть когда нулевой элемент массивов не совпадал.

T_r_D
27.03.2016, 02:49
xmetal
Спасибо за пример сравнения.

По поводу данных.
Ведройд не сохраняет в себе ни каких значений, он тупо считает и выводит то, что на него приходит.

Ардуина кладёт в массив данные с интересующих меня ID, данные по шине идут естественно один пакет за раз, а мне иногда нужны данные из разных пакетов, так что дуина их складывает в массив, а потом все изменения выкидывает в порт.
Тоесть выдаёт всё за раз.

Вот что в итоге сотворил.
При каждом приходе интересующего меня ID данные складываются в массив и пишется флаг Compare = true;
Ну а дальше проверяется в основном цикле вышли ли 100мс и состояние флага.
И если вышли и флаг true, то сравниваются массивы и если не равны, то выдаём данные в порт и записываем данные из массива 1 в массив 2 (тоесть с тем, с которым в дальнейшем будем сравнивать).

if ((millis() - time0) > 100 && Compare){
arrcmp = memcmp(DATA,DATA2,161);
if (arrcmp != 0)
{
Serial.write(DATA, 161); //41 + 54 +64
memcpy(DATA2,DATA,161); //Присваиваем массиву DATA2 160 байт массива DATA
}
time0 = millis();
Compare = false;
}


Так по идеи должно работать ещё быстрее

devova
28.03.2016, 09:36
Здравствуйте уми мира этого.
Вот начал читать ваш топик і понял што ето то што мне нужно. В обшех чертах у меня идея очень похожея, заменить монохромний дисплей на 7inch андроид, но рендерить на КОDI(XBMC). Почему сделать интерфейс для KODI? потому што я python developer и мне попросту проще так.
Итак мне уже идут CAN шилд на MCP2515 и MAX3053ЕСА и у меня Ситроен с-elysee с штатной RD45 магнитолой. Читал про небходимость утилити снифить і рендерить CAN коди (идея про 3 колонки), думал што навероє удобно подключить raspberry pi по SPI и уже там снифить и рендерить, єсли вам идея нравитса могу помочь в етом.
В общем ребята спасибо что развиваите єту тему, я хотел би присоєдинитса к вам, но сами понимаите, ратота, жена - отнимають много в ремени у меня. Но я буду старатса не отставать).
Когда мне все прийдет я залю скетч и посмотрю как ето работаєт у меня, если што задам вопроси.

P.S. я сам из Украини и руский не мой родной язик, так што простите за ошибки в написании

xmetal
28.03.2016, 17:16
Ардуина кладёт в массив данные с интересующих меня ID, данные по шине идут естественно один пакет за раз, а мне иногда нужны данные из разных пакетов, так что дуина их складывает в массив, а потом все изменения выкидывает в порт.
Тоесть выдаёт всё за раз.
Вот! Я и хочу сказать, что когда дуина начинает складывать данные из разных пакетов, нельзя разрешать сравнение массивов. Разрешать нужно только когда в массив положился последний кусок данных. Возможно в тестах на столе все данные успевали собраться за 100 мс, так как нету другого трафика в кан шине. А в реальных условиях какое-то сообщение притормозилось, таймер вышел, данные пошли в планшет и получили кашу.

T_r_D
29.03.2016, 01:45
xmetal Стоп- стоп!
У нас есть цикл, в нём есть определение приёма пакета и если приняли, то куча ифов.
На данный момент заменено на switch.
Задетектили приём пакета, пошли вниз по коду, если есть, то изменили что-то в массиве, если нет, то просто сделали пробежку сверху вниз, сравнили массивы и побежали на следующий круг.
В этом цикле как бы не может быть много пакетов.
Если приняли нужный нам пакет, то сравнив у нас естественно массивы не совпали и мы выдали весь пакет целиком в порт, не важно что записали всего один бит, передали всё равно 161 байт. Ну и в буферный масив перекинули данные основного массива чтоб потом сравнивать дальше.

Так что складывание данных только из одного пакета за цикл и сравнение тоже.

Сейчас оптимизировал это свитчем и сделал сравнение только если пришёл интересующий меня пакет. В порт лететь стало меньше. Проблема ушла с кашей.

То что не ловит переодически пакеты это уже где-то с железом косяк. Даже на минимальном скетче есть потери пакетов (просто когда пакеты в консоль выводятся). После пропайки TJA, укорочения хвоста витухи в машине стало полутчше,но всё равно теряет. Видимо вместо дисплея в разъём втыкать нужно чтоб лишних проводов и скруток не было.

На этой недели проверю.