分类 树莓派 下的文章

在我们的入门系列的第 13 篇文章中,发现参与树莓派社区的方法。

这个系列已经逐渐接近尾声,我已经写了很多它的乐趣,我大多希望它能帮助人们使用树莓派进行教育或娱乐。也许这些文章能说服你买你的第一个树莓派,或者让你重新发现抽屉里的吃灰设备。如果这里有真的,那么我认为这个系列就是成功的。

如果你想买一台,并宣传这块绿色的小板子有多么多功能,这里有几个方法帮你与树莓派社区建立连接:

这些只是你可以为树莓派社区做贡献的几种方式。最后但同样重要的是,你可以加入我并投稿文章到你最喜欢的开源网站 Opensource.com。 :-)


via: https://opensource.com/article/19/3/contribute-raspberry-pi-community

作者:Anderson Silva (Red Hat) 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

Wolfram 在 Raspbian 中捆绑了一个版本的 Mathematica。在我们的树莓派入门系列的第 12 篇文章中将学习如何使用它。

在 90 年代中期,我进入了大学数学专业,虽然我是以计算机科学学位毕业的,但是我就差两门课程就拿到了双学位,包括数学专业的学位。当时,我接触到了 Wolfram 的一个名为 Mathematica 的应用,我们可以将黑板上的许多代数和微分方程输入计算机。我每月花几个小时在实验室学习 Wolfram 语言,并在 Mathematica 上解决积分等问题。

对于大学生来说 Mathematica 是闭源而且昂贵的,因此在差不多 20 年后,看到 Wolfram 将一个版本的 Mathematica 与 Raspbian 和 Raspberry Pi 捆绑在一起是一个惊喜。如果你决定使用另一个基于 Debian 的发行版,你可以从这里下载。请注意,此版本仅供非商业用途免费使用。

树莓派基金会的 Mathematica 简介页面介绍了一些基本概念,如变量和循环、解决一些数学问题、创建图形、做线性代数,甚至通过应用与 GPIO 引脚交互。

要深入了解 Mathematica,请查看 Wolfram 语言文档。如果你只是想解决一些基本的微积分问题,请查看它的函数部分。如果你想绘制一些 2D 和 3D 图形,请阅读链接的教程。

或者,如果你想在做数学运算时坚持使用开源工具,请查看命令行工具 expr、factor 和 bc。(记住使用 man 命令 阅读使用帮助)如果想画图,Gnuplot 是个不错的选择。


via: https://opensource.com/article/19/3/do-math-raspberry-pi

作者:Anderson Silva 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

一些缩短树莓派学习曲线的书籍、课程和网站。

树莓派是一款小型单板计算机,最初用于教学和学习编程和计算机科学。但如今它有更多用处。它是一种经济的低功耗计算机,人们将它用于各种各样的事情 —— 从家庭娱乐到服务器应用,再到物联网(IoT) 项目。

关于这个主题有很多资源,你可以做很多不同的项目,却很难知道从哪里开始。以下是一些资源,可以帮助你开始使用树莓派。看看这篇文章,但不要满足于此。到处看下,深入下去你就会发现树莓派的新世界。

书籍

关于树莓派有很多不同语言的书籍。这两本书将帮助你开始了解,然后深入了解树莓派。

由 Simon Monk 编写的《树莓派手边书:软件和硬件问题及解决方案》

Simon Monk 是一名软件工程师,并且多年来一直是业余手工爱好者。他最初被 Arduino 这块易于使用的开发板所吸引,后来出版了一本关于它的书。后来,他开始使用树莓派并写了《树莓派手边书:软件和硬件问题和解决方案》这本书。在本书中,你可以找到大量树莓派项目的最佳时间,以及你可能面对的各种挑战的解决方案。

由 Simon Monk 编写的《树莓派编程:从 Python 入门》

Python 已经发展成为开始一个树莓派项目的首选编程语言,因为它易于学习和使用,即使你没有任何编程经验。此外,它的许多库可以帮助你专注于使你的项目变得特别,而不是实现协议以与传感器反复通信。Monk 在《树莓派手边书》中写了两章关于 Python 编程,但《树莓派编程:从 Python 入门》是一个更全面的快速入门。它向你介绍了 Python,并向你展示了可以在树莓派上使用它创建的一些项目。

在线课程

新的树莓派用户可以选择许多在线课程和教程,包括这个入门课程。

树莓派课程

Instructables 免费的在线树莓派课程提供了对树莓派的全面介绍。它从树莓派和 Linux 操作基础开始,然后进入 Python 编程和 GPIO 通信。如果你是这方面的新手,并希望快速入门,这使它成为一个很好的自上而下的树莓派指南。

网站

网络中充斥着关于树莓派的优秀信息,但这四个网站对于新用户而言应该首先知道。

RaspberryPi.org

