• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

С чего начать создание спортивного секундомера (1 сенсор запускает секундомер, 2 останавливает)

pvvx

Активный участник сообщества
Начните с реализации секундомера на ESP
Прикручиваете кнопку к ESP
По нажатию кнопки первый раз запоминаете системное время
Какая задержка от фронта внешнего сигнала до считывания "системное время"?
при нажатии второй раз вычитаете из системного времени первое значение.
А тут какая задержка от фронта внешнего сигнала до считывания "системного времени"?

Результат пересылаете на комп
Как, когда и каким интерфейсом переслать?
Сто пятьсот финишировавших устройств одновременно подключатся к одной AP и скопом передадут по UDP? :)
рассуждение о мгновенной стабильности частоты кварца не является ответом на конкретный вопрос о погрешности измерения интервала в 1000 секунд.
Стабильность кварца на стационарной AP гораздо больше, чем "системное время" от стекляшки у ESP. Минимум на десятичный порядок и перепаивать в самом модуле WiFi ничего не требуется.
Вы об этом хотели сказать, но стесняетесь?
Но и главные вопросы:
1 Где в ваших предложениях единая синхронная система времени от которой можно оттолкнуться и привязаться любому устройству?
2 Куда там у вас прикручивать супер стабильный абсолютный источник времени?
3 Вам сложно загрузить Arduino и скинутые "либы" для собственной проверки?
Тогда так и пишите - помогите и обучите установке Arduino для ESP8266.
 

pvvx

Активный участник сообщества
С какой погрешностью можно измерить интервал времени в 1000 секунд на AP?
C точностью к +-50 nc если к стационарной AP на OpenWRT прикрутить PTP (IEEE 1588)
Но зачем там WiFi AP, если функция всего-то = измерение интервала?
Если кому требуется точность (джиттер) к 20 ns, то можно прикрутить многое из специализированного хлама с GPS.
А мне не нужна точность более времени прохождения радиоволны в радиусе работы WiFi 802.11n/a AP. Ну не хочу я вычислять на это расстояние поправку. Просто лень, но возможность есть, особенно при при много-антенном роутере... :p
Аналогично не хочу и лень разрабатывать новый аналог TCP и 802.11n/a из недо-кусков ESP-NOW и UDP.
Проще передавать дровам WiFi на linux дополнительную переменную со своим супер пупер timestamp для вставки в маяк (beacon), так как стандарт это уже предусмотрел на заре появления WiFi...
Напомню вам "скорость света" :) :)
 

pvvx

Активный участник сообщества
судя по продаваемому оборудованию погрешность в 0.1 0.01 секунды вполне хватает.
Дык купите это оборудование и не мешайтесь сдеся :p
Так зачем что-то городить если такую погрешность можно достигнуть за 2-5 долларов на ардуине без особых заморочек
А мы хотим что-то новое и лучшее, и уже имеем точность измерения периода в +-1.7 см от скорости распространения звука на 100 рублевом модуле c одним вызовом готовой функции в прерывании по пину. :p
 

pvvx

Активный участник сообщества
Бедные спортсмены - тот кто дальше от стартового пистолета, тот гарантированно проиграет... :) :)
Импульс старта к нему придет с громадной задержкой во много-много единиц нашего счетчика !!!
 

pvvx

Активный участник сообщества
Вчера я презагрузил роутер – “был старт спортсменов ESP8266 с TSF”.
Вписал в пример на Arduino SSID и пароль сети, нажал капу upload_2019-5-20_16-17-3.png и ...
В порт 12345 TCP от “бегущей” ESP8266 приходят посылки, что она в пути уже 67482553918 мкс:

Receive from 192.168.1.225 : 50404: 67352451289
Receive from 192.168.1.225 : 52285: 67365463277
Receive from 192.168.1.225 : 55954: 67378471779
Receive from 192.168.1.225 : 50157: 67391490348
Receive from 192.168.1.225 : 57272: 67404497941
Receive from 192.168.1.225 : 50414: 67417508051
Receive from 192.168.1.225 : 49701: 67430518140
Receive from 192.168.1.225 : 62911: 67443526721
Receive from 192.168.1.225 : 52881: 67456536491
Receive from 192.168.1.225 : 50605: 67469546451
Receive from 192.168.1.225 : 50022: 67482553918


