Это продолжение статьи, в которой рассмотрен USB HID термометр USB термометр на ATmega8
Компьютерная программа была доработана и теперь, показания термометра можно узнать, находясь в любой точке земного шара, с помощью любого браузера.
Вот код программы
; Для компиляции программы, нужна библиотека HID_Lib http://pure-basic.narod.ru/libs.html#HID_Lib
#USB_PID=$EF04
#USB_VID=$AAAA
#NO_Device="Нет связи с термометром"
LoadFont(2,"Arial",22,#PB_Font_Bold)
CurrentThermo.f=0
#ProgName="Web-сервер - USB градусник"
Port=80 ; На этом порту будет работать сервер
*Buffer = AllocateMemory(10000)
If InitNetwork() = 0
MessageRequester(#ProgName, "Ошибка инициализации сетевой библиотеки!", #MB_OK|#MB_ICONERROR)
End
EndIf
Procedure FindDevice_Timer() ; Периодическая (каждые 400 мс.) проверка доступности термометра
Shared DeviceHandle
Static Old_Test
Test=HID_Lib_DeviceTest(#USB_PID, #USB_VID) ; Есть ли требуемое USB HID устройство?
If Test<>Old_Test
Old_Test=Test
If Test
HID_Lib_CloseDevice(DeviceHandle)
DeviceHandle=HID_Lib_OpenDevice(#USB_PID, #USB_VID) ; Подключение к USB HID устройству
SetGadgetText(0,"Термометр подключён")
Else
HID_Lib_CloseDevice(DeviceHandle) ; Разрыв связи с USB HID устройством
DeviceHandle=0
SetGadgetText(0,#NO_Device)
SetGadgetText(1,"OFF")
SysTrayIconToolTip(1,"OFF")
EndIf
EndIf
EndProcedure
Procedure Thread(*x) ; Эта процедура работает в отдельном потоке
Shared DeviceHandle
Shared CurrentThermo.f
Dim In.a(4) ; Байтовый массив, используемый как бцфер приёма данных.
Repeat
If DeviceHandle ; Установлена ли связь с USB термометром?
In(0)=0
If HID_Lib_ReadDevice(DeviceHandle, @In(), 3) = 3 ; Чтение данных из USB термометра
Temp.w=In(2)
Temp<<8 ; Сдвиг влево на 8 позиций
Temp | In(1)
Result.f=Temp/16
CurrentThermo=Result
SetGadgetText(1,StrF(Result,1)+" °C") ; Отображение температуры в окне
SysTrayIconToolTip(1,StrF(Result,1)+" °C") ; Отображение температуры в трее
EndIf
Else
Delay(10)
EndIf
ForEver
EndProcedure
Procedure.s Generate_HTML_Code() ; Динамическая генерация HTML кода.
Shared DeviceHandle
Shared CurrentThermo.f
Protected HTML_Code.s
If DeviceHandle
StatusSensor.s="<span style="+Chr(34)+"color: RGB(51, 0, 153);"+Chr(34)+"> Подключён</span><br>"
Else
StatusSensor.s="<span style="+Chr(34)+"color: RGB(255, 0, 0);"+Chr(34)+"> Не обнаружен</span><br>"
EndIf
HTML_Code=""
HTML_Code+"<html><head><title>"+#ProgName+"</title>"
HTML_Code+"<STYLE TYPE="+Chr(34)+"text/css"+Chr(34)+"><!—BODY {background-color: black; font-family: Verdana; color: white; font-size: 9px} —> </STYLE>"
HTML_Code+"<meta http-equiv="+Chr(34)+"Content-Type"+Chr(34)+" content="+Chr(34)+"text/html; Charset=windows-1251"+Chr(34)
HTML_Code+"<META HTTP-EQUIV="+Chr(34)+"Refresh"+Chr(34)+" CONTENT="+Chr(34)+"2;URL="+Chr(34)+">"
HTML_Code+"</head><body><b>USB термометр</b>"+StatusSensor
If DeviceHandle
HTML_Code+"</br><b>Текущая температура - <span style="+Chr(34)+"font-weight: bold>; color: rgb(0, 102, 0);"+Chr(34)+">"+StrF(CurrentThermo,1)+" °C </span></b><br>"
EndIf
HTML_Code+"</body></html>"
ProcedureReturn HTML_Code
EndProcedure
Procedure Server_Event(*xx) ; Отдельный поток, в котором обрабатываются Web-сервером запросы от браузеров.
Shared *Buffer
Repeat
SEvent = NetworkServerEvent()
If SEvent
ClientID = EventClient()
Select SEvent
Case #PB_NetworkEvent_Connect ; Новый клиент подключился к серверу
Case #PB_NetworkEvent_Data ; От клинета пришли данные
OutHTML.s=Generate_HTML_Code()
Len_HTML=Len(OutHTML)
ReceiveNetworkData(ClientID, *Buffer, 10000)
SendNetworkString(ClientID, "HTTP/1.0 200 OK"+Chr($0D)+Chr($0A))
SendNetworkString(ClientID, "Server: "+#ProgName+Chr($0D)+Chr($0A))
SendNetworkString(ClientID, "Content-Length: "+Str(Len_HTML)+Chr($0D)+Chr($0A))
SendNetworkString(ClientID, "Content-Type: text/html"+Chr($0D)+Chr($0A))
SendNetworkString(ClientID, Chr($0D)+Chr($0A))
SendNetworkString(ClientID, OutHTML)
Case #PB_NetworkEvent_File ; От клиента пришел файл
Case #PB_NetworkEvent_Disconnect ; Клиент разорвал соединение с сервером
EndSelect
Else
Delay(20)
EndIf
ForEver
EndProcedure
If CreatePopupMenu(0) ; Контекстное меню для трея
MenuItem(1,"Показать окно")
MenuItem(2,"Скрыть окно")
MenuBar()
MenuItem(3,"Выход")
EndIf
If CreateNetworkServer(2, Port , #PB_Network_TCP)
; Открываем окно
OpenWindow(0,0,0,200,70,"Web Server USB t°", #PB_Window_MinimizeGadget|#PB_Window_Invisible|#PB_Window_ScreenCentered)
StickyWindow(0,1)
TextGadget(0,24,4,162,16,#NO_Device,#PB_Text_Center)
StringGadget(1,36,24,140,40,"OFF",#PB_Text_Center|#PB_String_ReadOnly)
SetGadgetFont(1,FontID(2))
SetGadgetColor(1,#PB_Gadget_FrontColor,$DF0000)
FindDevice_Timer()
;HideWindow(0,0)
AddWindowTimer(0,1,400) ; Запуск таймера
CreateThread(@Thread(),0) ; Создание отдельного потока из процедуры Thread()
CreateThread(@Server_Event(),0)
AddSysTrayIcon(1,WindowID(0),ExtractIcon_(0,ProgramFilename(),0)) ; Иконка в трее
SysTrayIconToolTip(1,"OFF")
Repeat ; Главный цикл проги Repeat - Until
Event=WaitWindowEvent() ; Идентификатор события
If Event=#PB_Event_Timer
If EventTimer()=1
FindDevice_Timer() ; Вызов процедуры по таймеру, каждые 400 мс.
EndIf
ElseIf Event=#PB_Event_SysTray ; Собтыие в трее
Select EventType()
Case #PB_EventType_RightClick ; Клик правой кнопокй мышки
DisplayPopupMenu(0,WindowID(0)) ; Отображение контекстного меню
Case #PB_EventType_LeftClick ; Клик левой кнопкой мышки
HideWindow(0,0) ; Отображение окна
SetWindowState(0,#PB_Window_Normal)
SetActiveWindow(0)
EndSelect
ElseIf Event=#PB_Event_MinimizeWindow ; Окно свернули
HideWindow(0,1) ; Скрываем главное окно
ElseIf Event=#PB_Event_Menu ; Событие в меню
Select EventMenu()
Case 1 ; Пункт "Показать окно"
HideWindow(0,0)
SetWindowState(0,#PB_Window_Normal)
SetActiveWindow(0)
Case 2 ; Пункт "Скрыть окно"
HideWindow(0,1)
Case 3 ; Пункт "Выход"
Break
EndSelect
EndIf
Until Event=#PB_Event_CloseWindow ; Прерывание главного цикла при закрытии окна
Else
MessageRequester(#ProgName, "Не удалось создать сервер на "+Str(Port)+" порту!", #MB_OK|#MB_ICONERROR)
EndIf
EndПосле запуска программы, её значок появится в трее

Если щелкнуть правой кнопкой мышки по значку и появившемся меню, выбрать пункт Показать окно

то на экране появится оно программы, в котором отобразится текущая, температура, полученная из ранее рассмотренного устройства - USB термометра

В программе организован Web-сервер, который собственно и позволяет работать с браузером.
Если программа запущена на одном компьютере с браузером, то в адресной строке браузера, следует ввести адрес http://127.0.0.1
Если же связь производится через интернет, что в адресной строке, нужно ввести IP адрес компьютера, на котором запущена рассматриваемая программа.
В браузере отобразится примерно такой текст:

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