更新初版
This commit is contained in:
1 parent
d627d67cd3
commit
ad0b261fe3
3 files changed
+517
No files matched your search
@@ -0,0 +1,392 @@
|
||||
/**************************************************************************
|
||||
Loongson 3A2000C Greatwall Mainborad Control Panel
|
||||
|
||||
Author : Wells Wang
|
||||
Version : 0.1beta
|
||||
|
||||
Release under GPL v3 License
|
||||
**************************************************************************/
|
||||
|
||||
#include <SPI.h>
|
||||
#include <Wire.h>
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Adafruit_SSD1306.h>
|
||||
#include <OneButton.h>
|
||||
|
||||
#define SCREEN_WIDTH 128 // OLED display width, in pixels
|
||||
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
|
||||
#define OLED_RESET -1
|
||||
#define SCREEN_ADDRESS 0x3C
|
||||
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
|
||||
|
||||
#define B_PREV D5
|
||||
#define B_NEXT D4
|
||||
#define B_OK D3
|
||||
#define B_PWR D6
|
||||
#define POWER D7
|
||||
OneButton btn_OK = OneButton(B_OK, true, false);
|
||||
OneButton btn_PREV = OneButton(B_PREV, true, false);
|
||||
OneButton btn_NEXT = OneButton(B_NEXT, true, false);
|
||||
OneButton btn_PWR = OneButton(B_PWR, true, false);
|
||||
|
||||
// Following is Chinese Character Matrix for Chinese UI.
|
||||
// 测(0) 试(1) 中(2) 通(3) 过(4) 失(5) 败(6)
|
||||
//#define TXT_HEIGHT 12
|
||||
//#define TXT_WIDTH 12
|
||||
//static const unsigned char PROGMEM txt[] =
|
||||
//{0x00,0x20,0xBE,0x20,0x62,0xA0,0x2A,0xA0,0x2A,0xA0,0xAA,0xA0,0x6A,0xA0,0x2A,0xA0,0x2A,0xA0,0x48,0x20,0x94,0x20,0x22,0x60,/*"测",0*/
|
||||
// 0x80,0xA0,0x40,0x80,0x0F,0xE0,0x00,0x80,0xC0,0x80,0x4E,0x80,0x44,0x80,0x44,0x80,0x44,0x80,0x46,0xA0,0x6C,0x60,0x40,0x20,/*"试",1*/
|
||||
// 0x04,0x00,0x04,0x00,0x04,0x00,0x7F,0xC0,0x44,0x40,0x44,0x40,0x44,0x40,0x7F,0xC0,0x44,0x40,0x04,0x00,0x04,0x00,0x04,0x00,/*"中",2*/
|
||||
// 0x9F,0x80,0x44,0x80,0x03,0x00,0x1F,0xC0,0xD2,0x40,0x5F,0xC0,0x52,0x40,0x5F,0xC0,0x52,0x40,0x52,0xC0,0x40,0x00,0xBF,0xE0,/*"通",3*/
|
||||
// 0x40,0x40,0x20,0x40,0x00,0x40,0x0F,0xE0,0xE0,0x40,0x24,0x40,0x22,0x40,0x22,0x40,0x20,0x40,0x21,0xC0,0x50,0x00,0x8F,0xE0,/*"过",4*/
|
||||
// 0xFB,0xFF,0xDB,0xFF,0xDB,0xFF,0xC0,0x7F,0xBB,0xFF,0x7B,0xFF,0xFB,0xFF,0x00,0x1F,0xF5,0xFF,0xEE,0xFF,0xDF,0x7F,0x3F,0x9F,/*"-失",5*/
|
||||
// 0xFE,0xFF,0x06,0xFF,0x75,0xFF,0x54,0x1F,0x53,0xBF,0x55,0xBF,0x55,0xBF,0x55,0xBF,0x55,0x7F,0xDE,0xFF,0xAD,0x7F,0x73,0x9F,/*"-败",6*/
|
||||
// 0x00,0x00,0x1F,0x80,0x3F,0xC0,0x76,0xE0,0x36,0xC0,0x7F,0xE0,0x3F,0xC0,0x79,0xE0,0x36,0xC0,0x7F,0xE0,0x3F,0xC0,0x1F,0x80,/* FAILED ICON 故障内存图标,7*/
|
||||
// 0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0x80,0x36,0xC0,0x10,0x80,0x30,0xC0,0x10,0x80,0x30,0xC0,0x10,0x80,0x30,0xC0,0x1F,0x80, /* MEMCHIP ICON 内存图标,8*/
|
||||
// 0x00,0x00,0x1F,0x80,0x3F,0xC0,0x76,0xE0,0x36,0xC0,0x7F,0xE0,0x3F,0xC0,0x76,0xE0,0x39,0xC0,0x7F,0xE0,0x3F,0xC0,0x1F,0x80};/* PASSED ICON 内存笑脸图标,9*/
|
||||
|
||||
#define USAGE_WIDTH 76 //screen_width - width_of_text_"CPU:100%"
|
||||
#define MODE_STATUS 1
|
||||
#define MODE_TEMP 2
|
||||
#define MODE_LOG 3
|
||||
|
||||
|
||||
int incomingByte = 0; // for incoming serial data
|
||||
String inputString = ""; // a String to hold incoming data
|
||||
bool stringComplete = false; // whether the string is complete
|
||||
bool update = false;
|
||||
byte mode[3] = {MODE_STATUS, MODE_TEMP, MODE_LOG};
|
||||
byte currentMode = 0;
|
||||
byte cpuUsage[USAGE_WIDTH];
|
||||
byte memUsage[USAGE_WIDTH];
|
||||
byte temperature[USAGE_WIDTH];
|
||||
String hostname = "MYHOSTNAME";
|
||||
String kernel = "0.00.0";
|
||||
String ip = "255.255.255.255";
|
||||
String displaytime = "00:00";
|
||||
String uptime = "000d00h";
|
||||
byte cu = 0;
|
||||
byte mu = 0;
|
||||
byte page = 0;
|
||||
String logItem;
|
||||
|
||||
|
||||
|
||||
//
|
||||
// UI 相关
|
||||
// =======================================================
|
||||
|
||||
/*
|
||||
void drawTxt(int x, int y, byte id) {
|
||||
unsigned char ch[24];
|
||||
for (int i=0; i<24; i++){
|
||||
ch[i] = pgm_read_word_near(txt + id*24 +i);
|
||||
// Serial.println(txt[i],BIN);
|
||||
}
|
||||
display.drawBitmap(x,y,ch, TXT_WIDTH, TXT_HEIGHT, 1);
|
||||
}
|
||||
*/
|
||||
|
||||
void drawUsageGraph(byte graphData[], int x, int y){
|
||||
int i;
|
||||
|
||||
display.fillRect(x, y, USAGE_WIDTH, 10, SSD1306_BLACK);
|
||||
for (i=0; i < USAGE_WIDTH; i++){
|
||||
display.drawLine(x + i, y+10-graphData[i], x+i, y+10, SSD1306_WHITE);
|
||||
}
|
||||
display.display();
|
||||
}
|
||||
|
||||
void drawTempGraph(byte graphData[], int x, int y){
|
||||
int i;
|
||||
byte max_v = 0;
|
||||
byte min_v = 255;
|
||||
int last_y = 0;
|
||||
int pos_y;
|
||||
|
||||
for (i=0; i < USAGE_WIDTH; i++){
|
||||
if (graphData[i] > 0) {
|
||||
max_v = max(graphData[i], max_v);
|
||||
min_v = min(graphData[i], min_v);
|
||||
}
|
||||
}
|
||||
|
||||
display.fillRect(x, y, USAGE_WIDTH, 20, SSD1306_BLACK);
|
||||
for (i=0; i < USAGE_WIDTH; i++){
|
||||
if (graphData[i]>0){
|
||||
pos_y = y + 20 - int((graphData[i] - min_v + 5) *20 / (max_v-min_v+10)); // y + 20(图像宽度) - 当前温度在最大最小值上下5度之间的相对比例位置
|
||||
if (last_y > 0) //前面有效数值,和前一点用线连接
|
||||
display.drawLine(x + i - 1, last_y, x+i, pos_y, SSD1306_WHITE);
|
||||
else //前面无有效值,画第一个点
|
||||
display.drawPixel(x + i, pos_y , SSD1306_WHITE);
|
||||
last_y = pos_y;
|
||||
}
|
||||
}
|
||||
display.display();
|
||||
}
|
||||
|
||||
void updateUI(){
|
||||
display.fillRect(0,0, display.width(), 16, SSD1306_BLACK);
|
||||
display.setTextSize(2); // Normal 1:1 pixel scale
|
||||
display.setCursor(0,0);
|
||||
display.setTextColor(SSD1306_WHITE); // Draw white text
|
||||
display.print(hostname);
|
||||
display.fillRect(0,16, display.width(), 10, SSD1306_WHITE);
|
||||
display.setTextColor(SSD1306_BLACK); // Draw white text
|
||||
display.setTextSize(1);
|
||||
display.setCursor(0,17);
|
||||
display.print(ip);
|
||||
display.setCursor(display.width()-30,17);
|
||||
display.print(displaytime);
|
||||
display.setTextColor(SSD1306_WHITE); // Draw white text
|
||||
|
||||
switch (mode[currentMode]) {
|
||||
case MODE_STATUS:
|
||||
display.fillRect(104,33, 24, 20, SSD1306_BLACK);
|
||||
display.setCursor(104,33);
|
||||
display.print(cu);display.print("%");
|
||||
display.setCursor(104,45);
|
||||
display.print(mu);display.print("%");
|
||||
display.fillRect(0,56, display.width(), 8, SSD1306_BLACK);
|
||||
display.setCursor(0,56);
|
||||
display.print(kernel);
|
||||
display.setCursor(display.width()-uptime.length()*6, 56);
|
||||
display.print(uptime);
|
||||
drawUsageGraph(cpuUsage, 0, 30);
|
||||
drawUsageGraph(memUsage, 0, 42);
|
||||
break;
|
||||
case MODE_TEMP:
|
||||
display.fillRect(86,45, 24, 16, SSD1306_BLACK);
|
||||
display.setTextSize(2);
|
||||
display.setCursor(86,45);
|
||||
display.print(temperature[USAGE_WIDTH-1]);
|
||||
drawTempGraph(temperature, 0, 42);
|
||||
break;
|
||||
case MODE_LOG:
|
||||
display.fillRect(0,30, display.width(), display.height()-30, SSD1306_BLACK);
|
||||
if (logItem.length()>0){
|
||||
display.setCursor(0,30);
|
||||
display.print(logItem);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
display.display();
|
||||
update = false;
|
||||
}
|
||||
|
||||
void drawUI(){
|
||||
display.clearDisplay();
|
||||
//display.drawLine(0, 25, display.width()-1, 25, SSD1306_WHITE);
|
||||
//drawTxt(80,20,8);
|
||||
|
||||
switch(mode[currentMode]){
|
||||
case MODE_STATUS:
|
||||
display.setTextColor(SSD1306_WHITE); // Draw white text
|
||||
display.setTextSize(1);
|
||||
display.setCursor(80,33);
|
||||
display.print(F("CPU:"));
|
||||
display.setCursor(80,45);
|
||||
display.print(F("MEM:"));
|
||||
break;
|
||||
case MODE_TEMP:
|
||||
display.setTextColor(SSD1306_WHITE);
|
||||
display.setTextSize(1);
|
||||
display.setCursor(0,33);
|
||||
display.print(F("CPU Temperature"));
|
||||
display.setTextSize(2);
|
||||
display.setCursor(116,45);
|
||||
display.print(F("C"));
|
||||
display.setTextSize(1);
|
||||
display.setCursor(112,39);
|
||||
display.print(F("o"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// 数据处理
|
||||
// =======================================================
|
||||
|
||||
void updateUsageData(byte usageData[], byte newVal){
|
||||
int i;
|
||||
for (i=0; i< USAGE_WIDTH - 1; i++){
|
||||
usageData[i] = usageData[i+1];
|
||||
}
|
||||
usageData[i] = newVal;
|
||||
}
|
||||
|
||||
byte getByteValue(String data, String cmd){
|
||||
byte temp_b[2] = {0,0};
|
||||
String temp;
|
||||
|
||||
if (data.indexOf(cmd)>0){
|
||||
temp = data.substring(data.indexOf(cmd)+4, data.indexOf(cmd)+5);
|
||||
temp.getBytes(temp_b, 2);
|
||||
}
|
||||
return temp_b[0];
|
||||
}
|
||||
|
||||
boolean updateValue(String data, String &key, String cmd){
|
||||
String temp;
|
||||
boolean res = false;
|
||||
if (data.indexOf(cmd)>0){
|
||||
temp = data.substring(data.indexOf(cmd)+4);
|
||||
temp = temp.substring(0,temp.indexOf("\n"));
|
||||
if (key != temp){
|
||||
key = temp;
|
||||
res = true;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void parseData(String data){
|
||||
|
||||
if (data){
|
||||
data = " " + data;
|
||||
updateValue(data, hostname, "!HN!");
|
||||
updateValue(data, ip, "!IP!");
|
||||
updateValue(data, kernel, "!KR!");
|
||||
updateValue(data, uptime, "!UT!");
|
||||
updateValue(data, displaytime, "!TI!");
|
||||
if (data.indexOf("!CG!")>0) updateUsageData(cpuUsage, getByteValue(data, "!CG!"));
|
||||
if (data.indexOf("!MG!")>0) updateUsageData(memUsage, getByteValue(data, "!MG!"));
|
||||
if (data.indexOf("!CT!")>0) updateUsageData(temperature, getByteValue(data, "!CT!"));
|
||||
if (data.indexOf("!CU!")>0) cu = getByteValue(data, "!CU!");
|
||||
if (data.indexOf("!MU!")>0) mu = getByteValue(data, "!MU!");
|
||||
if (data.indexOf("!LP!")>0) page = getByteValue(data, "!LP!");
|
||||
updateValue(data, logItem, "!LG!");
|
||||
|
||||
update = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
// 事件处理
|
||||
// =======================================================
|
||||
|
||||
|
||||
/*
|
||||
SerialEvent occurs whenever a new data comes in the hardware serial RX. This
|
||||
routine is run between each time loop() runs, so using delay inside loop can
|
||||
delay response. Multiple bytes of data may be available.
|
||||
*/
|
||||
void serialEvent() {
|
||||
while (Serial.available()) {
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
// get the new byte:
|
||||
char inChar = (char)Serial.read();
|
||||
// add it to the inputString:
|
||||
inputString += inChar;
|
||||
// if the incoming character is a newline, set a flag so the main loop can
|
||||
// do something about it:
|
||||
if (inChar == '\n') {
|
||||
parseData(inputString);
|
||||
inputString = "";
|
||||
}
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void clickOK() {
|
||||
currentMode = (currentMode + 1) % (sizeof(mode) / sizeof(mode[0]));
|
||||
if (mode[currentMode] == MODE_LOG){
|
||||
Serial.write("#GL#");
|
||||
Serial.write(page);
|
||||
Serial.write("\n");
|
||||
}
|
||||
drawUI();
|
||||
updateUI();
|
||||
}
|
||||
|
||||
static void clickPREV() {
|
||||
if (mode[currentMode] == MODE_LOG){
|
||||
if (page > 0) page = page - 1;
|
||||
Serial.write("#GL#");
|
||||
Serial.write(page);
|
||||
Serial.write("\n");
|
||||
delay(100);
|
||||
updateUI();
|
||||
}
|
||||
}
|
||||
|
||||
static void clickNEXT() {
|
||||
if (mode[currentMode] == MODE_LOG){
|
||||
if (page <255) page = page + 1;
|
||||
Serial.write("#GL#");
|
||||
Serial.write(page);
|
||||
Serial.write("\n");
|
||||
delay(100);
|
||||
updateUI();
|
||||
}
|
||||
}
|
||||
|
||||
static void clickPWR() {
|
||||
digitalWrite(POWER, LOW);
|
||||
digitalWrite(POWER, HIGH);
|
||||
delay(5000);
|
||||
digitalWrite(POWER, LOW);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// 初始化
|
||||
// =======================================================
|
||||
|
||||
void setup() {
|
||||
|
||||
int i;
|
||||
|
||||
pinMode(LED_BUILTIN, OUTPUT); // Initialize the LED_BUILTIN pin as an output
|
||||
pinMode(POWER, OUTPUT);
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
digitalWrite(POWER, LOW);
|
||||
|
||||
Serial.begin(115200);
|
||||
// reserve 200 bytes for the inputString:
|
||||
inputString.reserve(250);
|
||||
logItem.reserve(250);
|
||||
logItem = "";
|
||||
|
||||
btn_OK.attachClick(clickOK);
|
||||
btn_PREV.attachClick(clickPREV);
|
||||
btn_NEXT.attachClick(clickNEXT);
|
||||
btn_PWR.attachClick(clickPWR);
|
||||
|
||||
|
||||
for (i=0; i < USAGE_WIDTH; i++){
|
||||
updateUsageData(cpuUsage, 0);
|
||||
updateUsageData(memUsage, 0);
|
||||
updateUsageData(temperature, 0);
|
||||
}
|
||||
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
|
||||
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
|
||||
Serial.println(F("SSD1306 allocation failed"));
|
||||
for(;;); // Don't proceed, loop forever
|
||||
}
|
||||
|
||||
drawUI();
|
||||
updateUI();
|
||||
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 循环体
|
||||
// =======================================================
|
||||
|
||||
void loop() {
|
||||
int i;
|
||||
// print the string when a newline arrives:
|
||||
if (update) {
|
||||
updateUI();
|
||||
}
|
||||
btn_OK.tick();
|
||||
btn_PREV.tick();
|
||||
btn_NEXT.tick();
|
||||
btn_PWR.tick();
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
#################################################
|
||||
# Agent of Loongson Control Panel
|
||||
# Author: Wells Wang
|
||||
# Version: 0.1beta
|
||||
# Released under GPL v3 License.
|
||||
#################################################
|
||||
|
||||
|
||||
import serial, threading, psutil, os, datetime, time;
|
||||
from settings import *
|
||||
|
||||
ser = None
|
||||
hostname = 'hostname'
|
||||
kernal = ''
|
||||
ip = ''
|
||||
transfering = False
|
||||
|
||||
|
||||
def init():
|
||||
global ser
|
||||
try:
|
||||
ser = serial.Serial(DEVICEPORT, BAUDRATE, timeout = TIMEOUT)
|
||||
except:
|
||||
print("Init serial port {} faild!".format(DEVICEPORT))
|
||||
|
||||
def startTransfer():
|
||||
global transfering
|
||||
while transfering:
|
||||
time.sleep(0.01)
|
||||
transfering = True
|
||||
|
||||
def endTransfer():
|
||||
global transfering
|
||||
transfering = False
|
||||
|
||||
|
||||
def updateData():
|
||||
global ser, hostname, kernal, ip
|
||||
threading.Timer(5.0, updateData).start()
|
||||
|
||||
startTransfer()
|
||||
|
||||
if (os.uname().nodename != hostname):
|
||||
hostname = os.uname().nodename
|
||||
ser.write('!HN!{}\n'.format(hostname).encode('utf8'))
|
||||
if (os.uname().release != kernal):
|
||||
kernal = os.uname().release
|
||||
ser.write('!KR!{}\n'.format(kernal[:kernal.index('-')][:6]).encode('utf8'))
|
||||
|
||||
try:
|
||||
cip = os.popen("ip a show dev {}".format(NETDEV)).read()
|
||||
cip = cip[cip.index('inet ') + 5 : cip.index('inet ') + 20]
|
||||
cip = cip[:cip.index('/')]
|
||||
if (ip != cip):
|
||||
ip = cip
|
||||
ser.write('!IP!{}\n'.format(ip).encode('utf8'))
|
||||
except:
|
||||
print ("[ERROR]: Network Device {} IP address get faild!".format(NETDEV))
|
||||
cpu_percent = psutil.cpu_percent()
|
||||
mem_percent = psutil.virtual_memory().percent
|
||||
ser.write('!CG!{}\n'.format(chr(int(cpu_percent/10))).encode('utf8'))
|
||||
ser.write('!CU!{}\n'.format(chr(int(round(cpu_percent)))).encode('utf8'))
|
||||
ser.write('!MG!{}\n'.format(chr(int(mem_percent/10))).encode('utf8'))
|
||||
ser.write('!MU!{}\n'.format(chr(int(round(mem_percent)))).encode('utf8'))
|
||||
|
||||
ser.write('!TI!{}\n'.format(datetime.datetime.now().strftime("%H:%M")).encode('utf8'))
|
||||
|
||||
uptime = (time.time() - psutil.boot_time()) /3600
|
||||
ser.write('!UT!{}d{}h\n'.format(int(uptime / 24), int(uptime % 24)).encode('utf8'))
|
||||
|
||||
endTransfer()
|
||||
|
||||
print("[{}] Data updated.".format(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
|
||||
|
||||
|
||||
def sendLog(page = 0):
|
||||
global ser
|
||||
startTransfer()
|
||||
try:
|
||||
size = os.path.getsize(LOGFILE)
|
||||
if page < 0: page = 0
|
||||
if (TPP * page > size): page = int(size / TPP)
|
||||
elif (TPP * page == size): page = page - 1
|
||||
|
||||
f = open(LOGFILE, "r")
|
||||
f.seek(TPP * page)
|
||||
msg = f.read(TPP).replace("\n", " ")
|
||||
ser.write('!LP!{}\n'.format(chr(page)).encode('utf8'))
|
||||
ser.write('!LG!{}\n'.format(msg).encode('utf8'))
|
||||
print("Message sent: {}\n".format(msg))
|
||||
except:
|
||||
print("Log file operation failed!")
|
||||
endTransfer()
|
||||
|
||||
def serialInputTrigger():
|
||||
threading.Timer(0.5, serialInputTrigger).start()
|
||||
while ser.in_waiting:
|
||||
response = ser.readline()
|
||||
print("[RESPONSE]: {}\n".format(response))
|
||||
if b'#GL#' in response:
|
||||
sendLog(response[response.index(b'#GL#')+4])
|
||||
|
||||
|
||||
if __name__=='__main__':
|
||||
print("Start to initialize serial port '{}' ...".format(DEVICEPORT))
|
||||
init()
|
||||
if ser:
|
||||
print('Successfull!')
|
||||
updateData()
|
||||
serialInputTrigger()
|
||||
#while 1:
|
||||
# if ser.in_waiting:
|
||||
# print("[RESPONSE]: {}\n".format(ser.readline()))
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
DEVICEPORT = '/dev/ttyUSB0'
|
||||
BAUDRATE = 115200
|
||||
TIMEOUT = 1
|
||||
NETDEV = 'ens33'
|
||||
LOGFILE = 'msg.log'
|
||||
TPP = 84
|
||||
Reference in new issue
Block a user