Роутер говорит, что спортсмены в пути уже 18ч 44м:

upload_2019-5-20_16-15-17.png

А где обещанное nicolz отклонение?
 

pvvx

Активный участник сообщества
Извиняюсь что на тут, где я ныне, нет генератора со стабильностью в 6 дес.знаков… но есть USB осел и старенький AG4151 DDS генератор. У него в спеках для Square: Jitter (rms) 300ps + 100ppm of period (typical). Будем считать что 5 дес.знаков.
Ставим на нем меандр 100 mHz (10 сек) и на пин 13 ESP12E Devkit со скетчем:
Код:
#include <ESP8266WiFi.h>
#include <WiFiTSF.h>
#include <inttypes.h>

#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK  "your-password"
#endif

const char* ssid     = STASSID;
const char* password = STAPSK;

const char* host = "192.168.1.6";
const uint16_t port = 12345;

const byte interruptPin = 13;
int numberOfInterrupts = 0;

volatile byte writecount = 0;
byte readcount = 0;
#define MAX_COUNT_TSF 32
uint64_t pin_tsf[MAX_COUNT_TSF];

void ICACHE_RAM_ATTR handleInterrupt() {
  if (++writecount >= MAX_COUNT_TSF) writecount = 0;
  pin_tsf[writecount] = get_tsf_station();
}

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

  // We start by connecting to a WiFi network

  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  /* Explicitly set the ESP8266 to be a WiFi-client, otherwise, it by default,
     would try to act as both a client and an access-point and could cause
     network-issues with your other WiFi-devices on your WiFi-network. */
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), handleInterrupt, FALLING);
}

char buf[128];

void loop() {
  if ( writecount != readcount ) {
    // Use WiFiClient class to create TCP connections
    WiFiClient client;
    if (!client.connect(host, port)) {
      Serial.println("connection failed");
      delay(1000);
      return;
    }
    // This will send a string to the server
    if (client.connected()) {
      while ( writecount != readcount ) {
        uint64_t old_tsf = pin_tsf[readcount];
        if (++readcount >= MAX_COUNT_TSF) readcount = 0;
        uint64_t new_tsf = pin_tsf[readcount];
        sprintf(buf, "%" PRId64 ";%" PRId64, new_tsf, new_tsf - old_tsf);
        client.println(buf);
        Serial.println(buf);
      }
    }
    // Close the connection
    client.stop();
  }
  delay(555); // execute once every 555 ms, don't flood remote service
}
Уходим гулять… Приходим и на ноуте получаем:

Connecting to xxxxx
.......
WiFi connected
IP address:
192.168.1.225
// первый импульс от страта
74288313045;74288313045
// время срабатывания TSF AP в us; период в us
74298312561;9999516
74308312833;10000272
74318312814;9999981
74328312752;9999938
74338312347;9999595
74348312604;10000257
74358312554;9999950
74368312450;9999896
… и далее
Копируем в tsf.csv и травим на него Exel для наглядности:
upload_2019-5-20_18-49-1.png
Видим, что необходимая точность в 5-ть дес. знаков полностью достигнута несмотря на примитивность алго и дикие лаги-джиттеры в Arduino.

Попробуем уточнить расхождение времени на 1000 сек замере. Для этого возьмем разницу меток TSF через 100.
upload_2019-5-20_18-50-34.png
Видим, что различие частоты генератора от частоты AP находится в 7-м дес. знаке... На 1000 сек менее +- 0.5 ms.
Т.е., если мы введем поправку (0.9999935) в генератор или к TSF в AP, то получим стабильность при измерении периодов в 1000 сек при некой известной температуре к 1 ppm :p
(безусловно нужен более точный источник для калибровки)
И это без каких-либо фильтров, ФАПЧ, и прочих доп. протоколов и алгоритмов!
@nicolz полностью в попе :p
 