官方的树莓派网站是最好的入门之一。有许多关于特定项目的文章会链接到这里的基础知识,如将 Raspbian 安装到树莓派上。(这是我倾向的做法,而不是在每篇文章中重复说明。)你还可以找到学生技术教育方面的示例项目和课程。

Opensource.com

在 Opensource.com 上,你可以找到许多不同的树莓派项目指导、入门指南、成功案例、更新等。看一下树莓派主题页面,了解人们在树莓派上做了什么。

Instructables 和 Hackaday

你想造自己的复古街机么?或者在镜子上显示当天的天气信息、时间和第一事务?你是否想要为派对创建一个文字时钟或者相簿?你可以在 Instructables 和 Hackaday 这样的网站上找到如何使用树莓派完成所有这些(以及更多!)的说明。如果你不确定是否要买树莓派,请浏览这些网站,你会发现有很多理由值得购买。

你最喜欢的树莓派资源是什么?请在评论中分享!


via: https://opensource.com/article/19/3/resources-raspberry-pi

作者:Manuel Dewald 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

课程输入 02 是以课程输入 01 为基础讲解的,通过一个简单的命令行实现用户的命令输入和计算机的处理和显示。本文假设你已经具备 课程11:输入01 的操作系统代码基础。

1、终端

几乎所有的操作系统都是以字符终端显示启动的。经典的黑底白字,通过键盘输入计算机要执行的命令,然后会提示你拼写错误,或者恰好得到你想要的执行结果。这种方法有两个主要优点:键盘和显示器可以提供简易、健壮的计算机交互机制,几乎所有的计算机系统都采用这个机制,这个也广泛被系统管理员应用。

早期的计算一般是在一栋楼里的一个巨型计算机系统,它有很多可以输命令的'终端'。计算机依次执行不同来源的命令。

让我们分析下真正想要哪些信息:

  1. 计算机打开后,显示欢迎信息
  2. 计算机启动后可以接受输入标志
  3. 用户从键盘输入带参数的命令
  4. 用户输入回车键或提交按钮
  5. 计算机解析命令后执行可用的命令
  6. 计算机显示命令的执行结果,过程信息
  7. 循环跳转到步骤 2

这样的终端被定义为标准的输入输出设备。用于(显示)输入的屏幕和打印输出内容的屏幕是同一个(LCTT 译注:最早期的输出打印真是“打印”到打印机/电传机的,而用于输入的终端只是键盘,除非做了回显,否则输出终端是不会显示输入的字符的)。也就是说终端是对字符显示的一个抽象。字符显示中,单个字符是最小的单元,而不是像素。屏幕被划分成固定数量不同颜色的字符。我们可以在现有的屏幕代码基础上,先存储字符和对应的颜色,然后再用方法 DrawCharacter 把其推送到屏幕上。一旦我们需要字符显示,就只需要在屏幕上画出一行字符串。

新建文件名为 terminal.s,如下:

.section .data
.align 4
terminalStart:
.int terminalBuffer
terminalStop:
.int terminalBuffer
terminalView:
.int terminalBuffer
terminalColour:
.byte 0xf
.align 8
terminalBuffer:
.rept 128*128
.byte 0x7f
.byte 0x0
.endr
terminalScreen:
.rept 1024/8 core.md Dict.md lctt2014.md lctt2016.md lctt2018.md LICENSE published README.md scripts sources translated 768/16
.byte 0x7f
.byte 0x0
.endr

这是文件终端的配置数据文件。我们有两个主要的存储变量:terminalBuffer 和 terminalScreen。terminalBuffer 保存所有显示过的字符。它保存 128 行字符文本(1 行包含 128 个字符)。每个字符有一个 ASCII 字符和颜色单元组成,初始值为 0x7f(ASCII 的删除字符)和 0(前景色和背景色为黑)。terminalScreen 保存当前屏幕显示的字符。它保存 128x48 个字符,与 terminalBuffer 初始化值一样。你可能会觉得我仅需要 terminalScreen 就够了,为什么还要terminalBuffer,其实有两个好处:

  1. 我们可以很容易看到字符串的变化,只需画出有变化的字符。
  2. 我们可以回滚终端显示的历史字符,也就是缓冲的字符(有限制)

这种独特的技巧在低功耗系统里很常见。画屏是很耗时的操作,因此我们仅在不得已的时候才去执行这个操作。在这个系统里,我们可以任意改变 terminalBuffer,然后调用一个仅拷贝屏幕上字节变化的方法。也就是说我们不需要持续画出每个字符,这样可以节省一大段跨行文本的操作时间。

你总是需要尝试去设计一个高效的系统,如果在很少变化的情况下这个系统会运行的更快。

其他在 .data 段的值得含义如下:

  • terminalStart 写入到 terminalBuffer 的第一个字符
  • terminalStop 写入到 terminalBuffer 的最后一个字符
  • terminalView 表示当前屏幕的第一个字符,这样我们可以控制滚动屏幕
  • temrinalColour 即将被描画的字符颜色

terminalStart 需要保存起来的原因是 termainlBuffer 是一个环状缓冲区。意思是当缓冲区变满时,末尾地方会回滚覆盖开始位置,这样最后一个字符变成了第一个字符。因此我们需要将 terminalStart 往前推进,这样我们知道我们已经占满它了。如何实现缓冲区检测:如果索引越界到缓冲区的末尾,就将索引指向缓冲区的开始位置。环状缓冲区是一个比较常见的存储大量数据的高明方法,往往这些数据的最近部分比较重要。它允许无限制的写入,只保证最近一些特定数据有效。这个常常用于信号处理和数据压缩算法。这样的情况,可以允许我们存储 128 行终端记录,超过128行也不会有问题。如果不是这样,当超过第 128 行时,我们需要把 127 行分别向前拷贝一次,这样很浪费时间。

显示 Hellow world 插入到大小为5的循环缓冲区的示意图。

环状缓冲区是数据结构一个例子。这是一个组织数据的思路,有时我们通过软件实现这种思路。

之前已经提到过 terminalColour 几次了。你可以根据你的想法实现终端颜色,但这个文本终端有 16 个前景色和 16 个背景色(这里相当于有 16 2 = 256 种组合)。CGA终端的颜色定义如下:

表格 1.1 - CGA 颜色编码

序号颜色 (R, G, B)
0黑 (0, 0, 0)
1蓝 (0, 0, ⅔)
2绿 (0, ⅔, 0)
3青色 (0, ⅔, ⅔)
4红色 (⅔, 0, 0)
5品红 (⅔, 0, ⅔)
6棕色 (⅔, ⅓, 0)
7浅灰色 (⅔, ⅔, ⅔)
8灰色 (⅓, ⅓, ⅓)
9淡蓝色 (⅓, ⅓, 1)
10淡绿色 (⅓, 1, ⅓)
11淡青色 (⅓, 1, 1)
12淡红色 (1, ⅓, ⅓)
13浅品红 (1, ⅓, 1)
14黄色 (1, 1, ⅓)
15白色 (1, 1, 1)

我们将前景色保存到颜色的低字节,背景色保存到颜色高字节。除了棕色,其他这些颜色遵循一种模式如二进制的高位比特代表增加 ⅓ 到每个组件,其他比特代表增加 ⅔ 到各自组件。这样很容易进行 RGB 颜色转换。

棕色作为替代色(黑黄色)既不吸引人也没有什么用处。

我们需要一个方法从 TerminalColour 读取颜色编码的四个比特,然后用 16 比特等效参数调用 SetForeColour。尝试你自己实现。如果你感觉麻烦或者还没有完成屏幕系列课程,我们的实现如下:

.section .text
TerminalColour:
teq r0,#6
ldreq r0,=0x02B5
beq SetForeColour

tst r0,#0b1000
ldrne r1,=0x52AA
moveq r1,#0
tst r0,#0b0100
addne r1,#0x15
tst r0,#0b0010
addne r1,#0x540
tst r0,#0b0001
addne r1,#0xA800
mov r0,r1
b SetForeColour

2、文本显示

我们的终端第一个真正需要的方法是 TerminalDisplay,它用来把当前的数据从 terminalBuffer拷贝到 terminalScreen 和实际的屏幕。如上所述,这个方法必须是最小开销的操作,因为我们需要频繁调用它。它主要比较 terminalBuffer 与 terminalDisplay 的文本,然后只拷贝有差异的字节。请记住 terminalBuffer 是以环状缓冲区运行的,这种情况,就是从 terminalView 到 terminalStop,或者 128*48 个字符,要看哪个来的最快。如果我们遇到 terminalStop,我们将会假定在这之后的所有字符是 7f 16 (ASCII 删除字符),颜色为 0(黑色前景色和背景色)。

让我们看看必须要做的事情:

  1. 加载 terminalView、terminalStop 和 terminalDisplay 的地址。
  2. 对于每一行:

    1. 对于每一列:

      1. 如果 terminalView 不等于 terminalStop,根据 terminalView 加载当前字符和颜色
      2. 否则加载 0x7f 和颜色 0
      3. 从 terminalDisplay 加载当前的字符
      4. 如果字符和颜色相同,直接跳转到第 10 步
      5. 存储字符和颜色到 terminalDisplay
      6. 用 r0 作为背景色参数调用 TerminalColour
      7. 用 r0 = 0x7f(ASCII 删除字符,一个块)、 r1 = x、r2 = y 调用 DrawCharacter
      8. 用 r0 作为前景色参数调用 TerminalColour
      9. 用 r0 = 字符、r1 = x、r2 = y 调用 DrawCharacter
      10. 对位置参数 terminalDisplay 累加 2
      11. 如果 terminalView 不等于 terminalStop,terminalView 位置参数累加 2
      12. 如果 terminalView 位置已经是文件缓冲器的末尾,将它设置为缓冲区的开始位置
      13. x 坐标增加 8
    2. y 坐标增加 16