pvvx

Активный участник сообщества
Пока был занят другими делами накопилось ещё замерчиков…
Теперь для лучшего понимания происходящих процессов приведем всё к единому знаменателю. Т.е. поглядим возникающие дисперсии, джиттер и лаги в Arduino:
upload_2019-5-20_20-8-21.png
Т.е. при использовании Arduino имеем лаги и джиттеры для любого замера в +- 400 мкс, а при чистом СИ и правленых либах SDK + минимальная коррекция, выходим к показателю +-5 us. Привет Arduino-писателям :p
 

Сергей_Ф

Moderator
Команда форума
@pvvx да ладно вам. Для региональных соревнований точность 800 мкс для скалолазанья - выше крыши, имхо. Даже для лёгкой атлетики сойдёт. :)
Отличная работа, Виктор!
 

pvvx

Активный участник сообщества
если AP будет реализован на одном из ESP то ошибки измерения времени составят мс а не мкс.
Попробуем это узнать.
Сравним метод измерения TSF и через функцию millis().
В процедуру прерывания по спаду импульса добавим получение времени функций millis().
Код:
#include <ESP8266WiFi.h>
#include <WiFiTSF.h>
#include <inttypes.h>

#ifndef STASSID
#define STASSID "your-ssid"
#define STAPSK  "your-password"
#endif

const char* ssid     = STASSID;
const char* password = STAPSK;

const char* host = "192.168.1.6";
const uint16_t port = 12345;

const byte interruptPin = 13;
int numberOfInterrupts = 0;

volatile byte writecount = 0;
byte readcount = 0;
#define MAX_COUNT_TSF 64
uint64_t pin_tsf[MAX_COUNT_TSF];
uint32_t pin_ms[MAX_COUNT_TSF];

void ICACHE_RAM_ATTR handleInterrupt() {
  if (++writecount >= MAX_COUNT_TSF) writecount = 0;
  pin_tsf[writecount] = get_tsf_station();
  pin_ms[writecount] = millis();
}

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

  // We start by connecting to a WiFi network

  Serial.println();
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  /* Explicitly set the ESP8266 to be a WiFi-client, otherwise, it by default,
     would try to act as both a client and an access-point and could cause
     network-issues with your other WiFi-devices on your WiFi-network. */
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), handleInterrupt, FALLING);
}

char buf[128];

void loop() {
  if ( writecount != readcount ) {
    // Use WiFiClient class to create TCP connections
    WiFiClient client;
    if (!client.connect(host, port)) {
      Serial.println("connection failed");
      delay(1000);
      return;
    }
    // This will send a string to the server
    if (client.connected()) {
      while ( writecount != readcount ) {
        uint64_t old_tsf = pin_tsf[readcount];
        uint32_t old_ms = pin_ms[readcount];
        if (++readcount >= MAX_COUNT_TSF) readcount = 0;
        uint64_t new_tsf = pin_tsf[readcount];
        uint32_t new_ms = pin_ms[readcount];
        sprintf(buf, "%" PRIu64 ";%" PRIu64 ";%" PRIu32 ";%" PRIu32, new_tsf, new_tsf - old_tsf, new_ms, new_ms - old_ms);
        client.println(buf);
        Serial.println(buf);
      }
    }
    // Close the connection
    client.stop();
  }
  delay(555); // execute once every 555 ms, don't flood remote service
}

* Счетчик синхронизации с TSF и таймера millis() тактируются от единого стекла-кварца ESP8266.
* Счетчик синхронизации TSF на ESP8266 обновляется каждые 0.1 сек от AP. Т.е. уход стекла ESP8266 подправляется каждые 0.1 сек на значение счета таймера в AP, а он тактируется своим кварцем.
* На ногу пигна 13 идет меандр в 10 сек с дешевого и старого DDS генератора AG4151.
* Обстановка в сети роутера ужасна. К его WiFi 2.4 и 5 ГГц подключено к десятку устройств + десяток 1 ГБ сетевых, включая телевизор у детей...