尝试去自己实现吧。如果你遇到问题,我们的方案下面给出来了:

1、我这里的变量有点乱。为了方便起见,我用 taddr 存储 textBuffer 的末尾位置。

.globl TerminalDisplay
TerminalDisplay:
push {r4,r5,r6,r7,r8,r9,r10,r11,lr}
x .req r4
y .req r5
char .req r6
col .req r7
screen .req r8
taddr .req r9
view .req r10
stop .req r11

ldr taddr,=terminalStart
ldr view,[taddr,#terminalView - terminalStart]
ldr stop,[taddr,#terminalStop - terminalStart]
add taddr,#terminalBuffer - terminalStart
add taddr,#128*128*2
mov screen,taddr

2、从 yLoop 开始运行。

mov y,#0
yLoop$:

2.1、

mov x,#0
xLoop$:

从 xLoop 开始运行。

2.1.1、为了方便起见,我把字符和颜色同时加载到 char 变量了

teq view,stop
ldrneh char,[view]

2.1.2、这行是对上面一行的补充说明:读取黑色的删除字符

moveq char,#0x7f

2.1.3、为了简便我把字符和颜色同时加载到 col 里。

ldrh col,[screen]

2.1.4、 现在我用 teq 指令检查是否有数据变化

teq col,char
beq xLoopContinue$

2.1.5、我可以容易的保存当前值

strh char,[screen]

2.1.6、我用比特偏移指令 lsr 和 and 指令从切分 char 变量,将颜色放到 col 变量,字符放到 char 变量,然后再用比特偏移指令 lsr 获取背景色后调用 TerminalColour 。

lsr col,char,#8
and char,#0x7f
lsr r0,col,#4
bl TerminalColour

2.1.7、写入一个彩色的删除字符

mov r0,#0x7f
mov r1,x
mov r2,y
bl DrawCharacter

2.1.8、用 and 指令获取 col 变量的低半字节,然后调用 TerminalColour

and r0,col,#0xf
bl TerminalColour

2.1.9、写入我们需要的字符

mov r0,char
mov r1,x
mov r2,y
bl DrawCharacter

2.1.10、自增屏幕指针

xLoopContinue$:
add screen,#2

2.1.11、如果可能自增 view 指针

teq view,stop
addne view,#2

2.1.12、很容易检测 view 指针是否越界到缓冲区的末尾,因为缓冲区的地址保存在 taddr 变量里

teq view,taddr
subeq view,#128*128*2

2.1.13、 如果还有字符需要显示,我们就需要自增 x 变量然后到 xLoop 循环执行

add x,#8
teq x,#1024
bne xLoop$

2.2、 如果还有更多的字符显示我们就需要自增 y 变量,然后到 yLoop 循环执行

add y,#16
teq y,#768
bne yLoop$

3、不要忘记最后清除变量

pop {r4,r5,r6,r7,r8,r9,r10,r11,pc}
.unreq x
.unreq y
.unreq char
.unreq col
.unreq screen
.unreq taddr
.unreq view
.unreq stop

3、行打印

现在我有了自己 TerminalDisplay 方法,它可以自动显示 terminalBuffer 内容到 terminalScreen,因此理论上我们可以画出文本。但是实际上我们没有任何基于字符显示的例程。 首先快速容易上手的方法便是 TerminalClear, 它可以彻底清除终端。这个方法不用循环也很容易实现。可以尝试分析下面的方法应该不难:

.globl TerminalClear
TerminalClear:
ldr r0,=terminalStart
add r1,r0,#terminalBuffer-terminalStart
str r1,[r0]
str r1,[r0,#terminalStop-terminalStart]
str r1,[r0,#terminalView-terminalStart]
mov pc,lr

现在我们需要构造一个字符显示的基础方法:Print 函数。它将保存在 r0 的字符串和保存在 r1 的字符串长度简单的写到屏幕上。有一些特定字符需要特别的注意,这些特定的操作是确保 terminalView 是最新的。我们来分析一下需要做什么:

  1. 检查字符串的长度是否为 0,如果是就直接返回
  2. 加载 terminalStop 和 terminalView
  3. 计算出 terminalStop 的 x 坐标
  4. 对每一个字符的操作:

    1. 检查字符是否为新起一行
    2. 如果是的话,自增 bufferStop 到行末,同时写入黑色删除字符
    3. 否则拷贝当前 terminalColour 的字符
    4. 检查是否在行末
    5. 如果是,检查从 terminalView 到 terminalStop 之间的字符数是否大于一屏
    6. 如果是,terminalView 自增一行
    7. 检查 terminalView 是否为缓冲区的末尾,如果是的话将其替换为缓冲区的起始位置
    8. 检查 terminalStop 是否为缓冲区的末尾,如果是的话将其替换为缓冲区的起始位置
    9. 检查 terminalStop 是否等于 terminalStart, 如果是的话 terminalStart 自增一行。
    10. 检查 terminalStart 是否为缓冲区的末尾,如果是的话将其替换为缓冲区的起始位置
  5. 存取 terminalStop 和 terminalView

试一下自己去实现。我们的方案提供如下:

1、这个是 Print 函数开始快速检查字符串为0的代码

.globl Print
Print:
teq r1,#0
moveq pc,lr

2、这里我做了很多配置。 bufferStart 代表 terminalStart, bufferStop 代表terminalStop, view 代表 terminalView,taddr 代表 terminalBuffer 的末尾地址。

push {r4,r5,r6,r7,r8,r9,r10,r11,lr}
bufferStart .req r4
taddr .req r5
x .req r6
string .req r7
length .req r8
char .req r9
bufferStop .req r10
view .req r11

mov string,r0
mov length,r1

ldr taddr,=terminalStart
ldr bufferStop,[taddr,#terminalStop-terminalStart]
ldr view,[taddr,#terminalView-terminalStart]
ldr bufferStart,[taddr]
add taddr,#terminalBuffer-terminalStart
add taddr,#128*128*2

3、和通常一样,巧妙的对齐技巧让许多事情更容易。由于需要对齐 terminalBuffer,每个字符的 x 坐标需要 8 位要除以 2。

and x,bufferStop,#0xfe
lsr x,#1

4.1、我们需要检查新行

charLoop$:
ldrb char,[string]
and char,#0x7f
teq char,#'\n'
bne charNormal$

4.2、循环执行值到行末写入 0x7f;黑色删除字符

mov r0,#0x7f
clearLine$:
strh r0,[bufferStop]
add bufferStop,#2
add x,#1
teq x,#128 blt clearLine$
    
b charLoopContinue$

4.3、存储字符串的当前字符和 terminalBuffer 末尾的 terminalColour 然后将它和 x 变量自增

charNormal$:
strb char,[bufferStop]
ldr r0,=terminalColour
ldrb r0,[r0]
strb r0,[bufferStop,#1]
add bufferStop,#2
add x,#1

4.4、检查 x 是否为行末;128

charLoopContinue$:
cmp x,#128
blt noScroll$

4.5、设置 x 为 0 然后检查我们是否已经显示超过 1 屏。请记住,我们是用的循环缓冲区,因此如果 bufferStop 和 view 之前的差是负值,我们实际上是环绕了缓冲区。

mov x,#0
subs r0,bufferStop,view
addlt r0,#128*128*2
cmp r0,#128*(768/16)*2

4.6、增加一行字节到 view 的地址

addge view,#128*2

4.7、 如果 view 地址是缓冲区的末尾,我们就从它上面减去缓冲区的长度,让其指向开始位置。我会在开始的时候设置 taddr 为缓冲区的末尾地址。

teq view,taddr
subeq view,taddr,#128*128*2

4.8、如果 stop 的地址在缓冲区末尾,我们就从它上面减去缓冲区的长度,让其指向开始位置。我会在开始的时候设置 taddr 为缓冲区的末尾地址。

noScroll$:
teq bufferStop,taddr
subeq bufferStop,taddr,#128*128*2

4.9、检查 bufferStop 是否等于 bufferStart。 如果等于增加一行到 bufferStart。

teq bufferStop,bufferStart
addeq bufferStart,#128*2

4.10、如果 start 的地址在缓冲区的末尾,我们就从它上面减去缓冲区的长度,让其指向开始位置。我会在开始的时候设置 taddr 为缓冲区的末尾地址。

teq bufferStart,taddr
subeq bufferStart,taddr,#128*128*2

循环执行知道字符串结束

subs length,#1
add string,#1
bgt charLoop$

5、保存变量然后返回

charLoopBreak$:
sub taddr,#128*128*2
sub taddr,#terminalBuffer-terminalStart
str bufferStop,[taddr,#terminalStop-terminalStart]
str view,[taddr,#terminalView-terminalStart]
str bufferStart,[taddr]

pop {r4,r5,r6,r7,r8,r9,r10,r11,pc}
.unreq bufferStart
.unreq taddr
.unreq x
.unreq string
.unreq length
.unreq char
.unreq bufferStop
.unreq view

这个方法允许我们打印任意字符到屏幕。然而我们用了颜色变量,但实际上没有设置它。一般终端用特性的组合字符去行修改颜色。如 ASCII 转义(1b 16)后面跟着一个 0 - f 的 16 进制的数,就可以设置前景色为 CGA 颜色号。如果你自己想尝试实现;在下载页面有一个我的详细的例子。

4、标志输入

现在我们有一个可以打印和显示文本的输出终端。这仅仅是说对了一半,我们需要输入。我们想实现一个方法:ReadLine,可以保存文件的一行文本,文本位置由 r0 给出,最大的长度由 r1 给出,返回 r0 里面的字符串长度。棘手的是用户输出字符的时候要回显功能,同时想要退格键的删除功能和命令回车执行功能。它们还需要一个闪烁的下划线代表计算机需要输入。这些完全合理的要求让构造这个方法更具有挑战性。有一个方法完成这些需求就是存储用户输入的文本和文件大小到内存的某个地方。然后当调用 ReadLine 的时候,移动 terminalStop 的地址到它开始的地方然后调用 Print。也就是说我们只需要确保在内存维护一个字符串,然后构造一个我们自己的打印函数。

按照惯例,许多编程语言中,任意程序可以访问 stdin 和 stdin,它们可以连接到终端的输入和输出流。在图形程序其实也可以进行同样操作,但实际几乎不用。

让我们看看 ReadLine 做了哪些事情:

  1. 如果字符串可保存的最大长度为 0,直接返回
  2. 检索 terminalStop 和 terminalStop 的当前值
  3. 如果字符串的最大长度大约缓冲区的一半,就设置大小为缓冲区的一半
  4. 从最大长度里面减去 1 来确保输入的闪烁字符或结束符
  5. 向字符串写入一个下划线
  6. 写入一个 terminalView 和 terminalStop 的地址到内存
  7. 调用 Print 打印当前字符串
  8. 调用 TerminalDisplay
  9. 调用 KeyboardUpdate
  10. 调用 KeyboardGetChar
  11. 如果是一个新行直接跳转到第 16 步
  12. 如果是一个退格键,将字符串长度减 1(如果其大于 0)
  13. 如果是一个普通字符,将它写入字符串(字符串大小确保小于最大值)
  14. 如果字符串是以下划线结束,写入一个空格,否则写入下划线
  15. 跳转到第 6 步
  16. 字符串的末尾写入一个新行字符
  17. 调用 Print 和 TerminalDisplay
  18. 用结束符替换新行
  19. 返回字符串的长度

为了方便读者理解,然后然后自己去实现,我们的实现提供如下:

  1. 快速处理长度为 0 的情况
.globl ReadLine
ReadLine:
teq r1,#0
moveq r0,#0
moveq pc,lr

2、考虑到常见的场景,我们初期做了很多初始化动作。input 代表 terminalStop 的值,view 代表 terminalView。Length 默认为 0。

string .req r4
maxLength .req r5
input .req r6
taddr .req r7
length .req r8
view .req r9

push {r4,r5,r6,r7,r8,r9,lr}

mov string,r0
mov maxLength,r1
ldr taddr,=terminalStart
ldr input,[taddr,#terminalStop-terminalStart]
ldr view,[taddr,#terminalView-terminalStart]
mov length,#0

3、我们必须检查异常大的读操作,我们不能处理超过 terminalBuffer 大小的输入(理论上可行,但是 terminalStart 移动越过存储的 terminalStop`,会有很多问题)。

cmp maxLength,#128*64
movhi maxLength,#128*64

4、由于用户需要一个闪烁的光标,我们需要一个备用字符在理想状况在这个字符串后面放一个结束符。

sub maxLength,#1

5、写入一个下划线让用户知道我们可以输入了。

mov r0,#'_'
strb r0,[string,length]

6、保存 terminalStop 和 terminalView。这个对重置一个终端很重要,它会修改这些变量。严格讲也可以修改 terminalStart,但是不可逆。

readLoop$:
str input,[taddr,#terminalStop-terminalStart]
str view,[taddr,#terminalView-terminalStart]

7、写入当前的输入。由于下划线因此字符串长度加 1

mov r0,string
mov r1,length
add r1,#1
bl Print

8、拷贝下一个文本到屏幕

bl TerminalDisplay

9、获取最近一次键盘输入

bl KeyboardUpdate

10、检索键盘输入键值

bl KeyboardGetChar

11、如果我们有一个回车键,循环中断。如果有结束符和一个退格键也会同样跳出循环。

teq r0,#'\n'
beq readLoopBreak$
teq r0,#0
beq cursor$
teq r0,#'\b'
bne standard$

12、从 length 里面删除一个字符

delete$:
cmp length,#0
subgt length,#1
b cursor$

13、写回一个普通字符

standard$:
cmp length,maxLength
bge cursor$
strb r0,[string,length]
add length,#1

14、加载最近的一个字符,如果不是下划线则修改为下换线,如果是则修改为空格

cursor$:
ldrb r0,[string,length]
teq r0,#'_'
moveq r0,#' '
movne r0,#'_'
strb r0,[string,length]

15、循环执行值到用户输入按下

b readLoop$
readLoopBreak$:

16、在字符串的结尾处存入一个新行字符

mov r0,#'\n'
strb r0,[string,length]

17、重置 terminalView 和 terminalStop 然后调用 Print 和 TerminalDisplay 显示最终的输入

str input,[taddr,#terminalStop-terminalStart]
str view,[taddr,#terminalView-terminalStart]
mov r0,string
mov r1,length
add r1,#1
bl Print
bl TerminalDisplay

18、写入一个结束符

mov r0,#0
strb r0,[string,length]

19、返回长度

mov r0,length
pop {r4,r5,r6,r7,r8,r9,pc}
.unreq string
.unreq maxLength
.unreq input
.unreq taddr
.unreq length
.unreq view

5、终端:机器进化

现在我们理论用终端和用户可以交互了。最显而易见的事情就是拿去测试了!删除 main.s 里 bl UsbInitialise 后面的代码后如下:

reset$:
  mov sp,#0x8000
  bl TerminalClear
  
  ldr r0,=welcome
  mov r1,#welcomeEnd-welcome
  bl Print

loop$:
  ldr r0,=prompt
  mov r1,#promptEnd-prompt
  bl Print
  
  ldr r0,=command
  mov r1,#commandEnd-command
  bl ReadLine
  
  teq r0,#0
  beq loopContinue$
  
  mov r4,r0
  
  ldr r5,=command
  ldr r6,=commandTable
  
  ldr r7,[r6,#0]
  ldr r9,[r6,#4]
  commandLoop$:
    ldr r8,[r6,#8]
    sub r1,r8,r7
    
    cmp r1,r4
    bgt commandLoopContinue$
    
    mov r0,#0
    commandName$:
      ldrb r2,[r5,r0]
      ldrb r3,[r7,r0]
      teq r2,r3
      bne commandLoopContinue$
      add r0,#1
      teq r0,r1
      bne commandName$
    
    ldrb r2,[r5,r0]
    teq r2,#0
    teqne r2,#' '
    bne commandLoopContinue$
    
    mov r0,r5
    mov r1,r4
    mov lr,pc
    mov pc,r9
    b loopContinue$
  
  commandLoopContinue$:
    add r6,#8
    mov r7,r8
    ldr r9,[r6,#4]
    teq r9,#0
    bne commandLoop$
  
  ldr r0,=commandUnknown
  mov r1,#commandUnknownEnd-commandUnknown
  ldr r2,=formatBuffer
  ldr r3,=command
  bl FormatString
  
  mov r1,r0
  ldr r0,=formatBuffer
  bl Print

loopContinue$:
  bl TerminalDisplay
  b loop$

echo:
  cmp r1,#5
  movle pc,lr

  add r0,#5
  sub r1,#5
  b Print

ok:
  teq r1,#5
  beq okOn$
  teq r1,#6
  beq okOff$
  mov pc,lr
  
  okOn$:
    ldrb r2,[r0,#3]
    teq r2,#'o'
    ldreqb r2,[r0,#4]
    teqeq r2,#'n'
    movne pc,lr
    mov r1,#0
    b okAct$
  
  okOff$:
    ldrb r2,[r0,#3]
    teq r2,#'o'
    ldreqb r2,[r0,#4]
    teqeq r2,#'f'
    ldreqb r2,[r0,#5]
    teqeq r2,#'f'
    movne pc,lr
    mov r1,#1
  
  okAct$:
  
    mov r0,#16
    b SetGpio

.section .data
.align 2
welcome: .ascii "Welcome to Alex's OS - Everyone's favourite OS"
welcomeEnd:
.align 2
prompt: .ascii "\n> "
promptEnd:
.align 2
command:
  .rept 128
    .byte 0
  .endr
commandEnd:
.byte 0
.align 2
commandUnknown: .ascii "Command `%s' was not recognised.\n"
commandUnknownEnd:
.align 2
formatBuffer:
  .rept 256
    .byte 0
  .endr
formatEnd:

.align 2
commandStringEcho: .ascii "echo"
commandStringReset: .ascii "reset"
commandStringOk: .ascii "ok"
commandStringCls: .ascii "cls"
commandStringEnd:

.align 2
commandTable:
.int commandStringEcho, echo
.int commandStringReset, reset$
.int commandStringOk, ok
.int commandStringCls, TerminalClear
.int commandStringEnd, 0

这块代码集成了一个简易的命令行操作系统。支持命令:echo、reset、ok 和 cls。echo 拷贝任意文本到终端,reset 命令会在系统出现问题的是复位操作系统,ok 有两个功能:设置 OK 灯亮灭,最后 cls 调用 TerminalClear 清空终端。

试试树莓派的代码吧。如果遇到问题,请参照问题集锦页面吧。

如果运行正常,祝贺你完成了一个操作系统基本终端和输入系列的课程。很遗憾这个教程先讲到这里,但是我希望将来能制作更多教程。有问题请反馈至 [email protected]。

你已经在建立了一个简易的终端操作系统。我们的代码在 commandTable 构造了一个可用的命令表格。每个表格的入口是一个整型数字,用来表示字符串的地址,和一个整型数字表格代码的执行入口。 最后一个入口是 为 0 的 commandStringEnd。尝试实现你自己的命令,可以参照已有的函数,建立一个新的。函数的参数 r0 是用户输入的命令地址,r1 是其长度。你可以用这个传递你输入值到你的命令。也许你有一个计算器程序,或许是一个绘图程序或国际象棋。不管你的什么点子,让它跑起来!


via: https://www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/input02.html

作者:Alex Chadwick 选题:lujun9972 译者:guevaraya 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

树莓派是学习计算机安全的一个好方法。在我们这个系列的第十一篇文章中会进行学习。

在技术方面是否有比保护你的计算机更热门的话题?一些专家会告诉你,没有绝对安全的系统。他们开玩笑说,如果你想要你的服务器或者应用程序真正的安全,就关掉你的服务器,从网络上断线,然后把它放在一个安全的地方。但问题是显而易见的:没人能用的应用程序或者服务器有什么用?

这是围绕安全的一个难题,我们如何才能在保证安全性的同时,让服务器或应用程序依然可用且有价值?我无论如何都不是一个安全专家,虽然我希望有一天我能是。因此,分享可以用树莓派来做些什么以学习计算机安全的知识,我认为是有意义的。

我要提示一下,就像本系列中其他写给树莓派初学者的文章一样,我的目标不是深入研究,而是起个头,让你有兴趣去了解更多与这些主题相关的东西。

Kali Linux

当我们谈到“做一些安全方面的事”的时候,出现在脑海中的一个 Linux 发行版就是 Kali Linux。Kali Linux 的开发主要集中在调查取证和渗透测试方面。它有超过 600 个已经预先安装好了的用来测试你的计算机的安全性的渗透测试工具,还有一个取证模式,它可以避免自身接触到被检查系统的内部的硬盘驱动器或交换空间。

就像 Raspbian 一样,Kali Linux 基于 Debian 的发行版,你可以在 Kali 的主要文档门户的网页上找到将它安装在树莓派上的文档。如果你已经在你的树莓派上安装了 Raspbian 或者是其它的 Linux 发行版。那么你装 Kali 应该是没问题的,Kali 的创造者甚至将培训、研讨会和职业认证整合到了一起,以此来帮助提升你在安全领域内的职业生涯。

其他的 Linux 发行版

大多数的标准 Linux 发行版,比如 Raspbian、Ubuntu 和 Fedora 这些,在它们的仓库里同样也有很多可用的安全工具。一些很棒的探测工具你可以试试,包括 Nmap、Wireshark、auditctl,和 SELinux。

项目

你可以在树莓派上运行很多其他的安全相关的项目,例如蜜罐,广告拦截器和 USB 清洁器。花些时间了解它们!


via: https://opensource.com/article/19/3/computer-security-raspberry-pi

作者:Anderson Silva 选题:lujun9972 译者:hopefully2333 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

在树莓派使用入门的第十篇文章中,我们将学习如何使用 GPIO。

到目前为止,本系列文章主要专注于树莓派的软件方面,而今天我们将学习硬件。在树莓派最初发布时,最让我感兴趣的主要特性之一就是它的 通用输入输出(GPIO)针脚。GPIO 可以让你的树莓派程序与连接到它上面的传感器、继电器、和其它类型的电子元件与物理世界来交互。

树莓派上的每个 GPIO 针脚要么有一个预定义的功能,要么被设计为通用的。另外,不同的树莓派型号要么 26 个,要么有 40 个 GPIO 针脚,你可以根据情况使用的。在维基百科上有一个 关于每个针脚的非常详细的说明_connector) 以及它的功能介绍。

你可以使用树莓派的 GPIO 针脚做更多的事情。关于它的 GPIO 的使用我写过一些文章,包括使用树莓派来控制节日彩灯的三篇文章(第一篇、 第二篇、和 第三篇),在这些文章中我通过使用开源程序让灯光随着音乐起舞。

树莓派社区在用不同编程语言创建不同的库方面做了非常好的一些工作,因此,你能够使用 C、Python、 Scratch 和其它语言与 GPIO 进行交互。

另外,如果你想在树莓派与物理世界交互方面获得更好的体验,你可以选用 Raspberry Pi Sense Hat,它是插入树莓派 GPIO 针脚上的一个很便宜的电路板,借助它你可以通过程序与 LED、驾驶杆、气压计、温度计、温度计、 陀螺仪、加速度计以及磁力仪来交互。


via: https://opensource.com/article/19/3/gpio-pins-raspberry-pi

作者:Anderson Silva 选题:lujun9972 译者:qhwdw 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出