В итоге имеем 3 таймера, каждый из них тактируется от своего кварца.
Получаем лог:
Connecting to xxxx
........
WiFi connected
IP address:
192.168.1.225
// TSF время старта; ; millis() время старта;
85085610010;85085610010;10078;10078
// TSF время события; период в us; millis() время события; период в ms
85095609950;9999940;20078;10000
85105609870;9999920;30078;10000
85115609453;9999583;40078;10000
85125609764;10000311;50078;10000
85135609331;9999567;60078;10000
85145609342;10000011;70078;10000
85155609568;10000226;80078;10000
85165609493;9999925;90079;10001
85175609062;9999569;100079;10000
85185609382;10000320;110079;10000
85195609299;9999917;120079;10000
…. и далее
за время накопления два раза ESP8266 не смогла создать коннект с компом...

В итоге имеем 500 замеров 10 сек меандра на GPIO:
upload_2019-5-20_23-19-6.png

Т.к. пока нет точного абсолютного таймера, тогда, если принять что генератор имеет уход равный среднему значению TSF и millis(), то расхождение таймера miilis() и кварца AP за период в 5000 сек составит:
upload_2019-5-20_23-19-21.png
Но это если взять среднее... AP наверняка более точная.
И итог: работа с TSF имеет большую точность и полностью заменяет локальный millis(), и самое главное имеет полную синхронизацию на всех станциях.
 

pvvx

Активный участник сообщества
Для региональных соревнований точность 800 мкс для скалолазанья - выше крыши, имхо. Даже для лёгкой атлетики сойдёт. :)
Если требуется измерять больший период чем 100000 сек с 1 ppm, то на любом роутере с OpenWRT стоит "ntpd — он корректирует время постоянно и «плавно» (без резких рывков, «размазывая» замедление/ускорение времени)". Коррекция хода внутреннего счетчика осуществляется прибавкой до нескольких nc через определенный вычисляемый период или ещё сложнее - в Linux этим управляет громадная структура с толпой данных... Этот счетчик и участвует в формировании TSF (как показали исходники). Т.е. если роутер имеет доступ к NTP серверам, то делать ничего не надо, в отличии от предложений nicolz.
 

pvvx

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

nikolz

Well-known member
pvvx,
В целом я доволен Вашими результатами.
Вы хорошо справились с поставленной задачей и провели удовлетворительные исследования данного вопроса.
и результат уже более правдоподобен - перешли от единиц мкс к единицам ms и получили правдоподобный результат.
================
Однако, Вы спорите сам с собой, хотя и постоянно обращаясь к кому-то третьему, называете всуе мой ник.
----------------
Если внимательно посмотрите на постановку мною данной задачи,
то я рассматривал соревнование в чистом поле или в горах, где нет инфраструктуры Wi-fi,
так как автор изначально не уточнял условия проведения соревнований,
В эксперименте я тоже рассматривал работу исключительно ESP без роутеров и уж тем более без переделанных OpenWRT.
----------------------
Причем я изначально сказал, что есть два варианта.
Один - это ваш - на основе имеющейся инфраструктуры WiFi,реализация которого требует активации Вашей деятельности.
второй -это мой - на основе лишь двух либо трех ESP, реализация которого может быть исполнена любым любителем.
-----------------
Вариант с браслетом - вообще не требует никакой синхронизации.
Он применяется при марафоне с забегом сотен и тысяч участников.
 

Сергей_Ф

Moderator
Команда форума
@nikolz а что в вашем предложении будет источником опорного сигнала времени? Одна из esp? О какой точности можно говорить в этом случае?
 

nikolz

Well-known member
@nikolz а что в вашем предложении будет источником опорного сигнала времени? Одна из esp? О какой точности можно говорить в этом случае?
уточню терминологию.
говорим о погрешности.
Вроде бы все написал, посмотрите там где картинка, там где я говорю о параметрах существующих систем (причем это не поделки а профессиональные системы, но в них нет заявления о точности измерения времени с погрешностью в мкс)
 

Сергей_Ф

Moderator
Команда форума
@nikolz Николай, согласитесь, что вариант предложенный Виктором позволяет оперировать точностью относительно опорного времени из интернета. Таким образом результат соревнований будет однозначно кореллироваться с результатами других соревнований, где бы они не проходили.
Ваш вариант привязан к локальному генератору мастер-esp. Какая у него точность мы не знаем и даже не знаем как она будет плавать при разной температуре. Профессиональные варианты, которые вы нашли в интернете, наверняка имеют сертификаты для использования в международных соревнованиях. Потому там и такая стоимость. Это должно как то описываться.
Ваш вариант, даже в случае проведения соревнований при разной температуре с одним набором esp, даст результаты с непредсказуемой погрешностью. Что уж говорить про разные наборы esp.
Не согласны?
 

nikolz

Well-known member
@nikolz Николай, согласитесь, что вариант предложенный Виктором позволяет оперировать точностью относительно опорного времени из интернета. Таким образом результат соревнований будет однозначно кореллироваться с результатами других соревнований, где бы они не проходили.
Ваш вариант привязан к локальному генератору мастер-esp. Какая у него точность мы не знаем и даже не знаем как она будет плавать при разной температуре. Профессиональные варианты, которые вы нашли в интернете, наверняка имеют сертификаты для использования в международных соревнованиях. Потому там и такая стоимость. Это должно как то описываться.
Ваш вариант, даже в случае проведения соревнований при разной температуре с одним набором esp, даст результаты с непредсказуемой погрешностью. Что уж говорить про разные наборы esp.
Не согласны?
Почему Вы полагаете, что я против варианта Виктора?
Мне нравится , что делает Виктор , что нельзя сказать о том, что он говорит.
На форуме он единственный, кто сделал действительно много и выложил свои решения. Это факт.
=============================
Полагаю, что я достаточно четко написал выше о разнице в его и моем решении задачи данной темы.
Повторю ...надцатый раз.
-------------------
Начну от печки.
Задача состоит в том, чтобы измерить отрезки времени с привязкой к единой шкале (общему началу координат)
Решить задачу можно разными способами
--------------------------
первый состоит в том, что используется эталонный стабильный источник времени и его показания передаются в точки измерения
Эти показания и используются как метки времени для замера интервала.
Вариант маяка WiFi, который благодаря патчу от Виктора доступен в ESP8266,
основан на передачи меток времени с шагом 100 мс
а интервал 100 мс квантуется локальным генератором.
В результате мы получаем время с шагом 100 мс с погрешностью эталона и более мелкий шаг с погрешностью таймера ESP8266.
--------------------
Очевидно, что если используем базовую станцию WiFi, то привязка будет к точности ее часов.
В интернете есть эталонные маяки - сервера времени. Можно привязываться к ним.
--------------------
Но такой метод можно реализовать на любом протоколе.
Например на BLE есть специальный режим маяка, в котором можно передавать эталонное время с любым шагом,
например те же 100 мс или 10 мс.
========================
Таким образом, если есть инфраструктура WiFi и доступ к счетчику TSF то метод реализуем.
Но не для всех чипов есть Виктор и следовательно доступ к счетчику TSF
----------------------------------------
Еще раз подчеркну, что этот метод реализуется на любом диапазоне и на любых протоколах.
==========================
Теперь перейдем к задаче измерения интервала времени в чистом поле или в горах.
-------------------------------
Когда wifi кирдык, нет базовых станций или, когда Виктор не написал, патч для TSF.
Что делать?
-------------------------------
Есть несколько вариантов (мои варианты в данной теме)
1) Создать базовый эталон времени и передавать метки времени в точки измерения
В качестве базы может быть ESP как AP Wifi или ESP-NOW.либо другой чип с BLE протоколом
-----------------
2) Не создавать специально базу, а передавать сигнал старта с одной точки на другую.
Этот вариант более универсальный и проще так как не требует привлечения Виктора и наличия инфраструктуры Wifi.
В этом варианте на один чип меньше.
----------------
3) устройства синхронизируются в начальном пункте. После этого используются автономно для измерения момента времени событий.
Это время ими передается асинхронно в точку обработки данных.
Т е в этом случае мы фактически делаем электронные часы, которые отсчитывают абсолютное время например по гринвичу и передают его в точку сбора информации
======================================
Очевидно, что Варианты без использования инфраструктуры WiFi априори менее точны,
так как в них менее точное железо,
но они существенно проще.
Вопрос какой вариант выбрать в том или ином случае решается с учетом конкретных условий и требований к точности.
=====================
Для оценки точности в своих вариантах я и сделал тест
усе.
 

pvvx

Активный участник сообщества
перешли от единиц мкс к единицам ms и получили правдоподобный результат.
Я ещё не дошел до границ в мс. Как было, так и осталось в +-5 мкс для моей сборки SDK и описанию указанному в начальной теме.
Не приписывайте методу лаги в +-400 мкс возникающие из-за писателей Arduino системы и её пользователей- это их беда, а не моя и не данного метода.
Эти лаги возникают в ней при любом методе, даже при чтении внутреннего аппаратного таймера по прерыванию :p
Причем я изначально сказал, что есть два варианта.
Где второй? Ждем измерений и демку, для возможности перепроверить... Да поленивее - ни у кого тут нет желания писать более десятка строк СИ/С++ - "вкалывают роботы" .
 

pvvx

Активный участник сообщества
Но не для всех чипов есть Виктор и следовательно доступ к счетчику TSF
Тут у вас выходит ошибочка.
Во всех нормальных модулях с SDK/DDK есть доступ к TSF. У некоторых для этого необходимо NDA, т.к. некоторые корпорации (не все!) по неясным причинам считают исходники своих драйверов WiFi "сикретными".
Этого нет исключительно у Exsperssif (походу и с NDA) и на основе имеющихся у меня данных за период с даты старта продаж ESP8266, по сей день, я могу только предполагать причины... На первое место выходит предположение о том, что у них или нет исходников или нарушены (c). Другого вроде не дано.
У многих, в базе SDK для простых смертных, существует API с функцией получения beacon фрейма и разными реализациями. У Realtek это иногда реализуется калбаком...
Для оценки точности в своих вариантах я и сделал тест
А нам можно тоже "потестить" Ваш вариант?
Или ТС и другим надо сделать и предоставить для вас Ваш вариант? o_O
 

pvvx

Активный участник сообщества
И на счет “Что там моего в TSF”:

Для реализации потребовалось:
1. Прочитать чужие статьи как делается синхронизация в 802.11
2. Поиском google в инете найти несколько “открытых” исходники дров WiFi.
3. Выбрать наиболее соответствующие исходники по имена процедур с листингом GCC от сборки SDK Espressif.
4. С помощью утилиты GCC для работы с либами разобрать файл ‘libnet80211.a’ от Espressif на объектные файлы.
5. В бинарном виде найти строку символов “cnx_update_bss_more” (в файле ‘wl_cnx_new.o’) и исправить последний символ на “_” получив “cnx_update_bss_mor_”.
6. С помощью утилит GCC собрать обратно файл либы ‘libnet80211.a’ из объектных файлов.
Что тут было “моего” и не описано ранее кем-то другим? Выберите номер п.п. :)

Причина применения патча в том, что над данной локальной процедурой не сработал “wrapping a call” с помощью опции --wrap= cnx_update_bss_more компилятору.
Вот тут и появляются главные вопросы:
А нафига так было делать программерам Espressif?
Почему незя было это 'расшарить' для свободного стандартного доступа средствами GCC, если сами не могут в течении многих лет предоставить запрашиваемый многими пользователями функционал API? Ничего сИкретного, хулиганского или хакерского от наличия такой функции в API сделать невозможно.
Причины явно в другом :p
 
Сверху Снизу